Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c
index 6e805d4..7f37857 100644
--- a/arch/arm/mach-omap/usb.c
+++ b/arch/arm/mach-omap/usb.c
@@ -288,8 +288,8 @@
 static struct resource udc_resources[] = {
 	/* order is significant! */
 	{		/* registers */
-		.start		= IO_ADDRESS(UDC_BASE),
-		.end		= IO_ADDRESS(UDC_BASE + 0xff),
+		.start		= UDC_BASE,
+		.end		= UDC_BASE + 0xff,
 		.flags		= IORESOURCE_MEM,
 	}, {		/* general IRQ */
 		.start		= IH2_BASE + 20,
@@ -355,8 +355,8 @@
 static struct resource otg_resources[] = {
 	/* order is significant! */
 	{
-		.start		= IO_ADDRESS(OTG_BASE),
-		.end		= IO_ADDRESS(OTG_BASE + 0xff),
+		.start		= OTG_BASE,
+		.end		= OTG_BASE + 0xff,
 		.flags		= IORESOURCE_MEM,
 	}, {
 		.start		= IH2_BASE + 8,
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index a708a1d..d79cd21 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_USB_MON)		+= mon/
 
 obj-$(CONFIG_USB_EHCI_HCD)	+= host/
+obj-$(CONFIG_USB_ISP116X_HCD)	+= host/
 obj-$(CONFIG_USB_OHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 0d9f537..f429862 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -1,30 +1,60 @@
 #
-# USB ATM driver configuration
+# USB/ATM DSL configuration
 #
-comment "USB ATM/DSL drivers"
+
+menu "USB DSL modem support"
 	depends on USB
 
 config USB_ATM
-	tristate "Generic USB ATM/DSL core I/O support"
+	tristate "USB DSL modem support"
 	depends on USB && ATM
 	select CRC32
 	default n
 	help
-	  This provides a library which is used for packet I/O by USB DSL
-	  modems, such as the SpeedTouch driver below. 
+	  Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
+	  modem to your computer's USB port.  You will then need to choose your
+	  modem from the list below.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called usb_atm.
+	  module will be called usbatm.
 
 config USB_SPEEDTOUCH
-	tristate "Alcatel Speedtouch USB support"
-	depends on USB && ATM
-	select USB_ATM
+	tristate "Speedtouch USB support"
+	depends on USB_ATM
+	select FW_LOADER
 	help
-	  Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
+	  Say Y here if you have an SpeedTouch USB or SpeedTouch 330
 	  modem.  In order to use your modem you will need to install the 
 	  two parts of the firmware, extracted by the user space tools; see
 	  <http://www.linux-usb.org/SpeedTouch/> for details.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called speedtch.
+
+config USB_CXACRU
+	tristate "Conexant AccessRunner USB support"
+	depends on USB_ATM
+	select FW_LOADER
+	help
+	  Say Y here if you have an ADSL USB modem based on the Conexant
+	  AccessRunner chipset.  In order to use your modem you will need to
+	  install the firmware, extracted by the user space tools; see
+	  <http://accessrunner.sourceforge.net/> for details.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cxacru.
+
+config USB_XUSBATM
+	tristate "Other USB DSL modem support"
+	depends on USB_ATM
+	help
+	  Say Y here if you have a DSL USB modem not explicitly supported by
+	  another USB DSL drivers.  In order to use your modem you will need to
+	  pass the vendor ID, product ID, and endpoint numbers for transmission
+	  and reception as module parameters.  You may need to initialize the
+	  the modem using a user space utility (a firmware loader for example).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called xusbatm.
+
+endmenu
diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile
index 9213b8b9..751f297 100644
--- a/drivers/usb/atm/Makefile
+++ b/drivers/usb/atm/Makefile
@@ -1,7 +1,8 @@
 #
-# Makefile for the rest of the USB drivers
-# (the ones that don't fit into any other categories)
+# Makefile for USB ATM/xDSL drivers
 #
 
-obj-$(CONFIG_USB_ATM)		+= usb_atm.o
+obj-$(CONFIG_USB_CXACRU)	+= cxacru.o
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= speedtch.o
+obj-$(CONFIG_USB_ATM)		+= usbatm.o
+obj-$(CONFIG_USB_XUSBATM)	+= xusbatm.o
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
new file mode 100644
index 0000000..cbd4a7d
--- /dev/null
+++ b/drivers/usb/atm/cxacru.c
@@ -0,0 +1,878 @@
+/******************************************************************************
+ *  cxacru.c  -  driver for USB ADSL modems based on
+ *               Conexant AccessRunner chipset
+ *
+ *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
+ *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*
+ *  Credit is due for Josep Comas, who created the original patch to speedtch.c
+ *  to support the different padding used by the AccessRunner (now generalized
+ *  into usbatm), and the userspace firmware loading utility.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>	/* FIXME: linux/firmware.h should include it itself */
+#include <linux/firmware.h>
+
+#include "usbatm.h"
+
+#define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands"
+#define DRIVER_VERSION	"0.2"
+#define DRIVER_DESC	"Conexant AccessRunner ADSL USB modem driver"
+
+static const char cxacru_driver_name[] = "cxacru";
+
+#define CXACRU_EP_CMD		0x01	/* Bulk/interrupt in/out */
+#define CXACRU_EP_DATA		0x02	/* Bulk in/out */
+
+#define CMD_PACKET_SIZE		64	/* Should be maxpacket(ep)? */
+
+/* Addresses */
+#define PLLFCLK_ADDR	0x00350068
+#define PLLBCLK_ADDR	0x0035006c
+#define SDRAMEN_ADDR	0x00350010
+#define FW_ADDR		0x00801000
+#define BR_ADDR		0x00180600
+#define SIG_ADDR	0x00180500
+#define BR_STACK_ADDR	0x00187f10
+
+/* Values */
+#define SDRAM_ENA	0x1
+
+#define CMD_TIMEOUT	2000	/* msecs */
+#define POLL_INTERVAL	5000	/* msecs */
+
+/* commands for interaction with the modem through the control channel before
+ * firmware is loaded  */
+enum cxacru_fw_request {
+	FW_CMD_ERR,
+	FW_GET_VER,
+	FW_READ_MEM,
+	FW_WRITE_MEM,
+	FW_RMW_MEM,
+	FW_CHECKSUM_MEM,
+	FW_GOTO_MEM,
+};
+
+/* commands for interaction with the modem through the control channel once
+ * firmware is loaded  */
+enum cxacru_cm_request {
+	CM_REQUEST_UNDEFINED = 0x80,
+	CM_REQUEST_TEST,
+	CM_REQUEST_CHIP_GET_MAC_ADDRESS,
+	CM_REQUEST_CHIP_GET_DP_VERSIONS,
+	CM_REQUEST_CHIP_ADSL_LINE_START,
+	CM_REQUEST_CHIP_ADSL_LINE_STOP,
+	CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS,
+	CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED,
+	CM_REQUEST_CARD_INFO_GET,
+	CM_REQUEST_CARD_DATA_GET,
+	CM_REQUEST_CARD_DATA_SET,
+	CM_REQUEST_COMMAND_HW_IO,
+	CM_REQUEST_INTERFACE_HW_IO,
+	CM_REQUEST_CARD_SERIAL_DATA_PATH_GET,
+	CM_REQUEST_CARD_SERIAL_DATA_PATH_SET,
+	CM_REQUEST_CARD_CONTROLLER_VERSION_GET,
+	CM_REQUEST_CARD_GET_STATUS,
+	CM_REQUEST_CARD_GET_MAC_ADDRESS,
+	CM_REQUEST_CARD_GET_DATA_LINK_STATUS,
+	CM_REQUEST_MAX,
+};
+
+/* reply codes to the commands above */
+enum cxacru_cm_status {
+	CM_STATUS_UNDEFINED,
+	CM_STATUS_SUCCESS,
+	CM_STATUS_ERROR,
+	CM_STATUS_UNSUPPORTED,
+	CM_STATUS_UNIMPLEMENTED,
+	CM_STATUS_PARAMETER_ERROR,
+	CM_STATUS_DBG_LOOPBACK,
+	CM_STATUS_MAX,
+};
+
+/* indices into CARD_INFO_GET return array */
+enum cxacru_info_idx {
+	CXINF_DOWNSTREAM_RATE,
+	CXINF_UPSTREAM_RATE,
+	CXINF_LINK_STATUS,
+	CXINF_LINE_STATUS,
+	CXINF_MAC_ADDRESS_HIGH,
+	CXINF_MAC_ADDRESS_LOW,
+	CXINF_UPSTREAM_SNR_MARGIN,
+	CXINF_DOWNSTREAM_SNR_MARGIN,
+	CXINF_UPSTREAM_ATTENUATION,
+	CXINF_DOWNSTREAM_ATTENUATION,
+	CXINF_TRANSMITTER_POWER,
+	CXINF_UPSTREAM_BITS_PER_FRAME,
+	CXINF_DOWNSTREAM_BITS_PER_FRAME,
+	CXINF_STARTUP_ATTEMPTS,
+	CXINF_UPSTREAM_CRC_ERRORS,
+	CXINF_DOWNSTREAM_CRC_ERRORS,
+	CXINF_UPSTREAM_FEC_ERRORS,
+	CXINF_DOWNSTREAM_FEC_ERRORS,
+	CXINF_UPSTREAM_HEC_ERRORS,
+	CXINF_DOWNSTREAM_HEC_ERRORS,
+	CXINF_LINE_STARTABLE,
+	CXINF_MODULATION,
+	CXINF_ADSL_HEADEND,
+	CXINF_ADSL_HEADEND_ENVIRONMENT,
+	CXINF_CONTROLLER_VERSION,
+	/* dunno what the missing two mean */
+	CXINF_MAX = 0x1c,
+};
+
+struct cxacru_modem_type {
+	u32 pll_f_clk;
+	u32 pll_b_clk;
+	int boot_rom_patch;
+};
+
+struct cxacru_data {
+	struct usbatm_data *usbatm;
+
+	const struct cxacru_modem_type *modem_type;
+
+	int line_status;
+	struct work_struct poll_work;
+
+	/* contol handles */
+	struct semaphore cm_serialize;
+	u8 *rcv_buf;
+	u8 *snd_buf;
+	struct urb *rcv_urb;
+	struct urb *snd_urb;
+	struct completion rcv_done;
+	struct completion snd_done;
+};
+
+/* the following three functions are stolen from drivers/usb/core/message.c */
+static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
+{
+	complete((struct completion *)urb->context);
+}
+
+static void cxacru_timeout_kill(unsigned long data)
+{
+	usb_unlink_urb((struct urb *) data);
+}
+
+static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
+				 int* actual_length)
+{
+	struct timer_list timer;
+	int status;
+
+	init_timer(&timer);
+	timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
+	timer.data = (unsigned long) urb;
+	timer.function = cxacru_timeout_kill;
+	add_timer(&timer);
+	wait_for_completion(done);
+	status = urb->status;
+	if (status == -ECONNRESET)
+		status = -ETIMEDOUT;
+	del_timer_sync(&timer);
+
+	if (actual_length)
+		*actual_length = urb->actual_length;
+	return status;
+}
+
+static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
+		     u8 *wdata, int wsize, u8 *rdata, int rsize)
+{
+	int ret, actlen;
+	int offb, offd;
+	const int stride = CMD_PACKET_SIZE - 4;
+	u8 *wbuf = instance->snd_buf;
+	u8 *rbuf = instance->rcv_buf;
+	int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+	int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+
+	if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
+		dbg("too big transfer requested");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	down(&instance->cm_serialize);
+
+	/* submit reading urb before the writing one */
+	init_completion(&instance->rcv_done);
+	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
+	if (ret < 0) {
+		dbg("submitting read urb for cm %#x failed", cm);
+		ret = ret;
+		goto fail;
+	}
+
+	memset(wbuf, 0, wbuflen);
+	/* handle wsize == 0 */
+	wbuf[0] = cm;
+	for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) {
+		wbuf[offb] = cm;
+		memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd));
+	}
+
+	instance->snd_urb->transfer_buffer_length = wbuflen;
+	init_completion(&instance->snd_done);
+	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
+	if (ret < 0) {
+		dbg("submitting write urb for cm %#x failed", cm);
+		ret = ret;
+		goto fail;
+	}
+
+	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
+	if (ret < 0) {
+		dbg("sending cm %#x failed", cm);
+		ret = ret;
+		goto fail;
+	}
+
+	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
+	if (ret < 0) {
+		dbg("receiving cm %#x failed", cm);
+		ret = ret;
+		goto fail;
+	}
+	if (actlen % CMD_PACKET_SIZE || !actlen) {
+		dbg("response is not a positive multiple of %d: %#x",
+				CMD_PACKET_SIZE, actlen);
+		ret = -EIO;
+		goto fail;
+	}
+
+	/* check the return status and copy the data to the output buffer, if needed */
+	for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
+		if (rbuf[offb] != cm) {
+			dbg("wrong cm %#x in response", rbuf[offb]);
+			ret = -EIO;
+			goto fail;
+		}
+		if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
+			dbg("response failed: %#x", rbuf[offb + 1]);
+			ret = -EIO;
+			goto fail;
+		}
+		if (offd >= rsize)
+			break;
+		memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd));
+		offd += stride;
+	}
+
+	ret = offd;
+	dbg("cm %#x", cm);
+fail:
+	up(&instance->cm_serialize);
+	return ret;
+}
+
+static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm,
+			       u32 *data, int size)
+{
+	int ret, len;
+	u32 *buf;
+	int offb, offd;
+	const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
+	int buflen =  ((size - 1) / stride + 1 + size * 2) * 4;
+
+	buf = kmalloc(buflen, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen);
+	if (ret < 0)
+		goto cleanup;
+
+	/* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */
+	len = ret / 4;
+	for (offb = 0; offb < len; ) {
+		int l = le32_to_cpu(buf[offb++]);
+		if (l > stride || l > (len - offb) / 2) {
+			dbg("wrong data length %#x in response", l);
+			ret = -EIO;
+			goto cleanup;
+		}
+		while (l--) {
+			offd = le32_to_cpu(buf[offb++]);
+			if (offd >= size) {
+				dbg("wrong index %#x in response", offd);
+				ret = -EIO;
+				goto cleanup;
+			}
+			data[offd] = le32_to_cpu(buf[offb++]);
+		}
+	}
+
+	ret = 0;
+
+cleanup:
+	kfree(buf);
+	return ret;
+}
+
+static int cxacru_card_status(struct cxacru_data *instance)
+{
+	int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+	if (ret < 0) {		/* firmware not loaded */
+		dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance);
+
+static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
+		struct atm_dev *atm_dev)
+{
+	struct cxacru_data *instance = usbatm_instance->driver_data;
+	struct device *dev = &usbatm_instance->usb_intf->dev;
+	/*
+	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+	*/
+	int ret;
+
+	dbg("cxacru_atm_start");
+
+	/* Read MAC address */
+	ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
+			atm_dev->esi, sizeof(atm_dev->esi));
+	if (ret < 0) {
+		dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
+		return ret;
+	}
+
+	/* start ADSL */
+	ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
+	if (ret < 0) {
+		dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
+		return ret;
+	}
+
+	/* Start status polling */
+	cxacru_poll_status(instance);
+	return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance)
+{
+	u32 buf[CXINF_MAX] = {};
+	struct device *dev = &instance->usbatm->usb_intf->dev;
+	struct atm_dev *atm_dev = instance->usbatm->atm_dev;
+	int ret;
+
+	ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
+	if (ret < 0) {
+		dev_warn(dev, "poll status: error %d\n", ret);
+		goto reschedule;
+	}
+
+	if (instance->line_status == buf[CXINF_LINE_STATUS])
+		goto reschedule;
+
+	instance->line_status = buf[CXINF_LINE_STATUS];
+	switch (instance->line_status) {
+	case 0:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: down\n");
+		break;
+
+	case 1:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: attemtping to activate\n");
+		break;
+
+	case 2:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: training\n");
+		break;
+
+	case 3:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: channel analysis\n");
+		break;
+
+	case 4:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: exchange\n");
+		break;
+
+	case 5:
+		atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
+		atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+		dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n",
+		     buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
+		break;
+
+	case 6:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: waiting\n");
+		break;
+
+	case 7:
+		atm_dev->signal = ATM_PHY_SIG_LOST;
+		dev_info(dev, "ADSL line: initializing\n");
+		break;
+
+	default:
+		atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+		dev_info(dev, "Unknown line state %02x\n", instance->line_status);
+		break;
+	}
+reschedule:
+	schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
+}
+
+static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
+		     u8 code1, u8 code2, u32 addr, u8 *data, int size)
+{
+	int ret;
+	u8 *buf;
+	int offd, offb;
+	const int stride = CMD_PACKET_SIZE - 8;
+
+	buf = (u8 *) __get_free_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	offb = offd = 0;
+	do {
+		int l = min_t(int, stride, size - offd);
+		buf[offb++] = fw;
+		buf[offb++] = l;
+		buf[offb++] = code1;
+		buf[offb++] = code2;
+		*((u32 *) (buf + offb)) = cpu_to_le32(addr);
+		offb += 4;
+		addr += l;
+		if(l)
+			memcpy(buf + offb, data + offd, l);
+		if (l < stride)
+			memset(buf + offb + l, 0, stride - l);
+		offb += stride;
+		offd += stride;
+		if ((offb >= PAGE_SIZE) || (offd >= size)) {
+			ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
+					   buf, offb, NULL, CMD_TIMEOUT);
+			if (ret < 0) {
+				dbg("sending fw %#x failed", fw);
+				goto cleanup;
+			}
+			offb = 0;
+		}
+	} while(offd < size);
+	dbg("sent fw %#x", fw);
+
+	ret = 0;
+
+cleanup:
+	free_page((unsigned long) buf);
+	return ret;
+}
+
+static void cxacru_upload_firmware(struct cxacru_data *instance,
+				   const struct firmware *fw,
+				   const struct firmware *bp,
+				   const struct firmware *cf)
+{
+	int ret;
+	int off;
+	struct usb_device *usb_dev = instance->usbatm->usb_dev;
+	struct device *dev = &instance->usbatm->usb_intf->dev;
+	u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
+	u32 val;
+
+	dbg("cxacru_upload_firmware");
+
+	/* FirmwarePllFClkValue */
+	val = cpu_to_le32(instance->modem_type->pll_f_clk);
+	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4);
+	if (ret) {
+		dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret);
+		return;
+	}
+
+	/* FirmwarePllBClkValue */
+	val = cpu_to_le32(instance->modem_type->pll_b_clk);
+	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4);
+	if (ret) {
+		dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret);
+		return;
+	}
+
+	/* Enable SDRAM */
+	val = cpu_to_le32(SDRAM_ENA);
+	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4);
+	if (ret) {
+		dev_err(dev, "Enable SDRAM failed: %d\n", ret);
+		return;
+	}
+
+	/* Firmware */
+	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
+	if (ret) {
+		dev_err(dev, "Firmware upload failed: %d\n", ret);
+		return;
+	}
+
+	/* Boot ROM patch */
+	if (instance->modem_type->boot_rom_patch) {
+		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
+		if (ret) {
+			dev_err(dev, "Boot ROM patching failed: %d\n", ret);
+			return;
+		}
+	}
+
+	/* Signature */
+	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4);
+	if (ret) {
+		dev_err(dev, "Signature storing failed: %d\n", ret);
+		return;
+	}
+
+	if (instance->modem_type->boot_rom_patch) {
+		val = cpu_to_le32(BR_ADDR);
+		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
+	}
+	else {
+		ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
+	}
+	if (ret) {
+		dev_err(dev, "Passing control to firmware failed: %d\n", ret);
+		return;
+	}
+
+	/* Delay to allow firmware to start up. */
+	msleep_interruptible(1000);
+
+	usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD));
+	usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD));
+	usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA));
+	usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA));
+
+	ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+	if (ret < 0) {
+		dev_err(dev, "modem failed to initialize: %d\n", ret);
+		return;
+	}
+
+	/* Load config data (le32), doing one packet at a time */
+	if (cf)
+		for (off = 0; off < cf->size / 4; ) {
+			u32 buf[CMD_PACKET_SIZE / 4 - 1];
+			int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
+			buf[0] = cpu_to_le32(len);
+			for (i = 0; i < len; i++, off++) {
+				buf[i * 2 + 1] = cpu_to_le32(off);
+				memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
+			}
+			ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
+					(u8 *) buf, len, NULL, 0);
+			if (ret < 0) {
+				dev_err(dev, "load config data failed: %d\n", ret);
+				return;
+			}
+		}
+
+	msleep_interruptible(4000);
+}
+
+static int cxacru_find_firmware(struct cxacru_data *instance,
+				char* phase, const struct firmware **fw_p)
+{
+	struct device *dev = &instance->usbatm->usb_intf->dev;
+	char buf[16];
+
+	sprintf(buf, "cxacru-%s.bin", phase);
+	dbg("cxacru_find_firmware: looking for %s", buf);
+
+	if (request_firmware(fw_p, buf, dev)) {
+		dev_dbg(dev, "no stage %s firmware found\n", phase);
+		return -ENOENT;
+	}
+
+	dev_info(dev, "found firmware %s\n", buf);
+
+	return 0;
+}
+
+static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
+			     struct usb_interface *usb_intf)
+{
+	struct device *dev = &usbatm_instance->usb_intf->dev;
+	const struct firmware *fw, *bp, *cf;
+	struct cxacru_data *instance = usbatm_instance->driver_data;
+
+	int ret = cxacru_find_firmware(instance, "fw", &fw);
+	if (ret) {
+		dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n");
+		return ret;
+	}
+
+	if (instance->modem_type->boot_rom_patch) {
+		ret = cxacru_find_firmware(instance, "bp", &bp);
+		if (ret) {
+			dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n");
+			release_firmware(fw);
+			return ret;
+		}
+	}
+
+	if (cxacru_find_firmware(instance, "cf", &cf))		/* optional */
+		cf = NULL;
+
+	cxacru_upload_firmware(instance, fw, bp, cf);
+
+	if (cf)
+		release_firmware(cf);
+	if (instance->modem_type->boot_rom_patch)
+		release_firmware(bp);
+	release_firmware(fw);
+
+	ret = cxacru_card_status(instance);
+	if (ret)
+		dbg("modem initialisation failed");
+	else
+		dbg("done setting up the modem");
+
+	return ret;
+}
+
+static int cxacru_bind(struct usbatm_data *usbatm_instance,
+		       struct usb_interface *intf, const struct usb_device_id *id,
+		       int *need_heavy_init)
+{
+	struct cxacru_data *instance;
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	int ret;
+
+	/* instance init */
+	instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance) {
+		dbg("cxacru_bind: no memory for instance data");
+		return -ENOMEM;
+	}
+
+	memset(instance, 0, sizeof(*instance));
+
+	instance->usbatm = usbatm_instance;
+	instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
+
+	instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
+	if (!instance->rcv_buf) {
+		dbg("cxacru_bind: no memory for rcv_buf");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
+	if (!instance->snd_buf) {
+		dbg("cxacru_bind: no memory for snd_buf");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!instance->rcv_urb) {
+		dbg("cxacru_bind: no memory for rcv_urb");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!instance->snd_urb) {
+		dbg("cxacru_bind: no memory for snd_urb");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	usb_fill_int_urb(instance->rcv_urb,
+			usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
+			instance->rcv_buf, PAGE_SIZE,
+			cxacru_blocking_completion, &instance->rcv_done, 1);
+	instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+	usb_fill_int_urb(instance->snd_urb,
+			usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
+			instance->snd_buf, PAGE_SIZE,
+			cxacru_blocking_completion, &instance->snd_done, 4);
+	instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+	init_MUTEX(&instance->cm_serialize);
+
+	INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance);
+
+	usbatm_instance->driver_data = instance;
+
+	*need_heavy_init = cxacru_card_status(instance);
+
+	return 0;
+
+ fail:
+	free_page((unsigned long) instance->snd_buf);
+	free_page((unsigned long) instance->rcv_buf);
+	usb_free_urb(instance->snd_urb);
+	usb_free_urb(instance->rcv_urb);
+	kfree(instance);
+
+	return ret;
+}
+
+static void cxacru_unbind(struct usbatm_data *usbatm_instance,
+		struct usb_interface *intf)
+{
+	struct cxacru_data *instance = usbatm_instance->driver_data;
+
+	dbg("cxacru_unbind entered");
+
+	if (!instance) {
+		dbg("cxacru_unbind: NULL instance!");
+		return;
+	}
+
+	while (!cancel_delayed_work(&instance->poll_work))
+	       flush_scheduled_work();
+
+	usb_kill_urb(instance->snd_urb);
+	usb_kill_urb(instance->rcv_urb);
+	usb_free_urb(instance->snd_urb);
+	usb_free_urb(instance->rcv_urb);
+
+	free_page((unsigned long) instance->snd_buf);
+	free_page((unsigned long) instance->rcv_buf);
+	kfree(instance);
+
+	usbatm_instance->driver_data = NULL;
+}
+
+static const struct cxacru_modem_type cxacru_cafe = {
+	.pll_f_clk = 0x02d874df,
+	.pll_b_clk = 0x0196a51a,
+	.boot_rom_patch = 1,
+};
+
+static const struct cxacru_modem_type cxacru_cb00 = {
+	.pll_f_clk = 0x5,
+	.pll_b_clk = 0x3,
+	.boot_rom_patch = 0,
+};
+
+static const struct usb_device_id cxacru_usb_ids[] = {
+	{ /* V = Conexant			P = ADSL modem (Euphrates project)	*/
+		USB_DEVICE(0x0572, 0xcafe),	.driver_info = (unsigned long) &cxacru_cafe
+	},
+	{ /* V = Conexant			P = ADSL modem (Hasbani project)	*/
+		USB_DEVICE(0x0572, 0xcb00),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Conexant			P = ADSL modem				*/
+		USB_DEVICE(0x0572, 0xcb01),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Conexant			P = ADSL modem				*/
+		USB_DEVICE(0x0572, 0xcb06),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Olitec				P = ADSL modem version 2		*/
+		USB_DEVICE(0x08e3, 0x0100),	.driver_info = (unsigned long) &cxacru_cafe
+	},
+	{ /* V = Olitec				P = ADSL modem version 3		*/
+		USB_DEVICE(0x08e3, 0x0102),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Trust/Amigo Technology Co.	P = AMX-CA86U				*/
+		USB_DEVICE(0x0eb0, 0x3457),	.driver_info = (unsigned long) &cxacru_cafe
+	},
+	{ /* V = Zoom				P = 5510				*/
+		USB_DEVICE(0x1803, 0x5510),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Draytek			P = Vigor 318				*/
+		USB_DEVICE(0x0675, 0x0200),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Zyxel				P = 630-C1 aka OMNI ADSL USB (Annex A)	*/
+		USB_DEVICE(0x0586, 0x330a),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Zyxel				P = 630-C3 aka OMNI ADSL USB (Annex B)	*/
+		USB_DEVICE(0x0586, 0x330b),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Aethra				P = Starmodem UM1020			*/
+		USB_DEVICE(0x0659, 0x0020),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Aztech Systems			P = ? AKA Pirelli AUA-010		*/
+		USB_DEVICE(0x0509, 0x0812),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Netopia			P = Cayman 3341(Annex A)/3351(Annex B)	*/
+		USB_DEVICE(0x100d, 0xcb01),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{ /* V = Netopia			P = Cayman 3342(Annex A)/3352(Annex B)	*/
+		USB_DEVICE(0x100d, 0x3342),	.driver_info = (unsigned long) &cxacru_cb00
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, cxacru_usb_ids);
+
+static struct usbatm_driver cxacru_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= cxacru_driver_name,
+	.bind		= cxacru_bind,
+	.heavy_init	= cxacru_heavy_init,
+	.unbind		= cxacru_unbind,
+	.atm_start	= cxacru_atm_start,
+	.in		= CXACRU_EP_DATA,
+	.out		= CXACRU_EP_DATA,
+	.rx_padding	= 3,
+	.tx_padding	= 11,
+};
+
+static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	return usbatm_usb_probe(intf, id, &cxacru_driver);
+}
+
+static struct usb_driver cxacru_usb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= cxacru_driver_name,
+	.probe		= cxacru_usb_probe,
+	.disconnect	= usbatm_usb_disconnect,
+	.id_table	= cxacru_usb_ids
+};
+
+static int __init cxacru_init(void)
+{
+	return usb_register(&cxacru_usb_driver);
+}
+
+static void __exit cxacru_cleanup(void)
+{
+	usb_deregister(&cxacru_usb_driver);
+}
+
+module_init(cxacru_init);
+module_exit(cxacru_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 2a1697b..6a6eaa2 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -5,6 +5,8 @@
  *  Copyright (C) 2003, Duncan Sands
  *  Copyright (C) 2004, David Woodhouse
  *
+ *  Based on "modem_run.c", copyright (C) 2001, Benoit Papillault
+ *
  *  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)
@@ -21,467 +23,189 @@
  *
  ******************************************************************************/
 
+#include <asm/page.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
 #include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
-#include "usb_atm.h"
-
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#	define USE_FW_LOADER
-#endif
+#include "usbatm.h"
 
 #define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION	"1.8"
+#define DRIVER_VERSION	"1.9"
 #define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSION
 
 static const char speedtch_driver_name[] = "speedtch";
 
-#define SPEEDTOUCH_VENDORID		0x06b9
-#define SPEEDTOUCH_PRODUCTID		0x4061
+#define CTRL_TIMEOUT 2000	/* milliseconds */
+#define DATA_TIMEOUT 2000	/* milliseconds */
 
-/* Timeout in jiffies */
-#define CTRL_TIMEOUT 2000
-#define DATA_TIMEOUT 2000
+#define OFFSET_7	0		/* size 1 */
+#define OFFSET_b	1		/* size 8 */
+#define OFFSET_d	9		/* size 4 */
+#define OFFSET_e	13		/* size 1 */
+#define OFFSET_f	14		/* size 1 */
+#define TOTAL		15
 
-#define OFFSET_7  0		/* size 1 */
-#define OFFSET_b  1		/* size 8 */
-#define OFFSET_d  9		/* size 4 */
-#define OFFSET_e 13		/* size 1 */
-#define OFFSET_f 14		/* size 1 */
-#define TOTAL    15
+#define SIZE_7		1
+#define SIZE_b		8
+#define SIZE_d		4
+#define SIZE_e		1
+#define SIZE_f		1
 
-#define SIZE_7 1
-#define SIZE_b 8
-#define SIZE_d 4
-#define SIZE_e 1
-#define SIZE_f 1
+#define MIN_POLL_DELAY		5000	/* milliseconds */
+#define MAX_POLL_DELAY		60000	/* milliseconds */
 
-static int dl_512_first = 0;
-static int sw_buffering = 0;
+#define RESUBMIT_DELAY		1000	/* milliseconds */
 
-module_param(dl_512_first, bool, 0444);
-MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware");
+#define DEFAULT_ALTSETTING	1
+#define DEFAULT_DL_512_FIRST	0
+#define DEFAULT_SW_BUFFERING	0
 
-module_param(sw_buffering, uint, 0444);
-MODULE_PARM_DESC(sw_buffering, "Enable software buffering");
+static int altsetting = DEFAULT_ALTSETTING;
+static int dl_512_first = DEFAULT_DL_512_FIRST;
+static int sw_buffering = DEFAULT_SW_BUFFERING;
 
-#define UDSL_IOCTL_LINE_UP		1
-#define UDSL_IOCTL_LINE_DOWN		2
+module_param(altsetting, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(altsetting,
+		 "Alternative setting for data interface (default: "
+		 __MODULE_STRING(DEFAULT_ALTSETTING) ")");
 
-#define SPEEDTCH_ENDPOINT_INT		0x81
-#define SPEEDTCH_ENDPOINT_DATA		0x07
-#define SPEEDTCH_ENDPOINT_FIRMWARE	0x05
+module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dl_512_first,
+		 "Read 512 bytes before sending firmware (default: "
+		 __MODULE_STRING(DEFAULT_DL_512_FIRST) ")");
+
+module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sw_buffering,
+		 "Enable software buffering (default: "
+		 __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
+
+#define ENDPOINT_INT		0x81
+#define ENDPOINT_DATA		0x07
+#define ENDPOINT_FIRMWARE	0x05
 
 #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
 
-static struct usb_device_id speedtch_usb_ids[] = {
-	{USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
-
 struct speedtch_instance_data {
-	struct udsl_instance_data u;
+	struct usbatm_data *usbatm;
 
-	/* Status */
+	struct work_struct status_checker;
+
+	int poll_delay; /* milliseconds */
+
+	struct timer_list resubmit_timer;
 	struct urb *int_urb;
 	unsigned char int_data[16];
-	struct work_struct poll_work;
-	struct timer_list poll_timer;
-};
-/* USB */
 
-static int speedtch_usb_probe(struct usb_interface *intf,
-			      const struct usb_device_id *id);
-static void speedtch_usb_disconnect(struct usb_interface *intf);
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
-			      void *user_data);
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs);
-static void speedtch_poll_status(struct speedtch_instance_data *instance);
-
-static struct usb_driver speedtch_usb_driver = {
-	.owner		= THIS_MODULE,
-	.name		= speedtch_driver_name,
-	.probe		= speedtch_usb_probe,
-	.disconnect	= speedtch_usb_disconnect,
-	.ioctl		= speedtch_usb_ioctl,
-	.id_table	= speedtch_usb_ids,
+	unsigned char scratch_buffer[TOTAL];
 };
 
 /***************
 **  firmware  **
 ***************/
 
-static void speedtch_got_firmware(struct speedtch_instance_data *instance,
-				  int got_it)
+static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state)
 {
-	int err;
-	struct usb_interface *intf;
-
-	down(&instance->u.serialize);	/* vs self, speedtch_firmware_start */
-	if (instance->u.status == UDSL_LOADED_FIRMWARE)
-		goto out;
-	if (!got_it) {
-		instance->u.status = UDSL_NO_FIRMWARE;
-		goto out;
-	}
-	if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) {
-		dbg("speedtch_got_firmware: usb_set_interface returned %d!", err);
-		instance->u.status = UDSL_NO_FIRMWARE;
-		goto out;
-	}
-
-	/* Set up interrupt endpoint */
-	intf = usb_ifnum_to_if(instance->u.usb_dev, 0);
-	if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) {
-
-		instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (instance->int_urb) {
-
-			usb_fill_int_urb(instance->int_urb, instance->u.usb_dev,
-					 usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT),
-					 instance->int_data,
-					 sizeof(instance->int_data),
-					 speedtch_handle_int, instance, 50);
-			err = usb_submit_urb(instance->int_urb, GFP_KERNEL);
-			if (err) {
-				/* Doesn't matter; we'll poll anyway */
-				dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err);
-				usb_free_urb(instance->int_urb);
-				instance->int_urb = NULL;
-				usb_driver_release_interface(&speedtch_usb_driver, intf);
-			}
-		}
-	}
-	/* Start status polling */
-	mod_timer(&instance->poll_timer, jiffies + (1 * HZ));
-
-	instance->u.status = UDSL_LOADED_FIRMWARE;
-	tasklet_schedule(&instance->u.receive_tasklet);
- out:
-	up(&instance->u.serialize);
-	wake_up_interruptible(&instance->u.firmware_waiters);
-}
-
-static int speedtch_set_swbuff(struct speedtch_instance_data *instance,
-			       int state)
-{
-	struct usb_device *dev = instance->u.usb_dev;
+	struct usbatm_data *usbatm = instance->usbatm;
+	struct usb_device *usb_dev = usbatm->usb_dev;
 	int ret;
 
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			      0x32, 0x40, state ? 0x01 : 0x00,
-			      0x00, NULL, 0, 100);
-	if (ret < 0) {
-		printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n",
-		     state ? "En" : "Dis", ret);
-		return ret;
-	}
-
-	dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
-	return 0;
+	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			      0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT);
+	if (ret < 0)
+		usb_warn(usbatm,
+			 "%sabling SW buffering: usb_control_msg returned %d\n",
+			 state ? "En" : "Dis", ret);
+	else
+		dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
 }
 
 static void speedtch_test_sequence(struct speedtch_instance_data *instance)
 {
-	struct usb_device *dev = instance->u.usb_dev;
-	unsigned char buf[10];
+	struct usbatm_data *usbatm = instance->usbatm;
+	struct usb_device *usb_dev = usbatm->usb_dev;
+	unsigned char *buf = instance->scratch_buffer;
 	int ret;
 
 	/* URB 147 */
 	buf[0] = 0x1c;
 	buf[1] = 0x50;
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			      0x01, 0x40, 0x0b, 0x00, buf, 2, 100);
+	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			      0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT);
 	if (ret < 0)
-		printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret);
+		usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret);
 
 	/* URB 148 */
 	buf[0] = 0x32;
 	buf[1] = 0x00;
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			      0x01, 0x40, 0x02, 0x00, buf, 2, 100);
+	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			      0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT);
 	if (ret < 0)
-		printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret);
+		usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret);
 
 	/* URB 149 */
 	buf[0] = 0x01;
 	buf[1] = 0x00;
 	buf[2] = 0x01;
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			      0x01, 0x40, 0x03, 0x00, buf, 3, 100);
+	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			      0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT);
 	if (ret < 0)
-		printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret);
+		usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret);
 
 	/* URB 150 */
 	buf[0] = 0x01;
 	buf[1] = 0x00;
 	buf[2] = 0x01;
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			      0x01, 0x40, 0x04, 0x00, buf, 3, 100);
+	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			      0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
 	if (ret < 0)
-		printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret);
+		usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
 }
 
-static int speedtch_start_synchro(struct speedtch_instance_data *instance)
-{
-	struct usb_device *dev = instance->u.usb_dev;
-	unsigned char buf[2];
-	int ret;
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x04, 0x00,
-			      buf, sizeof(buf), CTRL_TIMEOUT);
-	if (ret < 0) {
-		printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret);
-		return ret;
-	}
-
-	dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]);
-	return 0;
-}
-
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs)
-{
-	struct speedtch_instance_data *instance = urb->context;
-	unsigned int count = urb->actual_length;
-	int ret;
-
-	/* The magic interrupt for "up state" */
-	const static unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
-	/* The magic interrupt for "down state" */
-	const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated; clean up */
-		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
-		goto exit;
-	}
-
-	if (count < 6) {
-		dbg("%s - int packet too short", __func__);
-		goto exit;
-	}
-
-	if (!memcmp(up_int, instance->int_data, 6)) {
-		del_timer(&instance->poll_timer);
-		printk(KERN_NOTICE "DSL line goes up\n");
-	} else if (!memcmp(down_int, instance->int_data, 6)) {
-		printk(KERN_NOTICE "DSL line goes down\n");
-	} else {
-		int i;
-
-		printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count);
-		for (i = 0; i < count; i++)
-			printk(" %02x", instance->int_data[i]);
-		printk("\n");
-	}
-	schedule_work(&instance->poll_work);
-
- exit:
-	rmb();
-	if (!instance->int_urb)
-		return;
-
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret)
-		err("%s - usb_submit_urb failed with result %d", __func__, ret);
-}
-
-static int speedtch_get_status(struct speedtch_instance_data *instance,
-			       unsigned char *buf)
-{
-	struct usb_device *dev = instance->u.usb_dev;
-	int ret;
-
-	memset(buf, 0, TOTAL);
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
-			      CTRL_TIMEOUT);
-	if (ret < 0) {
-		dbg("MSG 7 failed");
-		return ret;
-	}
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
-			      CTRL_TIMEOUT);
-	if (ret < 0) {
-		dbg("MSG B failed");
-		return ret;
-	}
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
-			      CTRL_TIMEOUT);
-	if (ret < 0) {
-		dbg("MSG D failed");
-		return ret;
-	}
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
-			      CTRL_TIMEOUT);
-	if (ret < 0) {
-		dbg("MSG E failed");
-		return ret;
-	}
-
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
-			      CTRL_TIMEOUT);
-	if (ret < 0) {
-		dbg("MSG F failed");
-		return ret;
-	}
-
-	return 0;
-}
-
-static void speedtch_poll_status(struct speedtch_instance_data *instance)
-{
-	unsigned char buf[TOTAL];
-	int ret;
-
-	ret = speedtch_get_status(instance, buf);
-	if (ret) {
-		printk(KERN_WARNING
-		       "SpeedTouch: Error %d fetching device status\n", ret);
-		return;
-	}
-
-	dbg("Line state %02x", buf[OFFSET_7]);
-
-	switch (buf[OFFSET_7]) {
-	case 0:
-		if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
-			instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-			printk(KERN_NOTICE "ADSL line is down\n");
-			/* It'll never resync again unless we ask it to... */
-			speedtch_start_synchro(instance);
-		}
-		break;
-
-	case 0x08:
-		if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
-			instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-			printk(KERN_NOTICE "ADSL line is blocked?\n");
-		}
-		break;
-
-	case 0x10:
-		if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
-			instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-			printk(KERN_NOTICE "ADSL line is synchronising\n");
-		}
-		break;
-
-	case 0x20:
-		if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) {
-			int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
-				| (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
-			int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
-				| (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);
-
-			if (!(down_speed & 0x0000ffff) &&
-			    !(up_speed & 0x0000ffff)) {
-				down_speed >>= 16;
-				up_speed >>= 16;
-			}
-			instance->u.atm_dev->link_rate = down_speed * 1000 / 424;
-			instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
-
-			printk(KERN_NOTICE
-			       "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",
-			       down_speed, up_speed);
-		}
-		break;
-
-	default:
-		if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
-			instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-			printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]);
-		}
-		break;
-	}
-}
-
-static void speedtch_timer_poll(unsigned long data)
-{
-	struct speedtch_instance_data *instance = (void *)data;
-
-	schedule_work(&instance->poll_work);
-	mod_timer(&instance->poll_timer, jiffies + (5 * HZ));
-}
-
-#ifdef USE_FW_LOADER
-static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
+static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 				     const struct firmware *fw1,
 				     const struct firmware *fw2)
 {
 	unsigned char *buffer;
-	struct usb_device *usb_dev = instance->u.usb_dev;
+	struct usbatm_data *usbatm = instance->usbatm;
 	struct usb_interface *intf;
-	int actual_length, ret;
+	struct usb_device *usb_dev = usbatm->usb_dev;
+	int actual_length;
+	int ret = 0;
 	int offset;
 
-	dbg("speedtch_upload_firmware");
-
-	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
-		dbg("speedtch_upload_firmware: interface not found!");
-		goto fail;
-	}
+	usb_dbg(usbatm, "%s entered\n", __func__);
 
 	if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
-		dbg("speedtch_upload_firmware: no memory for buffer!");
-		goto fail;
+		ret = -ENOMEM;
+		usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
+		goto out;
 	}
 
-	/* A user-space firmware loader may already have claimed interface #2 */
-	if ((ret =
-	     usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) {
-		dbg("speedtch_upload_firmware: interface in use (%d)!", ret);
-		goto fail_free;
+	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+		ret = -ENODEV;
+		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
+		goto out_free;
 	}
 
 	/* URB 7 */
 	if (dl_512_first) {	/* some modems need a read before writing the firmware */
-		ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+		ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
 				   buffer, 0x200, &actual_length, 2000);
 
 		if (ret < 0 && ret != -ETIMEDOUT)
-			dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);
+			usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
 		else
-			dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", ret);
+			usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret);
 	}
 
 	/* URB 8 : both leds are static green */
@@ -489,60 +213,60 @@
 		int thislen = min_t(int, PAGE_SIZE, fw1->size - offset);
 		memcpy(buffer, fw1->data + offset, thislen);
 
-		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
 				   buffer, thislen, &actual_length, DATA_TIMEOUT);
 
 		if (ret < 0) {
-			dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret);
-			goto fail_release;
+			usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
+			goto out_free;
 		}
-		dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size);
+		usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size);
 	}
 
 	/* USB led blinking green, ADSL led off */
 
 	/* URB 11 */
-	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
 			   buffer, 0x200, &actual_length, DATA_TIMEOUT);
 
 	if (ret < 0) {
-		dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret);
-		goto fail_release;
+		usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
+		goto out_free;
 	}
-	dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", actual_length);
+	usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);
 
 	/* URBs 12 to 139 - USB led blinking green, ADSL led off */
 	for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) {
 		int thislen = min_t(int, PAGE_SIZE, fw2->size - offset);
 		memcpy(buffer, fw2->data + offset, thislen);
 
-		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
 				   buffer, thislen, &actual_length, DATA_TIMEOUT);
 
 		if (ret < 0) {
-			dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret);
-			goto fail_release;
+			usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
+			goto out_free;
 		}
 	}
-	dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size);
+	usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size);
 
 	/* USB led static green, ADSL led static red */
 
 	/* URB 142 */
-	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
 			   buffer, 0x200, &actual_length, DATA_TIMEOUT);
 
 	if (ret < 0) {
-		dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret);
-		goto fail_release;
+		usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
+		goto out_free;
 	}
 
 	/* success */
-	dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length);
+	usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length);
 
 	/* Delay to allow firmware to start up. We can do this here
 	   because we're in our own kernel thread anyway. */
-	msleep(1000);
+	msleep_interruptible(1000);
 
 	/* Enable software buffering, if requested */
 	if (sw_buffering)
@@ -551,291 +275,546 @@
 	/* Magic spell; don't ask us what this does */
 	speedtch_test_sequence(instance);
 
-	/* Start modem synchronisation */
-	if (speedtch_start_synchro(instance))
-		dbg("speedtch_start_synchro: failed");
+	ret = 0;
 
-	speedtch_got_firmware(instance, 1);
-
+out_free:
 	free_page((unsigned long)buffer);
-	return;
-
- fail_release:
-	/* Only release interface #2 if uploading failed; we don't release it
-	   we succeeded.  This prevents the userspace tools from trying to load
-	   the firmware themselves */
-	usb_driver_release_interface(&speedtch_usb_driver, intf);
- fail_free:
-	free_page((unsigned long)buffer);
- fail:
-	speedtch_got_firmware(instance, 0);
+out:
+	return ret;
 }
 
-static int speedtch_find_firmware(struct speedtch_instance_data
-				  *instance, int phase,
+static int speedtch_find_firmware(struct usb_interface *intf, int phase,
 				  const struct firmware **fw_p)
 {
-	char buf[24];
-	const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice);
+	struct device *dev = &intf->dev;
+	const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice);
 	const u8 major_revision = bcdDevice >> 8;
 	const u8 minor_revision = bcdDevice & 0xff;
+	char buf[24];
 
 	sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
-	dbg("speedtch_find_firmware: looking for %s", buf);
+	dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
 
-	if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
+	if (request_firmware(fw_p, buf, dev)) {
 		sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
-		dbg("speedtch_find_firmware: looking for %s", buf);
+		dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
 
-		if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
+		if (request_firmware(fw_p, buf, dev)) {
 			sprintf(buf, "speedtch-%d.bin", phase);
-			dbg("speedtch_find_firmware: looking for %s", buf);
+			dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
 
-			if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
-				dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase);
+			if (request_firmware(fw_p, buf, dev)) {
+				dev_warn(dev, "no stage %d firmware found!\n", phase);
 				return -ENOENT;
 			}
 		}
 	}
 
-	dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf);
+	dev_info(dev, "found stage %d firmware %s\n", phase, buf);
 
 	return 0;
 }
 
-static int speedtch_load_firmware(void *arg)
+static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
 	const struct firmware *fw1, *fw2;
-	struct speedtch_instance_data *instance = arg;
+	struct speedtch_instance_data *instance = usbatm->driver_data;
+	int ret;
 
-	BUG_ON(!instance);
+	if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0)
+			return ret;
 
-	daemonize("firmware/speedtch");
-
-	if (!speedtch_find_firmware(instance, 1, &fw1)) {
-		if (!speedtch_find_firmware(instance, 2, &fw2)) {
-			speedtch_upload_firmware(instance, fw1, fw2);
-			release_firmware(fw2);
-		}
+	if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) {
 		release_firmware(fw1);
+		return ret;
 	}
 
-	/* In case we failed, set state back to NO_FIRMWARE so that
-	   another later attempt may work. Otherwise, we never actually
-	   manage to recover if, for example, the firmware is on /usr and
-	   we look for it too early. */
-	speedtch_got_firmware(instance, 0);
+	ret = speedtch_upload_firmware(instance, fw1, fw2);
 
-	module_put(THIS_MODULE);
-	udsl_put_instance(&instance->u);
+	release_firmware(fw2);
+	release_firmware(fw1);
+
+	return ret;
+}
+
+
+/**********
+**  ATM  **
+**********/
+
+static int speedtch_read_status(struct speedtch_instance_data *instance)
+{
+	struct usbatm_data *usbatm = instance->usbatm;
+	struct usb_device *usb_dev = usbatm->usb_dev;
+	unsigned char *buf = instance->scratch_buffer;
+	int ret;
+
+	memset(buf, 0, TOTAL);
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
+			      CTRL_TIMEOUT);
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__);
+		return ret;
+	}
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
+			      CTRL_TIMEOUT);
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: MSG B failed\n", __func__);
+		return ret;
+	}
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
+			      CTRL_TIMEOUT);
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: MSG D failed\n", __func__);
+		return ret;
+	}
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
+			      CTRL_TIMEOUT);
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: MSG E failed\n", __func__);
+		return ret;
+	}
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
+			      CTRL_TIMEOUT);
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: MSG F failed\n", __func__);
+		return ret;
+	}
+
 	return 0;
 }
-#endif /* USE_FW_LOADER */
 
-static void speedtch_firmware_start(struct speedtch_instance_data *instance)
+static int speedtch_start_synchro(struct speedtch_instance_data *instance)
 {
-#ifdef USE_FW_LOADER
+	struct usbatm_data *usbatm = instance->usbatm;
+	struct usb_device *usb_dev = usbatm->usb_dev;
+	unsigned char *buf = instance->scratch_buffer;
 	int ret;
-#endif
 
-	dbg("speedtch_firmware_start");
+	atm_dbg(usbatm, "%s entered\n", __func__);
 
-	down(&instance->u.serialize);	/* vs self, speedtch_got_firmware */
+	memset(buf, 0, 2);
 
-	if (instance->u.status >= UDSL_LOADING_FIRMWARE) {
-		up(&instance->u.serialize);
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x12, 0xc0, 0x04, 0x00,
+			      buf, 2, CTRL_TIMEOUT);
+
+	if (ret < 0)
+		atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret);
+	else
+		atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n",
+			__func__, ret, buf[0], buf[1]);
+
+	return ret;
+}
+
+static void speedtch_check_status(struct speedtch_instance_data *instance)
+{
+	struct usbatm_data *usbatm = instance->usbatm;
+	struct atm_dev *atm_dev = usbatm->atm_dev;
+	unsigned char *buf = instance->scratch_buffer;
+	int ret;
+
+	atm_dbg(usbatm, "%s entered\n", __func__);
+
+	ret = speedtch_read_status(instance);
+	if (ret < 0) {
+		atm_warn(usbatm, "error %d fetching device status\n", ret);
+		if (instance->poll_delay < MAX_POLL_DELAY)
+			instance->poll_delay *= 2;
 		return;
 	}
 
-	instance->u.status = UDSL_LOADING_FIRMWARE;
-	up(&instance->u.serialize);
+	if (instance->poll_delay > MIN_POLL_DELAY)
+		instance->poll_delay /= 2;
 
-#ifdef USE_FW_LOADER
-	udsl_get_instance(&instance->u);
-	try_module_get(THIS_MODULE);
+	atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]);
 
-	ret = kernel_thread(speedtch_load_firmware, instance,
-			    CLONE_FS | CLONE_FILES);
+	switch (buf[OFFSET_7]) {
+	case 0:
+		if (atm_dev->signal != ATM_PHY_SIG_LOST) {
+			atm_dev->signal = ATM_PHY_SIG_LOST;
+			atm_info(usbatm, "ADSL line is down\n");
+			/* It'll never resync again unless we ask it to... */
+			ret = speedtch_start_synchro(instance);
+		}
+		break;
 
-	if (ret >= 0)
-		return;		/* OK */
+	case 0x08:
+		if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
+			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+			atm_info(usbatm, "ADSL line is blocked?\n");
+		}
+		break;
 
-	dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret);
+	case 0x10:
+		if (atm_dev->signal != ATM_PHY_SIG_LOST) {
+			atm_dev->signal = ATM_PHY_SIG_LOST;
+			atm_info(usbatm, "ADSL line is synchronising\n");
+		}
+		break;
 
-	module_put(THIS_MODULE);
-	udsl_put_instance(&instance->u);
-	/* Just pretend it never happened... hope modem_run happens */
-#endif				/* USE_FW_LOADER */
+	case 0x20:
+		if (atm_dev->signal != ATM_PHY_SIG_FOUND) {
+			int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
+				| (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
+			int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
+				| (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);
 
-	speedtch_got_firmware(instance, 0);
+			if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) {
+				down_speed >>= 16;
+				up_speed >>= 16;
+			}
+
+			atm_dev->link_rate = down_speed * 1000 / 424;
+			atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+			atm_info(usbatm,
+				 "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",
+				 down_speed, up_speed);
+		}
+		break;
+
+	default:
+		if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
+			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+			atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]);
+		}
+		break;
+	}
 }
 
-static int speedtch_firmware_wait(struct udsl_instance_data *instance)
+static void speedtch_status_poll(unsigned long data)
 {
-	speedtch_firmware_start((void *)instance);
+	struct speedtch_instance_data *instance = (void *)data;
 
-	if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0)
-		return -ERESTARTSYS;
+	schedule_work(&instance->status_checker);
 
-	return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN;
+	/* The following check is racy, but the race is harmless */
+	if (instance->poll_delay < MAX_POLL_DELAY)
+		mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
+	else
+		atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
 }
 
+static void speedtch_resubmit_int(unsigned long data)
+{
+	struct speedtch_instance_data *instance = (void *)data;
+	struct urb *int_urb = instance->int_urb;
+	int ret;
+
+	atm_dbg(instance->usbatm, "%s entered\n", __func__);
+
+	if (int_urb) {
+		ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+		if (!ret)
+			schedule_work(&instance->status_checker);
+		else {
+			atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+			mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
+		}
+	}
+}
+
+static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
+{
+	struct speedtch_instance_data *instance = int_urb->context;
+	struct usbatm_data *usbatm = instance->usbatm;
+	unsigned int count = int_urb->actual_length;
+	int ret = int_urb->status;
+
+	/* The magic interrupt for "up state" */
+	const static unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
+	/* The magic interrupt for "down state" */
+	const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	atm_dbg(usbatm, "%s entered\n", __func__);
+
+	if (ret < 0) {
+		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+		goto fail;
+	}
+
+	if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
+		del_timer(&instance->status_checker.timer);
+		atm_info(usbatm, "DSL line goes up\n");
+	} else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
+		atm_info(usbatm, "DSL line goes down\n");
+	} else {
+		int i;
+
+		atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count);
+		for (i = 0; i < count; i++)
+			printk(" %02x", instance->int_data[i]);
+		printk("\n");
+		goto fail;
+	}
+
+	if ((int_urb = instance->int_urb)) {
+		ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+		schedule_work(&instance->status_checker);
+		if (ret < 0) {
+			atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+			goto fail;
+		}
+	}
+
+	return;
+
+fail:
+	if ((int_urb = instance->int_urb))
+		mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
+}
+
+static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
+{
+	struct usb_device *usb_dev = usbatm->usb_dev;
+	struct speedtch_instance_data *instance = usbatm->driver_data;
+	int i, ret;
+	unsigned char mac_str[13];
+
+	atm_dbg(usbatm, "%s entered\n", __func__);
+
+	if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {
+		atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);
+		return ret;
+	}
+
+	/* Set MAC address, it is stored in the serial number */
+	memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
+	if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
+		for (i = 0; i < 6; i++)
+			atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
+	}
+
+	/* Start modem synchronisation */
+	ret = speedtch_start_synchro(instance);
+
+	/* Set up interrupt endpoint */
+	if (instance->int_urb) {
+		ret = usb_submit_urb(instance->int_urb, GFP_KERNEL);
+		if (ret < 0) {
+			/* Doesn't matter; we'll poll anyway */
+			atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret);
+			usb_free_urb(instance->int_urb);
+			instance->int_urb = NULL;
+		}
+	}
+
+	/* Start status polling */
+	mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
+
+	return 0;
+}
+
+static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
+{
+	struct speedtch_instance_data *instance = usbatm->driver_data;
+	struct urb *int_urb = instance->int_urb;
+
+	atm_dbg(usbatm, "%s entered\n", __func__);
+
+	del_timer_sync(&instance->status_checker.timer);
+
+	/*
+	 * Since resubmit_timer and int_urb can schedule themselves and
+	 * each other, shutting them down correctly takes some care
+	 */
+	instance->int_urb = NULL; /* signal shutdown */
+	mb();
+	usb_kill_urb(int_urb);
+	del_timer_sync(&instance->resubmit_timer);
+	/*
+	 * At this point, speedtch_handle_int and speedtch_resubmit_int
+	 * can run or be running, but instance->int_urb == NULL means that
+	 * they will not reschedule
+	 */
+	usb_kill_urb(int_urb);
+	del_timer_sync(&instance->resubmit_timer);
+	usb_free_urb(int_urb);
+
+	flush_scheduled_work();
+}
+
+
 /**********
 **  USB  **
 **********/
 
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
-			      void *user_data)
-{
-	struct speedtch_instance_data *instance = usb_get_intfdata(intf);
+static struct usb_device_id speedtch_usb_ids[] = {
+	{USB_DEVICE(0x06b9, 0x4061)},
+	{}
+};
 
-	dbg("speedtch_usb_ioctl entered");
+MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
 
-	if (!instance) {
-		dbg("speedtch_usb_ioctl: NULL instance!");
-		return -ENODEV;
-	}
+static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);
 
-	switch (code) {
-	case UDSL_IOCTL_LINE_UP:
-		instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
-		speedtch_got_firmware(instance, 1);
-		return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO;
-	case UDSL_IOCTL_LINE_DOWN:
-		instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
-		return 0;
-	default:
-		return -ENOTTY;
-	}
+static struct usb_driver speedtch_usb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= speedtch_driver_name,
+	.probe		= speedtch_usb_probe,
+	.disconnect	= usbatm_usb_disconnect,
+	.id_table	= speedtch_usb_ids
+};
+
+static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
+	struct usb_interface *cur_intf;
+	int i;
+
+	for(i = 0; i < num_interfaces; i++)
+		if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
+			usb_set_intfdata(cur_intf, NULL);
+			usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
+		}
 }
 
-static int speedtch_usb_probe(struct usb_interface *intf,
-			      const struct usb_device_id *id)
+static int speedtch_bind(struct usbatm_data *usbatm,
+			 struct usb_interface *intf,
+			 const struct usb_device_id *id,
+			 int *need_heavy_init)
 {
-	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct usb_interface *cur_intf;
 	struct speedtch_instance_data *instance;
-	unsigned char mac_str[13];
-	int ret, i;
-	char buf7[SIZE_7];
+	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
+	int i, ret;
 
-	dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",
-	    le16_to_cpu(dev->descriptor.idVendor),
-	    le16_to_cpu(dev->descriptor.idProduct), ifnum);
+	usb_dbg(usbatm, "%s entered\n", __func__);
 
-	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || 
-	    (ifnum != 1))
+	if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+		usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
 		return -ENODEV;
+	}
 
-	dbg("speedtch_usb_probe: device accepted");
+	/* claim all interfaces */
 
-	/* instance init */
+	for (i=0; i < num_interfaces; i++) {
+		cur_intf = usb_ifnum_to_if(usb_dev, i);
+
+		if ((i != ifnum) && cur_intf) {
+			ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);
+
+			if (ret < 0) {
+				usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
+				speedtch_release_interfaces(usb_dev, i);
+				return ret;
+			}
+		}
+	}
+
 	instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+
 	if (!instance) {
-		dbg("speedtch_usb_probe: no memory for instance data!");
-		return -ENOMEM;
+		usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);
+		ret = -ENOMEM;
+		goto fail_release;
 	}
 
 	memset(instance, 0, sizeof(struct speedtch_instance_data));
 
-	if ((ret = usb_set_interface(dev, 0, 0)) < 0)
-		goto fail;
+	instance->usbatm = usbatm;
 
-	if ((ret = usb_set_interface(dev, 2, 0)) < 0)
-		goto fail;
+	INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);
 
-	instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA;
-	instance->u.firmware_wait = speedtch_firmware_wait;
-	instance->u.driver_name = speedtch_driver_name;
+	instance->status_checker.timer.function = speedtch_status_poll;
+	instance->status_checker.timer.data = (unsigned long)instance;
+	instance->poll_delay = MIN_POLL_DELAY;
 
-	ret = udsl_instance_setup(dev, &instance->u);
-	if (ret)
-		goto fail;
+	init_timer(&instance->resubmit_timer);
+	instance->resubmit_timer.function = speedtch_resubmit_int;
+	instance->resubmit_timer.data = (unsigned long)instance;
 
-	init_timer(&instance->poll_timer);
-	instance->poll_timer.function = speedtch_timer_poll;
-	instance->poll_timer.data = (unsigned long)instance;
+	instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
 
-	INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance);
+	if (instance->int_urb)
+		usb_fill_int_urb(instance->int_urb, usb_dev,
+				 usb_rcvintpipe(usb_dev, ENDPOINT_INT),
+				 instance->int_data, sizeof(instance->int_data),
+				 speedtch_handle_int, instance, 50);
+	else
+		usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
 
-	/* set MAC address, it is stored in the serial number */
-	memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi));
-	if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
-		for (i = 0; i < 6; i++)
-			instance->u.atm_dev->esi[i] =
-				(hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
-	}
+	/* check whether the modem already seems to be alive */
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      0x12, 0xc0, 0x07, 0x00,
+			      instance->scratch_buffer + OFFSET_7, SIZE_7, 500);
 
-	/* First check whether the modem already seems to be alive */
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			      0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500);
+	*need_heavy_init = (ret != SIZE_7);
 
-	if (ret == SIZE_7) {
-		dbg("firmware appears to be already loaded");
-		speedtch_got_firmware(instance, 1);
-		speedtch_poll_status(instance);
-	} else {
-		speedtch_firmware_start(instance);
-	}
+	usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already");
 
-	usb_set_intfdata(intf, instance);
+	if (*need_heavy_init)
+		if ((ret = usb_reset_device(usb_dev)) < 0)
+			goto fail_free;
+
+        usbatm->driver_data = instance;
 
 	return 0;
 
- fail:
+fail_free:
+	usb_free_urb(instance->int_urb);
 	kfree(instance);
-
-	return -ENOMEM;
+fail_release:
+	speedtch_release_interfaces(usb_dev, num_interfaces);
+	return ret;
 }
 
-static void speedtch_usb_disconnect(struct usb_interface *intf)
+static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
-	struct speedtch_instance_data *instance = usb_get_intfdata(intf);
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct speedtch_instance_data *instance = usbatm->driver_data;
 
-	dbg("speedtch_usb_disconnect entered");
+	usb_dbg(usbatm, "%s entered\n", __func__);
 
-	if (!instance) {
-		dbg("speedtch_usb_disconnect: NULL instance!");
-		return;
-	}
-
-/*QQ need to handle disconnects on interface #2 while uploading firmware */
-/*QQ and what about interface #1? */
-
-	if (instance->int_urb) {
-		struct urb *int_urb = instance->int_urb;
-		instance->int_urb = NULL;
-		wmb();
-		usb_unlink_urb(int_urb);
-		usb_free_urb(int_urb);
-	}
-
-	instance->int_data[0] = 1;
-	del_timer_sync(&instance->poll_timer);
-	wmb();
-	flush_scheduled_work();
-
-	udsl_instance_disconnect(&instance->u);
-
-	/* clean up */
-	usb_set_intfdata(intf, NULL);
-	udsl_put_instance(&instance->u);
+	speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces);
+	usb_free_urb(instance->int_urb);
+	kfree(instance);
 }
 
+
 /***********
 **  init  **
 ***********/
 
+static struct usbatm_driver speedtch_usbatm_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= speedtch_driver_name,
+	.bind		= speedtch_bind,
+	.heavy_init	= speedtch_heavy_init,
+	.unbind		= speedtch_unbind,
+	.atm_start	= speedtch_atm_start,
+	.atm_stop	= speedtch_atm_stop,
+	.in		= ENDPOINT_DATA,
+	.out		= ENDPOINT_DATA
+};
+
+static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver);
+}
+
 static int __init speedtch_usb_init(void)
 {
-	dbg("speedtch_usb_init: driver version " DRIVER_VERSION);
+	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
 
 	return usb_register(&speedtch_usb_driver);
 }
 
 static void __exit speedtch_usb_cleanup(void)
 {
-	dbg("speedtch_usb_cleanup entered");
+	dbg("%s", __func__);
 
 	usb_deregister(&speedtch_usb_driver);
 }
diff --git a/drivers/usb/atm/usb_atm.c b/drivers/usb/atm/usb_atm.c
deleted file mode 100644
index a4cd447..0000000
--- a/drivers/usb/atm/usb_atm.c
+++ /dev/null
@@ -1,1188 +0,0 @@
-/******************************************************************************
- *  usb_atm.c - Generic USB xDSL driver core
- *
- *  Copyright (C) 2001, Alcatel
- *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- *  Copyright (C) 2004, David Woodhouse
- *
- *  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.
- *
- ******************************************************************************/
-
-/*
- *  Written by Johan Verrept, maintained by Duncan Sands (duncan.sands@free.fr)
- *
- *  1.7+:	- See the check-in logs
- *
- *  1.6:	- No longer opens a connection if the firmware is not loaded
- *  		- Added support for the speedtouch 330
- *  		- Removed the limit on the number of devices
- *  		- Module now autoloads on device plugin
- *  		- Merged relevant parts of sarlib
- *  		- Replaced the kernel thread with a tasklet
- *  		- New packet transmission code
- *  		- Changed proc file contents
- *  		- Fixed all known SMP races
- *  		- Many fixes and cleanups
- *  		- Various fixes by Oliver Neukum (oliver@neukum.name)
- *
- *  1.5A:	- Version for inclusion in 2.5 series kernel
- *		- Modifications by Richard Purdie (rpurdie@rpsys.net)
- *		- made compatible with kernel 2.5.6 onwards by changing
- *		udsl_usb_send_data_context->urb to a pointer and adding code
- *		to alloc and free it
- *		- remove_wait_queue() added to udsl_atm_processqueue_thread()
- *
- *  1.5:	- fixed memory leak when atmsar_decode_aal5 returned NULL.
- *		(reported by stephen.robinson@zen.co.uk)
- *
- *  1.4:	- changed the spin_lock() under interrupt to spin_lock_irqsave()
- *		- unlink all active send urbs of a vcc that is being closed.
- *
- *  1.3.1:	- added the version number
- *
- *  1.3:	- Added multiple send urb support
- *		- fixed memory leak and vcc->tx_inuse starvation bug
- *		  when not enough memory left in vcc.
- *
- *  1.2:	- Fixed race condition in udsl_usb_send_data()
- *  1.1:	- Turned off packet debugging
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "usb_atm.h"
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len);
-#define PACKETDEBUG(arg...)	udsl_print_packet (arg)
-#define vdbg(arg...)		dbg (arg)
-#else
-#define PACKETDEBUG(arg...)
-#define vdbg(arg...)
-#endif
-
-#define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION	"1.8"
-#define DRIVER_DESC	"Generic USB ATM/DSL I/O, version " DRIVER_VERSION
-
-static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
-static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
-static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS;
-static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS;
-static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
-static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
-
-module_param(num_rcv_urbs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_urbs,
-		 "Number of urbs used for reception (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
-
-module_param(num_snd_urbs, uint, 0444);
-MODULE_PARM_DESC(num_snd_urbs,
-		 "Number of urbs used for transmission (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
-
-module_param(num_rcv_bufs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_bufs,
-		 "Number of buffers used for reception (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_RCV_BUFS) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_RCV_BUFS) ")");
-
-module_param(num_snd_bufs, uint, 0444);
-MODULE_PARM_DESC(num_snd_bufs,
-		 "Number of buffers used for transmission (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_SND_BUFS) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_SND_BUFS) ")");
-
-module_param(rcv_buf_size, uint, 0444);
-MODULE_PARM_DESC(rcv_buf_size,
-		 "Size of the buffers used for reception (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
-
-module_param(snd_buf_size, uint, 0444);
-MODULE_PARM_DESC(snd_buf_size,
-		 "Size of the buffers used for transmission (range: 0-"
-		 __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
-		 __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
-
-/* ATM */
-
-static void udsl_atm_dev_close(struct atm_dev *dev);
-static int udsl_atm_open(struct atm_vcc *vcc);
-static void udsl_atm_close(struct atm_vcc *vcc);
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
-
-static struct atmdev_ops udsl_atm_devops = {
-	.dev_close	= udsl_atm_dev_close,
-	.open		= udsl_atm_open,
-	.close		= udsl_atm_close,
-	.ioctl		= udsl_atm_ioctl,
-	.send		= udsl_atm_send,
-	.proc_read	= udsl_atm_proc_read,
-	.owner		= THIS_MODULE,
-};
-
-/***********
-**  misc  **
-***********/
-
-static inline void udsl_pop(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-	if (vcc->pop)
-		vcc->pop(vcc, skb);
-	else
-		dev_kfree_skb(skb);
-}
-
-/*************
-**  decode  **
-*************/
-
-static inline struct udsl_vcc_data *udsl_find_vcc(struct udsl_instance_data *instance,
-						  short vpi, int vci)
-{
-	struct udsl_vcc_data *vcc;
-
-	list_for_each_entry(vcc, &instance->vcc_list, list)
-		if ((vcc->vci == vci) && (vcc->vpi == vpi))
-			return vcc;
-	return NULL;
-}
-
-static void udsl_extract_cells(struct udsl_instance_data *instance,
-			       unsigned char *source, unsigned int howmany)
-{
-	struct udsl_vcc_data *cached_vcc = NULL;
-	struct atm_vcc *vcc;
-	struct sk_buff *sarb;
-	struct udsl_vcc_data *vcc_data;
-	int cached_vci = 0;
-	unsigned int i;
-	int pti;
-	int vci;
-	short cached_vpi = 0;
-	short vpi;
-
-	for (i = 0; i < howmany;
-	     i++, source += ATM_CELL_SIZE + instance->rcv_padding) {
-		vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
-		vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
-		pti = (source[3] & 0x2) != 0;
-
-		vdbg("udsl_extract_cells: vpi %hd, vci %d, pti %d", vpi, vci, pti);
-
-		if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi))
-			vcc_data = cached_vcc;
-		else if ((vcc_data = udsl_find_vcc(instance, vpi, vci))) {
-			cached_vcc = vcc_data;
-			cached_vpi = vpi;
-			cached_vci = vci;
-		} else {
-			dbg("udsl_extract_cells: unknown vpi/vci (%hd/%d)!", vpi, vci);
-			continue;
-		}
-
-		vcc = vcc_data->vcc;
-		sarb = vcc_data->sarb;
-
-		if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
-			dbg("udsl_extract_cells: buffer overrun (sarb->len %u, vcc: 0x%p)!", sarb->len, vcc);
-			/* discard cells already received */
-			skb_trim(sarb, 0);
-		}
-
-		memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
-		__skb_put(sarb, ATM_CELL_PAYLOAD);
-
-		if (pti) {
-			struct sk_buff *skb;
-			unsigned int length;
-			unsigned int pdu_length;
-
-			length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
-
-			/* guard against overflow */
-			if (length > ATM_MAX_AAL5_PDU) {
-				dbg("udsl_extract_cells: bogus length %u (vcc: 0x%p)!", length, vcc);
-				atomic_inc(&vcc->stats->rx_err);
-				goto out;
-			}
-
-			pdu_length = UDSL_NUM_CELLS(length) * ATM_CELL_PAYLOAD;
-
-			if (sarb->len < pdu_length) {
-				dbg("udsl_extract_cells: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!", pdu_length, sarb->len, vcc);
-				atomic_inc(&vcc->stats->rx_err);
-				goto out;
-			}
-
-			if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
-				dbg("udsl_extract_cells: packet failed crc check (vcc: 0x%p)!", vcc);
-				atomic_inc(&vcc->stats->rx_err);
-				goto out;
-			}
-
-			vdbg("udsl_extract_cells: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", length, pdu_length, vcc);
-
-			if (!(skb = dev_alloc_skb(length))) {
-				dbg("udsl_extract_cells: no memory for skb (length: %u)!", length);
-				atomic_inc(&vcc->stats->rx_drop);
-				goto out;
-			}
-
-			vdbg("udsl_extract_cells: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", skb, skb->truesize);
-
-			if (!atm_charge(vcc, skb->truesize)) {
-				dbg("udsl_extract_cells: failed atm_charge (skb->truesize: %u)!", skb->truesize);
-				dev_kfree_skb(skb);
-				goto out;	/* atm_charge increments rx_drop */
-			}
-
-			memcpy(skb->data, sarb->tail - pdu_length, length);
-			__skb_put(skb, length);
-
-			vdbg("udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u", skb, skb->len, skb->truesize);
-
-			PACKETDEBUG(skb->data, skb->len);
-
-			vcc->push(vcc, skb);
-
-			atomic_inc(&vcc->stats->rx);
-		out:
-			skb_trim(sarb, 0);
-		}
-	}
-}
-
-/*************
-**  encode  **
-*************/
-
-static inline void udsl_fill_cell_header(unsigned char *target, struct atm_vcc *vcc)
-{
-	target[0] = vcc->vpi >> 4;
-	target[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
-	target[2] = vcc->vci >> 4;
-	target[3] = vcc->vci << 4;
-	target[4] = 0xec;
-}
-
-static const unsigned char zeros[ATM_CELL_PAYLOAD];
-
-static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-	struct udsl_control *ctrl = UDSL_SKB(skb);
-	unsigned int zero_padding;
-	u32 crc;
-
-	ctrl->atm_data.vcc = vcc;
-
-	ctrl->num_cells = UDSL_NUM_CELLS(skb->len);
-	ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
-
-	zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
-
-	if (ctrl->num_entire + 1 < ctrl->num_cells)
-		ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-	else
-		ctrl->pdu_padding = zero_padding;
-
-	ctrl->aal5_trailer[0] = 0;	/* UU = 0 */
-	ctrl->aal5_trailer[1] = 0;	/* CPI = 0 */
-	ctrl->aal5_trailer[2] = skb->len >> 8;
-	ctrl->aal5_trailer[3] = skb->len;
-
-	crc = crc32_be(~0, skb->data, skb->len);
-	crc = crc32_be(crc, zeros, zero_padding);
-	crc = crc32_be(crc, ctrl->aal5_trailer, 4);
-	crc = ~crc;
-
-	ctrl->aal5_trailer[4] = crc >> 24;
-	ctrl->aal5_trailer[5] = crc >> 16;
-	ctrl->aal5_trailer[6] = crc >> 8;
-	ctrl->aal5_trailer[7] = crc;
-}
-
-static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
-				     unsigned int howmany, struct sk_buff *skb,
-				     unsigned char **target_p)
-{
-	struct udsl_control *ctrl = UDSL_SKB(skb);
-	unsigned char *target = *target_p;
-	unsigned int nc, ne, i;
-
-	vdbg("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
-
-	nc = ctrl->num_cells;
-	ne = min(howmany, ctrl->num_entire);
-
-	for (i = 0; i < ne; i++) {
-		udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-		target += ATM_CELL_HEADER;
-		memcpy(target, skb->data, ATM_CELL_PAYLOAD);
-		target += ATM_CELL_PAYLOAD;
-		if (instance->snd_padding) {
-			memset(target, 0, instance->snd_padding);
-			target += instance->snd_padding;
-		}
-		__skb_pull(skb, ATM_CELL_PAYLOAD);
-	}
-
-	ctrl->num_entire -= ne;
-
-	if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
-		goto out;
-
-	udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-	target += ATM_CELL_HEADER;
-	memcpy(target, skb->data, skb->len);
-	target += skb->len;
-	__skb_pull(skb, skb->len);
-	memset(target, 0, ctrl->pdu_padding);
-	target += ctrl->pdu_padding;
-
-	if (--ctrl->num_cells) {
-		if (!--howmany) {
-			ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-			goto out;
-		}
-
-		if (instance->snd_padding) {
-			memset(target, 0, instance->snd_padding);
-			target += instance->snd_padding;
-		}
-		udsl_fill_cell_header(target, ctrl->atm_data.vcc);
-		target += ATM_CELL_HEADER;
-		memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-		target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-
-		--ctrl->num_cells;
-		UDSL_ASSERT(!ctrl->num_cells);
-	}
-
-	memcpy(target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
-	target += ATM_AAL5_TRAILER;
-	/* set pti bit in last cell */
-	*(target + 3 - ATM_CELL_SIZE) |= 0x2;
-	if (instance->snd_padding) {
-		memset(target, 0, instance->snd_padding);
-		target += instance->snd_padding;
-	}
- out:
-	*target_p = target;
-	return nc - ctrl->num_cells;
-}
-
-/**************
-**  receive  **
-**************/
-
-static void udsl_complete_receive(struct urb *urb, struct pt_regs *regs)
-{
-	struct udsl_receive_buffer *buf;
-	struct udsl_instance_data *instance;
-	struct udsl_receiver *rcv;
-	unsigned long flags;
-
-	if (!urb || !(rcv = urb->context)) {
-		dbg("udsl_complete_receive: bad urb!");
-		return;
-	}
-
-	instance = rcv->instance;
-	buf = rcv->buffer;
-
-	buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding);
-
-	vdbg("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf);
-
-	UDSL_ASSERT(buf->filled_cells <= rcv_buf_size);
-
-	/* may not be in_interrupt() */
-	spin_lock_irqsave(&instance->receive_lock, flags);
-	list_add(&rcv->list, &instance->spare_receivers);
-	list_add_tail(&buf->list, &instance->filled_receive_buffers);
-	if (likely(!urb->status))
-		tasklet_schedule(&instance->receive_tasklet);
-	spin_unlock_irqrestore(&instance->receive_lock, flags);
-}
-
-static void udsl_process_receive(unsigned long data)
-{
-	struct udsl_receive_buffer *buf;
-	struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
-	struct udsl_receiver *rcv;
-	int err;
-
- made_progress:
-	while (!list_empty(&instance->spare_receive_buffers)) {
-		spin_lock_irq(&instance->receive_lock);
-		if (list_empty(&instance->spare_receivers)) {
-			spin_unlock_irq(&instance->receive_lock);
-			break;
-		}
-		rcv = list_entry(instance->spare_receivers.next,
-				 struct udsl_receiver, list);
-		list_del(&rcv->list);
-		spin_unlock_irq(&instance->receive_lock);
-
-		buf = list_entry(instance->spare_receive_buffers.next,
-				 struct udsl_receive_buffer, list);
-		list_del(&buf->list);
-
-		rcv->buffer = buf;
-
-		usb_fill_bulk_urb(rcv->urb, instance->usb_dev,
-				  usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint),
-				  buf->base,
-				  rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
-				  udsl_complete_receive, rcv);
-
-		vdbg("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p",
-		     rcv->urb, rcv, buf);
-
-		if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) {
-			dbg("udsl_process_receive: urb submission failed (%d)!", err);
-			list_add(&buf->list, &instance->spare_receive_buffers);
-			spin_lock_irq(&instance->receive_lock);
-			list_add(&rcv->list, &instance->spare_receivers);
-			spin_unlock_irq(&instance->receive_lock);
-			break;
-		}
-	}
-
-	spin_lock_irq(&instance->receive_lock);
-	if (list_empty(&instance->filled_receive_buffers)) {
-		spin_unlock_irq(&instance->receive_lock);
-		return;		/* done - no more buffers */
-	}
-	buf = list_entry(instance->filled_receive_buffers.next,
-			 struct udsl_receive_buffer, list);
-	list_del(&buf->list);
-	spin_unlock_irq(&instance->receive_lock);
-
-	vdbg("udsl_process_receive: processing buf 0x%p", buf);
-	udsl_extract_cells(instance, buf->base, buf->filled_cells);
-	list_add(&buf->list, &instance->spare_receive_buffers);
-	goto made_progress;
-}
-
-/***********
-**  send  **
-***********/
-
-static void udsl_complete_send(struct urb *urb, struct pt_regs *regs)
-{
-	struct udsl_instance_data *instance;
-	struct udsl_sender *snd;
-	unsigned long flags;
-
-	if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
-		dbg("udsl_complete_send: bad urb!");
-		return;
-	}
-
-	vdbg("udsl_complete_send: urb 0x%p, status %d, snd 0x%p, buf 0x%p", urb,
-	     urb->status, snd, snd->buffer);
-
-	/* may not be in_interrupt() */
-	spin_lock_irqsave(&instance->send_lock, flags);
-	list_add(&snd->list, &instance->spare_senders);
-	list_add(&snd->buffer->list, &instance->spare_send_buffers);
-	tasklet_schedule(&instance->send_tasklet);
-	spin_unlock_irqrestore(&instance->send_lock, flags);
-}
-
-static void udsl_process_send(unsigned long data)
-{
-	struct udsl_send_buffer *buf;
-	struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
-	struct sk_buff *skb;
-	struct udsl_sender *snd;
-	int err;
-	unsigned int num_written;
-
- made_progress:
-	spin_lock_irq(&instance->send_lock);
-	while (!list_empty(&instance->spare_senders)) {
-		if (!list_empty(&instance->filled_send_buffers)) {
-			buf = list_entry(instance->filled_send_buffers.next,
-					 struct udsl_send_buffer, list);
-			list_del(&buf->list);
-		} else if ((buf = instance->current_buffer)) {
-			instance->current_buffer = NULL;
-		} else		/* all buffers empty */
-			break;
-
-		snd = list_entry(instance->spare_senders.next,
-				 struct udsl_sender, list);
-		list_del(&snd->list);
-		spin_unlock_irq(&instance->send_lock);
-
-		snd->buffer = buf;
-		usb_fill_bulk_urb(snd->urb, instance->usb_dev,
-				  usb_sndbulkpipe(instance->usb_dev, instance->data_endpoint),
-				  buf->base,
-				  (snd_buf_size - buf->free_cells) * (ATM_CELL_SIZE + instance->snd_padding),
-				  udsl_complete_send, snd);
-
-		vdbg("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p",
-		     snd->urb, snd_buf_size - buf->free_cells, snd, buf);
-
-		if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
-			dbg("udsl_process_send: urb submission failed (%d)!", err);
-			spin_lock_irq(&instance->send_lock);
-			list_add(&snd->list, &instance->spare_senders);
-			spin_unlock_irq(&instance->send_lock);
-			list_add(&buf->list, &instance->filled_send_buffers);
-			return;	/* bail out */
-		}
-
-		spin_lock_irq(&instance->send_lock);
-	}			/* while */
-	spin_unlock_irq(&instance->send_lock);
-
-	if (!instance->current_skb)
-		instance->current_skb = skb_dequeue(&instance->sndqueue);
-	if (!instance->current_skb)
-		return;		/* done - no more skbs */
-
-	skb = instance->current_skb;
-
-	if (!(buf = instance->current_buffer)) {
-		spin_lock_irq(&instance->send_lock);
-		if (list_empty(&instance->spare_send_buffers)) {
-			instance->current_buffer = NULL;
-			spin_unlock_irq(&instance->send_lock);
-			return;	/* done - no more buffers */
-		}
-		buf = list_entry(instance->spare_send_buffers.next,
-			       struct udsl_send_buffer, list);
-		list_del(&buf->list);
-		spin_unlock_irq(&instance->send_lock);
-
-		buf->free_start = buf->base;
-		buf->free_cells = snd_buf_size;
-
-		instance->current_buffer = buf;
-	}
-
-	num_written = udsl_write_cells(instance, buf->free_cells, skb, &buf->free_start);
-
-	vdbg("udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p",
-	     num_written, skb, buf);
-
-	if (!(buf->free_cells -= num_written)) {
-		list_add_tail(&buf->list, &instance->filled_send_buffers);
-		instance->current_buffer = NULL;
-	}
-
-	vdbg("udsl_process_send: buffer contains %d cells, %d left",
-	     snd_buf_size - buf->free_cells, buf->free_cells);
-
-	if (!UDSL_SKB(skb)->num_cells) {
-		struct atm_vcc *vcc = UDSL_SKB(skb)->atm_data.vcc;
-
-		udsl_pop(vcc, skb);
-		instance->current_skb = NULL;
-
-		atomic_inc(&vcc->stats->tx);
-	}
-
-	goto made_progress;
-}
-
-static void udsl_cancel_send(struct udsl_instance_data *instance,
-			     struct atm_vcc *vcc)
-{
-	struct sk_buff *skb, *n;
-
-	dbg("udsl_cancel_send entered");
-	spin_lock_irq(&instance->sndqueue.lock);
-	for (skb = instance->sndqueue.next, n = skb->next;
-	     skb != (struct sk_buff *)&instance->sndqueue;
-	     skb = n, n = skb->next)
-		if (UDSL_SKB(skb)->atm_data.vcc == vcc) {
-			dbg("udsl_cancel_send: popping skb 0x%p", skb);
-			__skb_unlink(skb, &instance->sndqueue);
-			udsl_pop(vcc, skb);
-		}
-	spin_unlock_irq(&instance->sndqueue.lock);
-
-	tasklet_disable(&instance->send_tasklet);
-	if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm_data.vcc == vcc)) {
-		dbg("udsl_cancel_send: popping current skb (0x%p)", skb);
-		instance->current_skb = NULL;
-		udsl_pop(vcc, skb);
-	}
-	tasklet_enable(&instance->send_tasklet);
-	dbg("udsl_cancel_send done");
-}
-
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-	int err;
-
-	vdbg("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
-
-	if (!instance) {
-		dbg("udsl_atm_send: NULL data!");
-		err = -ENODEV;
-		goto fail;
-	}
-
-	if (vcc->qos.aal != ATM_AAL5) {
-		dbg("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal);
-		err = -EINVAL;
-		goto fail;
-	}
-
-	if (skb->len > ATM_MAX_AAL5_PDU) {
-		dbg("udsl_atm_send: packet too long (%d vs %d)!", skb->len,
-		    ATM_MAX_AAL5_PDU);
-		err = -EINVAL;
-		goto fail;
-	}
-
-	PACKETDEBUG(skb->data, skb->len);
-
-	udsl_groom_skb(vcc, skb);
-	skb_queue_tail(&instance->sndqueue, skb);
-	tasklet_schedule(&instance->send_tasklet);
-
-	return 0;
-
- fail:
-	udsl_pop(vcc, skb);
-	return err;
-}
-
-/********************
-**  bean counting  **
-********************/
-
-static void udsl_destroy_instance(struct kref *kref)
-{
-	struct udsl_instance_data *instance =
-	    container_of(kref, struct udsl_instance_data, refcount);
-
-	tasklet_kill(&instance->receive_tasklet);
-	tasklet_kill(&instance->send_tasklet);
-	usb_put_dev(instance->usb_dev);
-	kfree(instance);
-}
-
-void udsl_get_instance(struct udsl_instance_data *instance)
-{
-	kref_get(&instance->refcount);
-}
-
-void udsl_put_instance(struct udsl_instance_data *instance)
-{
-	kref_put(&instance->refcount, udsl_destroy_instance);
-}
-
-/**********
-**  ATM  **
-**********/
-
-static void udsl_atm_dev_close(struct atm_dev *dev)
-{
-	struct udsl_instance_data *instance = dev->dev_data;
-
-	dev->dev_data = NULL;
-	udsl_put_instance(instance);
-}
-
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
-{
-	struct udsl_instance_data *instance = atm_dev->dev_data;
-	int left = *pos;
-
-	if (!instance) {
-		dbg("udsl_atm_proc_read: NULL instance!");
-		return -ENODEV;
-	}
-
-	if (!left--)
-		return sprintf(page, "%s\n", instance->description);
-
-	if (!left--)
-		return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
-			       atm_dev->esi[0], atm_dev->esi[1],
-			       atm_dev->esi[2], atm_dev->esi[3],
-			       atm_dev->esi[4], atm_dev->esi[5]);
-
-	if (!left--)
-		return sprintf(page,
-			       "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
-			       atomic_read(&atm_dev->stats.aal5.tx),
-			       atomic_read(&atm_dev->stats.aal5.tx_err),
-			       atomic_read(&atm_dev->stats.aal5.rx),
-			       atomic_read(&atm_dev->stats.aal5.rx_err),
-			       atomic_read(&atm_dev->stats.aal5.rx_drop));
-
-	if (!left--) {
-		switch (atm_dev->signal) {
-		case ATM_PHY_SIG_FOUND:
-			sprintf(page, "Line up");
-			break;
-		case ATM_PHY_SIG_LOST:
-			sprintf(page, "Line down");
-			break;
-		default:
-			sprintf(page, "Line state unknown");
-			break;
-		}
-
-		if (instance->usb_dev->state == USB_STATE_NOTATTACHED)
-			strcat(page, ", disconnected\n");
-		else {
-			if (instance->status == UDSL_LOADED_FIRMWARE)
-				strcat(page, ", firmware loaded\n");
-			else if (instance->status == UDSL_LOADING_FIRMWARE)
-				strcat(page, ", firmware loading\n");
-			else
-				strcat(page, ", no firmware\n");
-		}
-
-		return strlen(page);
-	}
-
-	return 0;
-}
-
-static int udsl_atm_open(struct atm_vcc *vcc)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-	struct udsl_vcc_data *new;
-	unsigned int max_pdu;
-	int vci = vcc->vci;
-	short vpi = vcc->vpi;
-	int err;
-
-	dbg("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
-
-	if (!instance) {
-		dbg("udsl_atm_open: NULL data!");
-		return -ENODEV;
-	}
-
-	/* only support AAL5 */
-	if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
-	    || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
-		dbg("udsl_atm_open: unsupported ATM type %d!", vcc->qos.aal);
-		return -EINVAL;
-	}
-
-	if (instance->firmware_wait &&
-	    (err = instance->firmware_wait(instance)) < 0) {
-		dbg("udsl_atm_open: firmware not loaded (%d)!", err);
-		return err;
-	}
-
-	down(&instance->serialize);	/* vs self, udsl_atm_close */
-
-	if (udsl_find_vcc(instance, vpi, vci)) {
-		dbg("udsl_atm_open: %hd/%d already in use!", vpi, vci);
-		up(&instance->serialize);
-		return -EADDRINUSE;
-	}
-
-	if (!(new = kmalloc(sizeof(struct udsl_vcc_data), GFP_KERNEL))) {
-		dbg("udsl_atm_open: no memory for vcc_data!");
-		up(&instance->serialize);
-		return -ENOMEM;
-	}
-
-	memset(new, 0, sizeof(struct udsl_vcc_data));
-	new->vcc = vcc;
-	new->vpi = vpi;
-	new->vci = vci;
-
-	/* udsl_extract_cells requires at least one cell */
-	max_pdu = max(1, UDSL_NUM_CELLS(vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
-	if (!(new->sarb = alloc_skb(max_pdu, GFP_KERNEL))) {
-		dbg("udsl_atm_open: no memory for SAR buffer!");
-		kfree(new);
-		up(&instance->serialize);
-		return -ENOMEM;
-	}
-
-	vcc->dev_data = new;
-
-	tasklet_disable(&instance->receive_tasklet);
-	list_add(&new->list, &instance->vcc_list);
-	tasklet_enable(&instance->receive_tasklet);
-
-	set_bit(ATM_VF_ADDR, &vcc->flags);
-	set_bit(ATM_VF_PARTIAL, &vcc->flags);
-	set_bit(ATM_VF_READY, &vcc->flags);
-
-	up(&instance->serialize);
-
-	tasklet_schedule(&instance->receive_tasklet);
-
-	dbg("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, max_pdu);
-
-	return 0;
-}
-
-static void udsl_atm_close(struct atm_vcc *vcc)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-	struct udsl_vcc_data *vcc_data = vcc->dev_data;
-
-	dbg("udsl_atm_close called");
-
-	if (!instance || !vcc_data) {
-		dbg("udsl_atm_close: NULL data!");
-		return;
-	}
-
-	dbg("udsl_atm_close: deallocating vcc 0x%p with vpi %d vci %d",
-	    vcc_data, vcc_data->vpi, vcc_data->vci);
-
-	udsl_cancel_send(instance, vcc);
-
-	down(&instance->serialize);	/* vs self, udsl_atm_open */
-
-	tasklet_disable(&instance->receive_tasklet);
-	list_del(&vcc_data->list);
-	tasklet_enable(&instance->receive_tasklet);
-
-	kfree_skb(vcc_data->sarb);
-	vcc_data->sarb = NULL;
-
-	kfree(vcc_data);
-	vcc->dev_data = NULL;
-
-	vcc->vpi = ATM_VPI_UNSPEC;
-	vcc->vci = ATM_VCI_UNSPEC;
-	clear_bit(ATM_VF_READY, &vcc->flags);
-	clear_bit(ATM_VF_PARTIAL, &vcc->flags);
-	clear_bit(ATM_VF_ADDR, &vcc->flags);
-
-	up(&instance->serialize);
-
-	dbg("udsl_atm_close successful");
-}
-
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
-			  void __user * arg)
-{
-	switch (cmd) {
-	case ATM_QUERYLOOP:
-		return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
-/**********
-**  USB  **
-**********/
-
-int udsl_instance_setup(struct usb_device *dev,
-			struct udsl_instance_data *instance)
-{
-	char *buf;
-	int i, length;
-
-	kref_init(&instance->refcount);	/* one for USB */
-	udsl_get_instance(instance);	/* one for ATM */
-
-	init_MUTEX(&instance->serialize);
-
-	instance->usb_dev = dev;
-
-	INIT_LIST_HEAD(&instance->vcc_list);
-
-	instance->status = UDSL_NO_FIRMWARE;
-	init_waitqueue_head(&instance->firmware_waiters);
-
-	spin_lock_init(&instance->receive_lock);
-	INIT_LIST_HEAD(&instance->spare_receivers);
-	INIT_LIST_HEAD(&instance->filled_receive_buffers);
-
-	tasklet_init(&instance->receive_tasklet, udsl_process_receive, (unsigned long)instance);
-	INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
-	skb_queue_head_init(&instance->sndqueue);
-
-	spin_lock_init(&instance->send_lock);
-	INIT_LIST_HEAD(&instance->spare_senders);
-	INIT_LIST_HEAD(&instance->spare_send_buffers);
-
-	tasklet_init(&instance->send_tasklet, udsl_process_send,
-		     (unsigned long)instance);
-	INIT_LIST_HEAD(&instance->filled_send_buffers);
-
-	/* receive init */
-	for (i = 0; i < num_rcv_urbs; i++) {
-		struct udsl_receiver *rcv = &(instance->receivers[i]);
-
-		if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-			dbg("udsl_usb_probe: no memory for receive urb %d!", i);
-			goto fail;
-		}
-
-		rcv->instance = instance;
-
-		list_add(&rcv->list, &instance->spare_receivers);
-	}
-
-	for (i = 0; i < num_rcv_bufs; i++) {
-		struct udsl_receive_buffer *buf =
-		    &(instance->receive_buffers[i]);
-
-		buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
-				    GFP_KERNEL);
-		if (!buf->base) {
-			dbg("udsl_usb_probe: no memory for receive buffer %d!", i);
-			goto fail;
-		}
-
-		list_add(&buf->list, &instance->spare_receive_buffers);
-	}
-
-	/* send init */
-	for (i = 0; i < num_snd_urbs; i++) {
-		struct udsl_sender *snd = &(instance->senders[i]);
-
-		if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
-			dbg("udsl_usb_probe: no memory for send urb %d!", i);
-			goto fail;
-		}
-
-		snd->instance = instance;
-
-		list_add(&snd->list, &instance->spare_senders);
-	}
-
-	for (i = 0; i < num_snd_bufs; i++) {
-		struct udsl_send_buffer *buf = &(instance->send_buffers[i]);
-
-		buf->base = kmalloc(snd_buf_size * (ATM_CELL_SIZE + instance->snd_padding),
-				    GFP_KERNEL);
-		if (!buf->base) {
-			dbg("udsl_usb_probe: no memory for send buffer %d!", i);
-			goto fail;
-		}
-
-		list_add(&buf->list, &instance->spare_send_buffers);
-	}
-
-	/* ATM init */
-	instance->atm_dev = atm_dev_register(instance->driver_name,
-					     &udsl_atm_devops, -1, NULL);
-	if (!instance->atm_dev) {
-		dbg("udsl_usb_probe: failed to register ATM device!");
-		goto fail;
-	}
-
-	instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
-	instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
-	instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-
-	/* temp init ATM device, set to 128kbit */
-	instance->atm_dev->link_rate = 128 * 1000 / 424;
-
-	/* device description */
-	buf = instance->description;
-	length = sizeof(instance->description);
-
-	if ((i = usb_string(dev, dev->descriptor.iProduct, buf, length)) < 0)
-		goto finish;
-
-	buf += i;
-	length -= i;
-
-	i = scnprintf(buf, length, " (");
-	buf += i;
-	length -= i;
-
-	if (length <= 0 || (i = usb_make_path(dev, buf, length)) < 0)
-		goto finish;
-
-	buf += i;
-	length -= i;
-
-	snprintf(buf, length, ")");
-
- finish:
-	/* ready for ATM callbacks */
-	wmb();
-	instance->atm_dev->dev_data = instance;
-
-	usb_get_dev(dev);
-
-	return 0;
-
- fail:
-	for (i = 0; i < num_snd_bufs; i++)
-		kfree(instance->send_buffers[i].base);
-
-	for (i = 0; i < num_snd_urbs; i++)
-		usb_free_urb(instance->senders[i].urb);
-
-	for (i = 0; i < num_rcv_bufs; i++)
-		kfree(instance->receive_buffers[i].base);
-
-	for (i = 0; i < num_rcv_urbs; i++)
-		usb_free_urb(instance->receivers[i].urb);
-
-	return -ENOMEM;
-}
-
-void udsl_instance_disconnect(struct udsl_instance_data *instance)
-{
-	int i;
-
-	dbg("udsl_instance_disconnect entered");
-
-	if (!instance) {
-		dbg("udsl_instance_disconnect: NULL instance!");
-		return;
-	}
-
-	/* receive finalize */
-	tasklet_disable(&instance->receive_tasklet);
-
-	for (i = 0; i < num_rcv_urbs; i++)
-		usb_kill_urb(instance->receivers[i].urb);
-
-	/* no need to take the spinlock */
-	INIT_LIST_HEAD(&instance->filled_receive_buffers);
-	INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
-	tasklet_enable(&instance->receive_tasklet);
-
-	for (i = 0; i < num_rcv_urbs; i++)
-		usb_free_urb(instance->receivers[i].urb);
-
-	for (i = 0; i < num_rcv_bufs; i++)
-		kfree(instance->receive_buffers[i].base);
-
-	/* send finalize */
-	tasklet_disable(&instance->send_tasklet);
-
-	for (i = 0; i < num_snd_urbs; i++)
-		usb_kill_urb(instance->senders[i].urb);
-
-	/* no need to take the spinlock */
-	INIT_LIST_HEAD(&instance->spare_senders);
-	INIT_LIST_HEAD(&instance->spare_send_buffers);
-	instance->current_buffer = NULL;
-
-	tasklet_enable(&instance->send_tasklet);
-
-	for (i = 0; i < num_snd_urbs; i++)
-		usb_free_urb(instance->senders[i].urb);
-
-	for (i = 0; i < num_snd_bufs; i++)
-		kfree(instance->send_buffers[i].base);
-
-	/* ATM finalize */
-	shutdown_atm_dev(instance->atm_dev);
-}
-
-EXPORT_SYMBOL_GPL(udsl_get_instance);
-EXPORT_SYMBOL_GPL(udsl_put_instance);
-EXPORT_SYMBOL_GPL(udsl_instance_setup);
-EXPORT_SYMBOL_GPL(udsl_instance_disconnect);
-
-/***********
-**  init  **
-***********/
-
-static int __init udsl_usb_init(void)
-{
-	dbg("udsl_usb_init: driver version " DRIVER_VERSION);
-
-	if (sizeof(struct udsl_control) > sizeof(((struct sk_buff *) 0)->cb)) {
-		printk(KERN_ERR __FILE__ ": unusable with this kernel!\n");
-		return -EIO;
-	}
-
-	if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
-	    || (num_snd_urbs > UDSL_MAX_SND_URBS)
-	    || (num_rcv_bufs > UDSL_MAX_RCV_BUFS)
-	    || (num_snd_bufs > UDSL_MAX_SND_BUFS)
-	    || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
-	    || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
-		return -EINVAL;
-
-	return 0;
-}
-
-static void __exit udsl_usb_exit(void)
-{
-}
-
-module_init(udsl_usb_init);
-module_exit(udsl_usb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
-/************
-**  debug  **
-************/
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len)
-{
-	unsigned char buffer[256];
-	int i = 0, j = 0;
-
-	for (i = 0; i < len;) {
-		buffer[0] = '\0';
-		sprintf(buffer, "%.3d :", i);
-		for (j = 0; (j < 16) && (i < len); j++, i++) {
-			sprintf(buffer, "%s %2.2x", buffer, data[i]);
-		}
-		dbg("%s", buffer);
-	}
-	return i;
-}
-#endif
diff --git a/drivers/usb/atm/usb_atm.h b/drivers/usb/atm/usb_atm.h
deleted file mode 100644
index cf8c532..0000000
--- a/drivers/usb/atm/usb_atm.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/******************************************************************************
- *  usb_atm.h - Generic USB xDSL driver core
- *
- *  Copyright (C) 2001, Alcatel
- *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- *  Copyright (C) 2004, David Woodhouse
- *
- *  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 <linux/config.h>
-#include <linux/list.h>
-#include <linux/kref.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <asm/semaphore.h>
-
-/*
-#define DEBUG
-#define VERBOSE_DEBUG
-*/
-
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-#	define DEBUG
-#endif
-
-#include <linux/usb.h>
-
-#ifdef DEBUG
-#define UDSL_ASSERT(x)	BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(x)	do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0)
-#endif
-
-#define UDSL_MAX_RCV_URBS		4
-#define UDSL_MAX_SND_URBS		4
-#define UDSL_MAX_RCV_BUFS		8
-#define UDSL_MAX_SND_BUFS		8
-#define UDSL_MAX_RCV_BUF_SIZE		1024	/* ATM cells */
-#define UDSL_MAX_SND_BUF_SIZE		1024	/* ATM cells */
-#define UDSL_DEFAULT_RCV_URBS		2
-#define UDSL_DEFAULT_SND_URBS		2
-#define UDSL_DEFAULT_RCV_BUFS		4
-#define UDSL_DEFAULT_SND_BUFS		4
-#define UDSL_DEFAULT_RCV_BUF_SIZE	64	/* ATM cells */
-#define UDSL_DEFAULT_SND_BUF_SIZE	64	/* ATM cells */
-
-#define ATM_CELL_HEADER			(ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-#define UDSL_NUM_CELLS(x)		(((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
-
-/* receive */
-
-struct udsl_receive_buffer {
-	struct list_head list;
-	unsigned char *base;
-	unsigned int filled_cells;
-};
-
-struct udsl_receiver {
-	struct list_head list;
-	struct udsl_receive_buffer *buffer;
-	struct urb *urb;
-	struct udsl_instance_data *instance;
-};
-
-struct udsl_vcc_data {
-	/* vpi/vci lookup */
-	struct list_head list;
-	short vpi;
-	int vci;
-	struct atm_vcc *vcc;
-
-	/* raw cell reassembly */
-	struct sk_buff *sarb;
-};
-
-/* send */
-
-struct udsl_send_buffer {
-	struct list_head list;
-	unsigned char *base;
-	unsigned char *free_start;
-	unsigned int free_cells;
-};
-
-struct udsl_sender {
-	struct list_head list;
-	struct udsl_send_buffer *buffer;
-	struct urb *urb;
-	struct udsl_instance_data *instance;
-};
-
-struct udsl_control {
-	struct atm_skb_data atm_data;
-	unsigned int num_cells;
-	unsigned int num_entire;
-	unsigned int pdu_padding;
-	unsigned char aal5_trailer[ATM_AAL5_TRAILER];
-};
-
-#define UDSL_SKB(x)		((struct udsl_control *)(x)->cb)
-
-/* main driver data */
-
-enum udsl_status {
-	UDSL_NO_FIRMWARE,
-	UDSL_LOADING_FIRMWARE,
-	UDSL_LOADED_FIRMWARE
-};
-
-struct udsl_instance_data {
-	struct kref refcount;
-	struct semaphore serialize;
-
-	/* USB device part */
-	struct usb_device *usb_dev;
-	char description[64];
-	int data_endpoint;
-	int snd_padding;
-	int rcv_padding;
-	const char *driver_name;
-
-	/* ATM device part */
-	struct atm_dev *atm_dev;
-	struct list_head vcc_list;
-
-	/* firmware */
-	int (*firmware_wait) (struct udsl_instance_data *);
-	enum udsl_status status;
-	wait_queue_head_t firmware_waiters;
-
-	/* receive */
-	struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
-	struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
-
-	spinlock_t receive_lock;
-	struct list_head spare_receivers;
-	struct list_head filled_receive_buffers;
-
-	struct tasklet_struct receive_tasklet;
-	struct list_head spare_receive_buffers;
-
-	/* send */
-	struct udsl_sender senders[UDSL_MAX_SND_URBS];
-	struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
-
-	struct sk_buff_head sndqueue;
-
-	spinlock_t send_lock;
-	struct list_head spare_senders;
-	struct list_head spare_send_buffers;
-
-	struct tasklet_struct send_tasklet;
-	struct sk_buff *current_skb;			/* being emptied */
-	struct udsl_send_buffer *current_buffer;	/* being filled */
-	struct list_head filled_send_buffers;
-};
-
-extern int udsl_instance_setup(struct usb_device *dev,
-			       struct udsl_instance_data *instance);
-extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
-extern void udsl_get_instance(struct udsl_instance_data *instance);
-extern void udsl_put_instance(struct udsl_instance_data *instance);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
new file mode 100644
index 0000000..bb1db19
--- /dev/null
+++ b/drivers/usb/atm/usbatm.c
@@ -0,0 +1,1230 @@
+/******************************************************************************
+ *  usbatm.c - Generic USB xDSL driver core
+ *
+ *  Copyright (C) 2001, Alcatel
+ *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ *  Copyright (C) 2004, David Woodhouse, Roman Kagan
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*
+ *  Written by Johan Verrept, Duncan Sands (duncan.sands@free.fr) and David Woodhouse
+ *
+ *  1.7+:	- See the check-in logs
+ *
+ *  1.6:	- No longer opens a connection if the firmware is not loaded
+ *  		- Added support for the speedtouch 330
+ *  		- Removed the limit on the number of devices
+ *  		- Module now autoloads on device plugin
+ *  		- Merged relevant parts of sarlib
+ *  		- Replaced the kernel thread with a tasklet
+ *  		- New packet transmission code
+ *  		- Changed proc file contents
+ *  		- Fixed all known SMP races
+ *  		- Many fixes and cleanups
+ *  		- Various fixes by Oliver Neukum (oliver@neukum.name)
+ *
+ *  1.5A:	- Version for inclusion in 2.5 series kernel
+ *		- Modifications by Richard Purdie (rpurdie@rpsys.net)
+ *		- made compatible with kernel 2.5.6 onwards by changing
+ *		usbatm_usb_send_data_context->urb to a pointer and adding code
+ *		to alloc and free it
+ *		- remove_wait_queue() added to usbatm_atm_processqueue_thread()
+ *
+ *  1.5:	- fixed memory leak when atmsar_decode_aal5 returned NULL.
+ *		(reported by stephen.robinson@zen.co.uk)
+ *
+ *  1.4:	- changed the spin_lock() under interrupt to spin_lock_irqsave()
+ *		- unlink all active send urbs of a vcc that is being closed.
+ *
+ *  1.3.1:	- added the version number
+ *
+ *  1.3:	- Added multiple send urb support
+ *		- fixed memory leak and vcc->tx_inuse starvation bug
+ *		  when not enough memory left in vcc.
+ *
+ *  1.2:	- Fixed race condition in usbatm_usb_send_data()
+ *  1.1:	- Turned off packet debugging
+ *
+ */
+
+#include "usbatm.h"
+
+#include <asm/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len);
+#define PACKETDEBUG(arg...)	usbatm_print_packet (arg)
+#define vdbg(arg...)		dbg (arg)
+#else
+#define PACKETDEBUG(arg...)
+#define vdbg(arg...)
+#endif
+
+#define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
+#define DRIVER_VERSION	"1.9"
+#define DRIVER_DESC	"Generic USB ATM/DSL I/O, version " DRIVER_VERSION
+
+static const char usbatm_driver_name[] = "usbatm";
+
+#define UDSL_MAX_RCV_URBS		16
+#define UDSL_MAX_SND_URBS		16
+#define UDSL_MAX_RCV_BUF_SIZE		1024	/* ATM cells */
+#define UDSL_MAX_SND_BUF_SIZE		1024	/* ATM cells */
+#define UDSL_DEFAULT_RCV_URBS		4
+#define UDSL_DEFAULT_SND_URBS		4
+#define UDSL_DEFAULT_RCV_BUF_SIZE	64	/* ATM cells */
+#define UDSL_DEFAULT_SND_BUF_SIZE	64	/* ATM cells */
+
+#define ATM_CELL_HEADER			(ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
+
+#define THROTTLE_MSECS			100	/* delay to recover processing after urb submission fails */
+
+static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
+static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
+static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
+static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
+
+module_param(num_rcv_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_rcv_urbs,
+		 "Number of urbs used for reception (range: 0-"
+		 __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
+		 __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
+
+module_param(num_snd_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_snd_urbs,
+		 "Number of urbs used for transmission (range: 0-"
+		 __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
+		 __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
+
+module_param(rcv_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(rcv_buf_size,
+		 "Size of the buffers used for reception in ATM cells (range: 1-"
+		 __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
+		 __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
+
+module_param(snd_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(snd_buf_size,
+		 "Size of the buffers used for transmission in ATM cells (range: 1-"
+		 __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
+		 __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
+
+
+/* receive */
+
+struct usbatm_vcc_data {
+	/* vpi/vci lookup */
+	struct list_head list;
+	short vpi;
+	int vci;
+	struct atm_vcc *vcc;
+
+	/* raw cell reassembly */
+	struct sk_buff *sarb;
+};
+
+
+/* send */
+
+struct usbatm_control {
+	struct atm_skb_data atm;
+	u32 len;
+	u32 crc;
+};
+
+#define UDSL_SKB(x)		((struct usbatm_control *)(x)->cb)
+
+
+/* ATM */
+
+static void usbatm_atm_dev_close(struct atm_dev *dev);
+static int usbatm_atm_open(struct atm_vcc *vcc);
+static void usbatm_atm_close(struct atm_vcc *vcc);
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
+
+static struct atmdev_ops usbatm_atm_devops = {
+	.dev_close	= usbatm_atm_dev_close,
+	.open		= usbatm_atm_open,
+	.close		= usbatm_atm_close,
+	.ioctl		= usbatm_atm_ioctl,
+	.send		= usbatm_atm_send,
+	.proc_read	= usbatm_atm_proc_read,
+	.owner		= THIS_MODULE,
+};
+
+
+/***********
+**  misc  **
+***********/
+
+static inline unsigned int usbatm_pdu_length(unsigned int length)
+{
+	length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER;
+	return length - length % ATM_CELL_PAYLOAD;
+}
+
+static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	if (vcc->pop)
+		vcc->pop(vcc, skb);
+	else
+		dev_kfree_skb(skb);
+}
+
+
+/***********
+**  urbs  **
+************/
+
+static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
+{
+	struct urb *urb;
+
+	spin_lock_irq(&channel->lock);
+	if (list_empty(&channel->list)) {
+		spin_unlock_irq(&channel->lock);
+		return NULL;
+	}
+
+	urb = list_entry(channel->list.next, struct urb, urb_list);
+	list_del(&urb->urb_list);
+	spin_unlock_irq(&channel->lock);
+
+	return urb;
+}
+
+static inline int usbatm_submit_urb(struct urb *urb)
+{
+	struct usbatm_channel *channel = urb->context;
+	int ret;
+
+	vdbg("%s: submitting urb 0x%p, size %u",
+	     __func__, urb, urb->transfer_buffer_length);
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		atm_dbg(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n",
+			__func__, urb, ret);
+
+		/* consider all errors transient and return the buffer back to the queue */
+		urb->status = -EAGAIN;
+		spin_lock_irq(&channel->lock);
+
+		/* must add to the front when sending; doesn't matter when receiving */
+		list_add(&urb->urb_list, &channel->list);
+
+		spin_unlock_irq(&channel->lock);
+
+		/* make sure the channel doesn't stall */
+		mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+	}
+
+	return ret;
+}
+
+static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
+{
+	struct usbatm_channel *channel = urb->context;
+	unsigned long flags;
+
+	vdbg("%s: urb 0x%p, status %d, actual_length %d",
+	     __func__, urb, urb->status, urb->actual_length);
+
+	/* usually in_interrupt(), but not always */
+	spin_lock_irqsave(&channel->lock, flags);
+
+	/* must add to the back when receiving; doesn't matter when sending */
+	list_add_tail(&urb->urb_list, &channel->list);
+
+	spin_unlock_irqrestore(&channel->lock, flags);
+
+	if (unlikely(urb->status))
+		/* throttle processing in case of an error */
+		mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+	else
+		tasklet_schedule(&channel->tasklet);
+}
+
+
+/*************
+**  decode  **
+*************/
+
+static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance,
+						  short vpi, int vci)
+{
+	struct usbatm_vcc_data *vcc;
+
+	list_for_each_entry(vcc, &instance->vcc_list, list)
+		if ((vcc->vci == vci) && (vcc->vpi == vpi))
+			return vcc;
+	return NULL;
+}
+
+static void usbatm_extract_cells(struct usbatm_data *instance,
+			       unsigned char *source, unsigned int avail_data)
+{
+	struct usbatm_vcc_data *cached_vcc = NULL;
+	struct atm_vcc *vcc;
+	struct sk_buff *sarb;
+	unsigned int stride = instance->rx_channel.stride;
+	int vci, cached_vci = 0;
+	short vpi, cached_vpi = 0;
+	u8 pti;
+
+	for (; avail_data >= stride; avail_data -= stride, source += stride) {
+		vpi = ((source[0] & 0x0f) << 4)  | (source[1] >> 4);
+		vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
+		pti = ((source[3] & 0xe) >> 1);
+
+		vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
+
+		if ((vci != cached_vci) || (vpi != cached_vpi)) {
+			cached_vpi = vpi;
+			cached_vci = vci;
+
+			cached_vcc = usbatm_find_vcc(instance, vpi, vci);
+
+			if (!cached_vcc)
+				atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
+		}
+
+		if (!cached_vcc)
+			continue;
+
+		vcc = cached_vcc->vcc;
+
+		/* OAM F5 end-to-end */
+		if (pti == ATM_PTI_E2EF5) {
+			atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci);
+			atomic_inc(&vcc->stats->rx_err);
+			continue;
+		}
+
+		sarb = cached_vcc->sarb;
+
+		if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
+			atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
+					__func__, sarb->len, vcc);
+			/* discard cells already received */
+			skb_trim(sarb, 0);
+			UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
+		}
+
+		memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+		__skb_put(sarb, ATM_CELL_PAYLOAD);
+
+		if (pti & 1) {
+			struct sk_buff *skb;
+			unsigned int length;
+			unsigned int pdu_length;
+
+			length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
+
+			/* guard against overflow */
+			if (length > ATM_MAX_AAL5_PDU) {
+				atm_dbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
+						__func__, length, vcc);
+				atomic_inc(&vcc->stats->rx_err);
+				goto out;
+			}
+
+			pdu_length = usbatm_pdu_length(length);
+
+			if (sarb->len < pdu_length) {
+				atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
+						__func__, pdu_length, sarb->len, vcc);
+				atomic_inc(&vcc->stats->rx_err);
+				goto out;
+			}
+
+			if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+				atm_dbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
+						__func__, vcc);
+				atomic_inc(&vcc->stats->rx_err);
+				goto out;
+			}
+
+			vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
+
+			if (!(skb = dev_alloc_skb(length))) {
+				atm_dbg(instance, "%s: no memory for skb (length: %u)!\n", __func__, length);
+				atomic_inc(&vcc->stats->rx_drop);
+				goto out;
+			}
+
+			vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
+
+			if (!atm_charge(vcc, skb->truesize)) {
+				atm_dbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", __func__, skb->truesize);
+				dev_kfree_skb(skb);
+				goto out;	/* atm_charge increments rx_drop */
+			}
+
+			memcpy(skb->data, sarb->tail - pdu_length, length);
+			__skb_put(skb, length);
+
+			vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
+			     __func__, skb, skb->len, skb->truesize);
+
+			PACKETDEBUG(skb->data, skb->len);
+
+			vcc->push(vcc, skb);
+
+			atomic_inc(&vcc->stats->rx);
+		out:
+			skb_trim(sarb, 0);
+		}
+	}
+}
+
+
+/*************
+**  encode  **
+*************/
+
+static unsigned int usbatm_write_cells(struct usbatm_data *instance,
+				       struct sk_buff *skb,
+				       u8 *target, unsigned int avail_space)
+{
+	struct usbatm_control *ctrl = UDSL_SKB(skb);
+	struct atm_vcc *vcc = ctrl->atm.vcc;
+	unsigned int num_written;
+	unsigned int stride = instance->tx_channel.stride;
+
+	vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
+	UDSL_ASSERT(!(avail_space % stride));
+
+	for (num_written = 0; num_written < avail_space && ctrl->len;
+	     num_written += stride, target += stride) {
+		unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
+		unsigned int left = ATM_CELL_PAYLOAD - data_len;
+		u8 *ptr = target;
+
+		ptr[0] = vcc->vpi >> 4;
+		ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+		ptr[2] = vcc->vci >> 4;
+		ptr[3] = vcc->vci << 4;
+		ptr[4] = 0xec;
+		ptr += ATM_CELL_HEADER;
+
+		memcpy(ptr, skb->data, data_len);
+		ptr += data_len;
+		__skb_pull(skb, data_len);
+
+		if(!left)
+			continue;
+
+		memset(ptr, 0, left);
+
+		if (left >= ATM_AAL5_TRAILER) {	/* trailer will go in this cell */
+			u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER;
+			/* trailer[0] = 0;		UU = 0 */
+			/* trailer[1] = 0;		CPI = 0 */
+			trailer[2] = ctrl->len >> 8;
+			trailer[3] = ctrl->len;
+
+			ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);
+
+			trailer[4] = ctrl->crc >> 24;
+			trailer[5] = ctrl->crc >> 16;
+			trailer[6] = ctrl->crc >> 8;
+			trailer[7] = ctrl->crc;
+
+			target[3] |= 0x2;	/* adjust PTI */
+
+			ctrl->len = 0;		/* tag this skb finished */
+		}
+		else
+			ctrl->crc = crc32_be(ctrl->crc, ptr, left);
+	}
+
+	return num_written;
+}
+
+
+/**************
+**  receive  **
+**************/
+
+static void usbatm_rx_process(unsigned long data)
+{
+	struct usbatm_data *instance = (struct usbatm_data *)data;
+	struct urb *urb;
+
+	while ((urb = usbatm_pop_urb(&instance->rx_channel))) {
+		vdbg("%s: processing urb 0x%p", __func__, urb);
+
+		if (usb_pipeisoc(urb->pipe)) {
+			int i;
+			for (i = 0; i < urb->number_of_packets; i++)
+				if (!urb->iso_frame_desc[i].status)
+					usbatm_extract_cells(instance,
+							     (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+							     urb->iso_frame_desc[i].actual_length);
+		}
+		else
+			if (!urb->status)
+				usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);
+
+		if (usbatm_submit_urb(urb))
+			return;
+	}
+}
+
+
+/***********
+**  send  **
+***********/
+
+static void usbatm_tx_process(unsigned long data)
+{
+	struct usbatm_data *instance = (struct usbatm_data *)data;
+	struct sk_buff *skb = instance->current_skb;
+	struct urb *urb = NULL;
+	const unsigned int buf_size = instance->tx_channel.buf_size;
+	unsigned int num_written = 0;
+	u8 *buffer = NULL;
+
+	if (!skb)
+		skb = skb_dequeue(&instance->sndqueue);
+
+	while (skb) {
+		if (!urb) {
+			urb = usbatm_pop_urb(&instance->tx_channel);
+			if (!urb)
+				break;		/* no more senders */
+			buffer = urb->transfer_buffer;
+			num_written = (urb->status == -EAGAIN) ?
+				urb->transfer_buffer_length : 0;
+		}
+
+		num_written += usbatm_write_cells(instance, skb,
+						  buffer + num_written,
+						  buf_size - num_written);
+
+		vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",
+		     __func__, num_written, skb, urb);
+
+		if (!UDSL_SKB(skb)->len) {
+			struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc;
+
+			usbatm_pop(vcc, skb);
+			atomic_inc(&vcc->stats->tx);
+
+			skb = skb_dequeue(&instance->sndqueue);
+		}
+
+		if (num_written == buf_size || (!skb && num_written)) {
+			urb->transfer_buffer_length = num_written;
+
+			if (usbatm_submit_urb(urb))
+				break;
+			urb = NULL;
+		}
+	}
+
+	instance->current_skb = skb;
+}
+
+static void usbatm_cancel_send(struct usbatm_data *instance,
+			       struct atm_vcc *vcc)
+{
+	struct sk_buff *skb, *n;
+
+	atm_dbg(instance, "%s entered\n", __func__);
+	spin_lock_irq(&instance->sndqueue.lock);
+	for (skb = instance->sndqueue.next, n = skb->next;
+	     skb != (struct sk_buff *)&instance->sndqueue;
+	     skb = n, n = skb->next)
+		if (UDSL_SKB(skb)->atm.vcc == vcc) {
+			atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);
+			__skb_unlink(skb, &instance->sndqueue);
+			usbatm_pop(vcc, skb);
+		}
+	spin_unlock_irq(&instance->sndqueue.lock);
+
+	tasklet_disable(&instance->tx_channel.tasklet);
+	if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) {
+		atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb);
+		instance->current_skb = NULL;
+		usbatm_pop(vcc, skb);
+	}
+	tasklet_enable(&instance->tx_channel.tasklet);
+	atm_dbg(instance, "%s done\n", __func__);
+}
+
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	struct usbatm_data *instance = vcc->dev->dev_data;
+	struct usbatm_control *ctrl = UDSL_SKB(skb);
+	int err;
+
+	vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
+
+	if (!instance) {
+		dbg("%s: NULL data!", __func__);
+		err = -ENODEV;
+		goto fail;
+	}
+
+	if (vcc->qos.aal != ATM_AAL5) {
+		atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+		err = -EINVAL;
+		goto fail;
+	}
+
+	if (skb->len > ATM_MAX_AAL5_PDU) {
+		atm_dbg(instance, "%s: packet too long (%d vs %d)!\n",
+				__func__, skb->len, ATM_MAX_AAL5_PDU);
+		err = -EINVAL;
+		goto fail;
+	}
+
+	PACKETDEBUG(skb->data, skb->len);
+
+	/* initialize the control block */
+	ctrl->atm.vcc = vcc;
+	ctrl->len = skb->len;
+	ctrl->crc = crc32_be(~0, skb->data, skb->len);
+
+	skb_queue_tail(&instance->sndqueue, skb);
+	tasklet_schedule(&instance->tx_channel.tasklet);
+
+	return 0;
+
+ fail:
+	usbatm_pop(vcc, skb);
+	return err;
+}
+
+
+/********************
+**  bean counting  **
+********************/
+
+static void usbatm_destroy_instance(struct kref *kref)
+{
+	struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
+
+	dbg("%s", __func__);
+
+	tasklet_kill(&instance->rx_channel.tasklet);
+	tasklet_kill(&instance->tx_channel.tasklet);
+	usb_put_dev(instance->usb_dev);
+	kfree(instance);
+}
+
+void usbatm_get_instance(struct usbatm_data *instance)
+{
+	dbg("%s", __func__);
+
+	kref_get(&instance->refcount);
+}
+
+void usbatm_put_instance(struct usbatm_data *instance)
+{
+	dbg("%s", __func__);
+
+	kref_put(&instance->refcount, usbatm_destroy_instance);
+}
+
+
+/**********
+**  ATM  **
+**********/
+
+static void usbatm_atm_dev_close(struct atm_dev *dev)
+{
+	struct usbatm_data *instance = dev->dev_data;
+
+	dbg("%s", __func__);
+
+	if (!instance)
+		return;
+
+	dev->dev_data = NULL;
+	usbatm_put_instance(instance);	/* taken in usbatm_atm_init */
+}
+
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
+{
+	struct usbatm_data *instance = atm_dev->dev_data;
+	int left = *pos;
+
+	if (!instance) {
+		dbg("%s: NULL instance!", __func__);
+		return -ENODEV;
+	}
+
+	if (!left--)
+		return sprintf(page, "%s\n", instance->description);
+
+	if (!left--)
+		return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+			       atm_dev->esi[0], atm_dev->esi[1],
+			       atm_dev->esi[2], atm_dev->esi[3],
+			       atm_dev->esi[4], atm_dev->esi[5]);
+
+	if (!left--)
+		return sprintf(page,
+			       "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+			       atomic_read(&atm_dev->stats.aal5.tx),
+			       atomic_read(&atm_dev->stats.aal5.tx_err),
+			       atomic_read(&atm_dev->stats.aal5.rx),
+			       atomic_read(&atm_dev->stats.aal5.rx_err),
+			       atomic_read(&atm_dev->stats.aal5.rx_drop));
+
+	if (!left--)
+		switch (atm_dev->signal) {
+		case ATM_PHY_SIG_FOUND:
+			return sprintf(page, "Line up\n");
+		case ATM_PHY_SIG_LOST:
+			return sprintf(page, "Line down\n");
+		default:
+			return sprintf(page, "Line state unknown\n");
+		}
+
+	return 0;
+}
+
+static int usbatm_atm_open(struct atm_vcc *vcc)
+{
+	struct usbatm_data *instance = vcc->dev->dev_data;
+	struct usbatm_vcc_data *new = NULL;
+	int ret;
+	int vci = vcc->vci;
+	short vpi = vcc->vpi;
+
+	if (!instance) {
+		dbg("%s: NULL data!", __func__);
+		return -ENODEV;
+	}
+
+	atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
+
+	/* only support AAL5 */
+	if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
+	    || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
+		atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+		return -EINVAL;
+	}
+
+	down(&instance->serialize);	/* vs self, usbatm_atm_close */
+
+	if (usbatm_find_vcc(instance, vpi, vci)) {
+		atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);
+		ret = -EADDRINUSE;
+		goto fail;
+	}
+
+	if (!(new = kmalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
+		atm_dbg(instance, "%s: no memory for vcc_data!\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	memset(new, 0, sizeof(struct usbatm_vcc_data));
+	new->vcc = vcc;
+	new->vpi = vpi;
+	new->vci = vci;
+
+	new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);
+	if (!new->sarb) {
+		atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	vcc->dev_data = new;
+
+	tasklet_disable(&instance->rx_channel.tasklet);
+	list_add(&new->list, &instance->vcc_list);
+	tasklet_enable(&instance->rx_channel.tasklet);
+
+	set_bit(ATM_VF_ADDR, &vcc->flags);
+	set_bit(ATM_VF_PARTIAL, &vcc->flags);
+	set_bit(ATM_VF_READY, &vcc->flags);
+
+	up(&instance->serialize);
+
+	atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);
+
+	return 0;
+
+fail:
+	kfree(new);
+	up(&instance->serialize);
+	return ret;
+}
+
+static void usbatm_atm_close(struct atm_vcc *vcc)
+{
+	struct usbatm_data *instance = vcc->dev->dev_data;
+	struct usbatm_vcc_data *vcc_data = vcc->dev_data;
+
+	if (!instance || !vcc_data) {
+		dbg("%s: NULL data!", __func__);
+		return;
+	}
+
+	atm_dbg(instance, "%s entered\n", __func__);
+
+	atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
+		__func__, vcc_data, vcc_data->vpi, vcc_data->vci);
+
+	usbatm_cancel_send(instance, vcc);
+
+	down(&instance->serialize);	/* vs self, usbatm_atm_open */
+
+	tasklet_disable(&instance->rx_channel.tasklet);
+	list_del(&vcc_data->list);
+	tasklet_enable(&instance->rx_channel.tasklet);
+
+	kfree_skb(vcc_data->sarb);
+	vcc_data->sarb = NULL;
+
+	kfree(vcc_data);
+	vcc->dev_data = NULL;
+
+	vcc->vpi = ATM_VPI_UNSPEC;
+	vcc->vci = ATM_VCI_UNSPEC;
+	clear_bit(ATM_VF_READY, &vcc->flags);
+	clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+	clear_bit(ATM_VF_ADDR, &vcc->flags);
+
+	up(&instance->serialize);
+
+	atm_dbg(instance, "%s successful\n", __func__);
+}
+
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
+			  void __user * arg)
+{
+	switch (cmd) {
+	case ATM_QUERYLOOP:
+		return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int usbatm_atm_init(struct usbatm_data *instance)
+{
+	struct atm_dev *atm_dev;
+	int ret, i;
+
+	/* ATM init */
+	atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+	if (!atm_dev) {
+		usb_dbg(instance, "%s: failed to register ATM device!\n", __func__);
+		return -1;
+	}
+
+	instance->atm_dev = atm_dev;
+
+	atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
+	atm_dev->ci_range.vci_bits = ATM_CI_MAX;
+	atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+
+	/* temp init ATM device, set to 128kbit */
+	atm_dev->link_rate = 128 * 1000 / 424;
+
+	if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
+		atm_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret);
+		goto fail;
+	}
+
+	/* ready for ATM callbacks */
+	usbatm_get_instance(instance);	/* dropped in usbatm_atm_dev_close */
+	mb();
+	atm_dev->dev_data = instance;
+
+	/* submit all rx URBs */
+	for (i = 0; i < num_rcv_urbs; i++)
+		usbatm_submit_urb(instance->urbs[i]);
+
+	return 0;
+
+ fail:
+	instance->atm_dev = NULL;
+	shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */
+	return ret;
+}
+
+
+/**********
+**  USB  **
+**********/
+
+static int usbatm_do_heavy_init(void *arg)
+{
+	struct usbatm_data *instance = arg;
+	int ret;
+
+	daemonize(instance->driver->driver_name);
+	allow_signal(SIGTERM);
+
+	complete(&instance->thread_started);
+
+	ret = instance->driver->heavy_init(instance, instance->usb_intf);
+
+	if (!ret)
+		ret = usbatm_atm_init(instance);
+
+	down(&instance->serialize);
+	instance->thread_pid = -1;
+	up(&instance->serialize);
+
+	complete_and_exit(&instance->thread_exited, ret);
+}
+
+static int usbatm_heavy_init(struct usbatm_data *instance)
+{
+	int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+
+	if (ret < 0) {
+		usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
+		return ret;
+	}
+
+	down(&instance->serialize);
+	instance->thread_pid = ret;
+	up(&instance->serialize);
+
+	wait_for_completion(&instance->thread_started);
+
+	return 0;
+}
+
+static void usbatm_tasklet_schedule(unsigned long data)
+{
+	tasklet_schedule((struct tasklet_struct *) data);
+}
+
+static inline void usbatm_init_channel(struct usbatm_channel *channel)
+{
+	spin_lock_init(&channel->lock);
+	INIT_LIST_HEAD(&channel->list);
+	channel->delay.function = usbatm_tasklet_schedule;
+	channel->delay.data = (unsigned long) &channel->tasklet;
+	init_timer(&channel->delay);
+}
+
+int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+		     struct usbatm_driver *driver)
+{
+	struct device *dev = &intf->dev;
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct usbatm_data *instance;
+	char *buf;
+	int error = -ENOMEM;
+	int i, length;
+	int need_heavy;
+
+	dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n",
+			__func__, driver->driver_name,
+			le16_to_cpu(usb_dev->descriptor.idVendor),
+			le16_to_cpu(usb_dev->descriptor.idProduct),
+			intf->altsetting->desc.bInterfaceNumber);
+
+	/* instance init */
+	instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+	if (!instance) {
+		dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* public fields */
+
+	instance->driver = driver;
+	snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name);
+
+	instance->usb_dev = usb_dev;
+	instance->usb_intf = intf;
+
+	buf = instance->description;
+	length = sizeof(instance->description);
+
+	if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0)
+		goto bind;
+
+	buf += i;
+	length -= i;
+
+	i = scnprintf(buf, length, " (");
+	buf += i;
+	length -= i;
+
+	if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0)
+		goto bind;
+
+	buf += i;
+	length -= i;
+
+	snprintf(buf, length, ")");
+
+ bind:
+	need_heavy = 1;
+	if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) {
+			dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
+			goto fail_free;
+	}
+
+	/* private fields */
+
+	kref_init(&instance->refcount);		/* dropped in usbatm_usb_disconnect */
+	init_MUTEX(&instance->serialize);
+
+	instance->thread_pid = -1;
+	init_completion(&instance->thread_started);
+	init_completion(&instance->thread_exited);
+
+	INIT_LIST_HEAD(&instance->vcc_list);
+
+	usbatm_init_channel(&instance->rx_channel);
+	usbatm_init_channel(&instance->tx_channel);
+	tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance);
+	tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance);
+	instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
+	instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out);
+	instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding;
+	instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding;
+	instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride;
+	instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride;
+	instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance;
+
+	skb_queue_head_init(&instance->sndqueue);
+
+	for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+		struct urb *urb;
+		u8 *buffer;
+		unsigned int iso_packets = 0, iso_size = 0;
+		struct usbatm_channel *channel = i < num_rcv_urbs ?
+			&instance->rx_channel : &instance->tx_channel;
+
+		if (usb_pipeisoc(channel->endpoint)) {
+			/* don't expect iso out endpoints */
+			iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0);
+			iso_size -= iso_size % channel->stride;	/* alignment */
+			BUG_ON(!iso_size);
+			iso_packets = (channel->buf_size - 1) / iso_size + 1;
+		}
+
+		urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
+		if (!urb) {
+			dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i);
+			goto fail_unbind;
+		}
+
+		instance->urbs[i] = urb;
+
+		buffer = kmalloc(channel->buf_size, GFP_KERNEL);
+		if (!buffer) {
+			dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i);
+			goto fail_unbind;
+		}
+		memset(buffer, 0, channel->buf_size);
+
+		usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint,
+				  buffer, channel->buf_size, usbatm_complete, channel);
+		if (iso_packets) {
+			int j;
+			urb->interval = 1;
+			urb->transfer_flags = URB_ISO_ASAP;
+			urb->number_of_packets = iso_packets;
+			for (j = 0; j < iso_packets; j++) {
+				urb->iso_frame_desc[j].offset = iso_size * j;
+				urb->iso_frame_desc[j].length = min_t(int, iso_size,
+								      channel->buf_size - urb->iso_frame_desc[j].offset);
+			}
+		}
+
+		/* put all tx URBs on the list of spares */
+		if (i >= num_rcv_urbs)
+			list_add_tail(&urb->urb_list, &channel->list);
+
+		vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p",
+		     __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
+	}
+
+	if (need_heavy && driver->heavy_init) {
+		error = usbatm_heavy_init(instance);
+	} else {
+		complete(&instance->thread_exited);	/* pretend that heavy_init was run */
+		error = usbatm_atm_init(instance);
+	}
+
+	if (error < 0)
+		goto fail_unbind;
+
+	usb_get_dev(usb_dev);
+	usb_set_intfdata(intf, instance);
+
+	return 0;
+
+ fail_unbind:
+	if (instance->driver->unbind)
+		instance->driver->unbind(instance, intf);
+ fail_free:
+	for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+		if (instance->urbs[i])
+			kfree(instance->urbs[i]->transfer_buffer);
+		usb_free_urb(instance->urbs[i]);
+	}
+
+	kfree (instance);
+
+	return error;
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_probe);
+
+void usbatm_usb_disconnect(struct usb_interface *intf)
+{
+	struct device *dev = &intf->dev;
+	struct usbatm_data *instance = usb_get_intfdata(intf);
+	int i;
+
+	dev_dbg(dev, "%s entered\n", __func__);
+
+	if (!instance) {
+		dev_dbg(dev, "%s: NULL instance!\n", __func__);
+		return;
+	}
+
+	usb_set_intfdata(intf, NULL);
+
+	down(&instance->serialize);
+	if (instance->thread_pid >= 0)
+		kill_proc(instance->thread_pid, SIGTERM, 1);
+	up(&instance->serialize);
+
+	wait_for_completion(&instance->thread_exited);
+
+	tasklet_disable(&instance->rx_channel.tasklet);
+	tasklet_disable(&instance->tx_channel.tasklet);
+
+	for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++)
+		usb_kill_urb(instance->urbs[i]);
+
+	del_timer_sync(&instance->rx_channel.delay);
+	del_timer_sync(&instance->tx_channel.delay);
+
+	if (instance->atm_dev && instance->driver->atm_stop)
+		instance->driver->atm_stop(instance, instance->atm_dev);
+
+	if (instance->driver->unbind)
+		instance->driver->unbind(instance, intf);
+
+	instance->driver_data = NULL;
+
+	/* turn usbatm_[rt]x_process into noop */
+	/* no need to take the spinlock */
+	INIT_LIST_HEAD(&instance->rx_channel.list);
+	INIT_LIST_HEAD(&instance->tx_channel.list);
+
+	tasklet_enable(&instance->rx_channel.tasklet);
+	tasklet_enable(&instance->tx_channel.tasklet);
+
+	for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+		kfree(instance->urbs[i]->transfer_buffer);
+		usb_free_urb(instance->urbs[i]);
+	}
+
+	/* ATM finalize */
+	if (instance->atm_dev)
+		shutdown_atm_dev(instance->atm_dev);
+
+	usbatm_put_instance(instance);	/* taken in usbatm_usb_probe */
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
+
+
+/***********
+**  init  **
+***********/
+
+static int __init usbatm_usb_init(void)
+{
+	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
+
+	if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
+		printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
+		return -EIO;
+	}
+
+	if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
+	    || (num_snd_urbs > UDSL_MAX_SND_URBS)
+	    || (rcv_buf_size < 1)
+	    || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
+	    || (snd_buf_size < 1)
+	    || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
+		return -EINVAL;
+
+	return 0;
+}
+module_init(usbatm_usb_init);
+
+static void __exit usbatm_usb_exit(void)
+{
+	dbg("%s", __func__);
+}
+module_exit(usbatm_usb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/************
+**  debug  **
+************/
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len)
+{
+	unsigned char buffer[256];
+	int i = 0, j = 0;
+
+	for (i = 0; i < len;) {
+		buffer[0] = '\0';
+		sprintf(buffer, "%.3d :", i);
+		for (j = 0; (j < 16) && (i < len); j++, i++) {
+			sprintf(buffer, "%s %2.2x", buffer, data[i]);
+		}
+		dbg("%s", buffer);
+	}
+	return i;
+}
+#endif
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
new file mode 100644
index 0000000..9366464
--- /dev/null
+++ b/drivers/usb/atm/usbatm.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *  usbatm.h - Generic USB xDSL driver core
+ *
+ *  Copyright (C) 2001, Alcatel
+ *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ *  Copyright (C) 2004, David Woodhouse
+ *
+ *  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	_USBATM_H_
+#define	_USBATM_H_
+
+#include <linux/config.h>
+
+/*
+#define DEBUG
+#define VERBOSE_DEBUG
+*/
+
+#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
+#	define DEBUG
+#endif
+
+#include <asm/semaphore.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/stringify.h>
+#include <linux/usb.h>
+
+#ifdef DEBUG
+#define UDSL_ASSERT(x)	BUG_ON(!(x))
+#else
+#define UDSL_ASSERT(x)	do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
+#endif
+
+#define usb_err(instance, format, arg...)	\
+	dev_err(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_info(instance, format, arg...)	\
+	dev_info(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_warn(instance, format, arg...)	\
+	dev_warn(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_dbg(instance, format, arg...)	\
+	dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
+
+/* FIXME: move to dev_* once ATM is driver model aware */
+#define atm_printk(level, instance, format, arg...)	\
+	printk(level "ATM dev %d: " format ,		\
+	(instance)->atm_dev->number , ## arg)
+
+#define atm_err(instance, format, arg...)	\
+	atm_printk(KERN_ERR, instance , format , ## arg)
+#define atm_info(instance, format, arg...)	\
+	atm_printk(KERN_INFO, instance , format , ## arg)
+#define atm_warn(instance, format, arg...)	\
+	atm_printk(KERN_WARNING, instance , format , ## arg)
+#ifdef DEBUG
+#define atm_dbg(instance, format, arg...)	\
+	atm_printk(KERN_DEBUG, instance , format , ## arg)
+#else
+#define atm_dbg(instance, format, arg...)	\
+	do {} while (0)
+#endif
+
+
+/* mini driver */
+
+struct usbatm_data;
+
+/*
+*  Assuming all methods exist and succeed, they are called in this order:
+*
+*  	bind, heavy_init, atm_start, ..., atm_stop, unbind
+*/
+
+struct usbatm_driver {
+	struct module *owner;
+
+	const char *driver_name;
+
+	/*
+	*  init device ... can sleep, or cause probe() failure.  Drivers with a heavy_init
+	*  method can avoid having it called by setting need_heavy_init to zero.
+	*/
+        int (*bind) (struct usbatm_data *, struct usb_interface *,
+		     const struct usb_device_id *id, int *need_heavy_init);
+
+	/* additional device initialization that is too slow to be done in probe() */
+        int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
+
+	/* cleanup device ... can sleep, but can't fail */
+        void (*unbind) (struct usbatm_data *, struct usb_interface *);
+
+	/* init ATM device ... can sleep, or cause ATM initialization failure */
+	int (*atm_start) (struct usbatm_data *, struct atm_dev *);
+
+	/* cleanup ATM device ... can sleep, but can't fail */
+	void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
+
+        int in;		/* rx endpoint */
+        int out;	/* tx endpoint */
+
+	unsigned rx_padding;
+	unsigned tx_padding;
+};
+
+extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+		struct usbatm_driver *driver);
+extern void usbatm_usb_disconnect(struct usb_interface *intf);
+
+
+struct usbatm_channel {
+	int endpoint;			/* usb pipe */
+	unsigned int stride;		/* ATM cell size + padding */
+	unsigned int buf_size;		/* urb buffer size */
+	spinlock_t lock;
+	struct list_head list;
+	struct tasklet_struct tasklet;
+	struct timer_list delay;
+	struct usbatm_data *usbatm;
+};
+
+/* main driver data */
+
+struct usbatm_data {
+	/******************
+	*  public fields  *
+        ******************/
+
+	/* mini driver */
+	struct usbatm_driver *driver;
+	void *driver_data;
+	char driver_name[16];
+
+	/* USB device */
+	struct usb_device *usb_dev;
+	struct usb_interface *usb_intf;
+	char description[64];
+
+	/* ATM device */
+	struct atm_dev *atm_dev;
+
+	/********************************
+	*  private fields - do not use  *
+        ********************************/
+
+	struct kref refcount;
+	struct semaphore serialize;
+
+	/* heavy init */
+	int thread_pid;
+	struct completion thread_started;
+	struct completion thread_exited;
+
+	/* ATM device */
+	struct list_head vcc_list;
+
+	struct usbatm_channel rx_channel;
+	struct usbatm_channel tx_channel;
+
+	struct sk_buff_head sndqueue;
+	struct sk_buff *current_skb;			/* being emptied */
+
+	struct urb *urbs[0];
+};
+
+#endif	/* _USBATM_H_ */
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
new file mode 100644
index 0000000..7fe7fb4
--- /dev/null
+++ b/drivers/usb/atm/xusbatm.c
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *  xusbatm.c -	dumb usbatm-based driver for modems initialized in userspace
+ *
+ *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ *  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 <linux/module.h>
+#include <linux/netdevice.h>		/* FIXME: required by linux/etherdevice.h */
+#include <linux/etherdevice.h>		/* for random_ether_addr() */
+
+#include "usbatm.h"
+
+
+#define XUSBATM_DRIVERS_MAX	8
+
+#define XUSBATM_PARM(name, type, parmtype, desc) \
+	static type name[XUSBATM_DRIVERS_MAX]; \
+	static int num_##name; \
+	module_param_array(name, parmtype, &num_##name, 0444); \
+	MODULE_PARM_DESC(name, desc)
+
+XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor");
+XUSBATM_PARM(product, unsigned short, ushort, "USB device product");
+
+XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number");
+XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number");
+XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)");
+XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)");
+
+static const char xusbatm_driver_name[] = "xusbatm";
+
+static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
+static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
+static struct usb_driver xusbatm_usb_driver;
+
+static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep)
+{
+	int i, j;
+
+	for (i = 0; i < intf->num_altsetting; i++) {
+		struct usb_host_interface *alt = intf->altsetting;
+		for (j = 0; j < alt->desc.bNumEndpoints; j++)
+			if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep)
+				return 1;
+	}
+	return 0;
+}
+
+static int xusbatm_bind(struct usbatm_data *usbatm_instance,
+			struct usb_interface *intf, const struct usb_device_id *id,
+			int *need_heavy_init)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	int drv_ix = id - xusbatm_usb_ids;
+	int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]);
+	int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]);
+	u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix];
+	int i, ret;
+
+	usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x"
+		" rx: ep %#x padd %d tx: ep %#x padd %d\n",
+		__func__, drv_ix, vendor[drv_ix], product[drv_ix],
+		rx_endpoint[drv_ix], rx_padding[drv_ix],
+		tx_endpoint[drv_ix], tx_padding[drv_ix]);
+
+	if (!rx_ep_present && !tx_ep_present) {
+		usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
+			__func__, intf->altsetting->desc.bInterfaceNumber,
+			rx_endpoint[drv_ix], tx_endpoint[drv_ix]);
+		return -ENODEV;
+	}
+
+	if (rx_ep_present && tx_ep_present)
+		return 0;
+
+	for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+		struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+
+		if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) {
+			ret = usb_driver_claim_interface(&xusbatm_usb_driver,
+							 cur_if, usbatm_instance);
+			if (!ret)
+				usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n",
+					__func__, cur_if->altsetting->desc.bInterfaceNumber, ret);
+			return ret;
+		}
+	}
+
+	usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n",
+		__func__, searched_ep);
+	return -ENODEV;
+}
+
+static void xusbatm_unbind(struct usbatm_data *usbatm_instance,
+			   struct usb_interface *intf)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	int i;
+	usb_dbg(usbatm_instance, "%s entered\n", __func__);
+
+	for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+		struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+		usb_set_intfdata(cur_if, NULL);
+		usb_driver_release_interface(&xusbatm_usb_driver, cur_if);
+	}
+}
+
+static int xusbatm_atm_start(struct usbatm_data *usbatm_instance,
+			     struct atm_dev *atm_dev)
+{
+	atm_dbg(usbatm_instance, "%s entered\n", __func__);
+
+	/* use random MAC as we've no way to get it from the device */
+	random_ether_addr(atm_dev->esi);
+
+	return 0;
+}
+
+
+static int xusbatm_usb_probe(struct usb_interface *intf,
+			     const struct usb_device_id *id)
+{
+	return usbatm_usb_probe(intf, id,
+				xusbatm_drivers + (id - xusbatm_usb_ids));
+}
+
+static struct usb_driver xusbatm_usb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= xusbatm_driver_name,
+	.probe		= xusbatm_usb_probe,
+	.disconnect	= usbatm_usb_disconnect,
+	.id_table	= xusbatm_usb_ids
+};
+
+static int __init xusbatm_init(void)
+{
+	int i;
+
+	dbg("xusbatm_init");
+
+	if (!num_vendor ||
+	    num_vendor != num_product ||
+	    num_vendor != num_rx_endpoint ||
+	    num_vendor != num_tx_endpoint) {
+		warn("malformed module parameters");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_vendor; i++) {
+		xusbatm_usb_ids[i].match_flags	= USB_DEVICE_ID_MATCH_DEVICE;
+		xusbatm_usb_ids[i].idVendor	= vendor[i];
+		xusbatm_usb_ids[i].idProduct	= product[i];
+
+
+		xusbatm_drivers[i].owner	= THIS_MODULE;
+		xusbatm_drivers[i].driver_name	= xusbatm_driver_name;
+		xusbatm_drivers[i].bind		= xusbatm_bind;
+		xusbatm_drivers[i].unbind	= xusbatm_unbind;
+		xusbatm_drivers[i].atm_start	= xusbatm_atm_start;
+		xusbatm_drivers[i].in		= rx_endpoint[i];
+		xusbatm_drivers[i].out		= tx_endpoint[i];
+		xusbatm_drivers[i].rx_padding	= rx_padding[i];
+		xusbatm_drivers[i].tx_padding	= tx_padding[i];
+	}
+
+	return usb_register(&xusbatm_usb_driver);
+}
+module_init(xusbatm_init);
+
+static void __exit xusbatm_exit(void)
+{
+	dbg("xusbatm_exit entered");
+
+	usb_deregister(&xusbatm_usb_driver);
+}
+module_exit(xusbatm_exit);
+
+MODULE_AUTHOR("Roman Kagan, Duncan Sands");
+MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 6d1f9b6..69e859e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -106,6 +106,111 @@
 	acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
 
 /*
+ * Write buffer management.
+ * All of these assume proper locks taken by the caller.
+ */
+
+static int acm_wb_alloc(struct acm *acm)
+{
+	int i, wbn;
+	struct acm_wb *wb;
+
+	wbn = acm->write_current;
+	i = 0;
+	for (;;) {
+		wb = &acm->wb[wbn];
+		if (!wb->use) {
+			wb->use = 1;
+			return wbn;
+		}
+		wbn = (wbn + 1) % ACM_NWB;
+		if (++i >= ACM_NWB)
+			return -1;
+	}
+}
+
+static void acm_wb_free(struct acm *acm, int wbn)
+{
+	acm->wb[wbn].use = 0;
+}
+
+static int acm_wb_is_avail(struct acm *acm)
+{
+	int i, n;
+
+	n = 0;
+	for (i = 0; i < ACM_NWB; i++) {
+		if (!acm->wb[i].use)
+			n++;
+	}
+	return n;
+}
+
+static inline int acm_wb_is_used(struct acm *acm, int wbn)
+{
+	return acm->wb[wbn].use;
+}
+
+/*
+ * Finish write.
+ */
+static void acm_write_done(struct acm *acm)
+{
+	unsigned long flags;
+	int wbn;
+
+	spin_lock_irqsave(&acm->write_lock, flags);
+	acm->write_ready = 1;
+	wbn = acm->write_current;
+	acm_wb_free(acm, wbn);
+	acm->write_current = (wbn + 1) % ACM_NWB;
+	spin_unlock_irqrestore(&acm->write_lock, flags);
+}
+
+/*
+ * Poke write.
+ */
+static int acm_write_start(struct acm *acm)
+{
+	unsigned long flags;
+	int wbn;
+	struct acm_wb *wb;
+	int rc;
+
+	spin_lock_irqsave(&acm->write_lock, flags);
+	if (!acm->dev) {
+		spin_unlock_irqrestore(&acm->write_lock, flags);
+		return -ENODEV;
+	}
+
+	if (!acm->write_ready) {
+		spin_unlock_irqrestore(&acm->write_lock, flags);
+		return 0;	/* A white lie */
+	}
+
+	wbn = acm->write_current;
+	if (!acm_wb_is_used(acm, wbn)) {
+		spin_unlock_irqrestore(&acm->write_lock, flags);
+		return 0;
+	}
+	wb = &acm->wb[wbn];
+
+	acm->write_ready = 0;
+	spin_unlock_irqrestore(&acm->write_lock, flags);
+
+	acm->writeurb->transfer_buffer = wb->buf;
+	acm->writeurb->transfer_dma = wb->dmah;
+	acm->writeurb->transfer_buffer_length = wb->len;
+	acm->writeurb->dev = acm->dev;
+
+	if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
+		dbg("usb_submit_urb(write bulk) failed: %d", rc);
+		acm_write_done(acm);
+	}
+	return rc;
+}
+
+/*
  * Interrupt handlers for various ACM device responses
  */
 
@@ -237,17 +342,13 @@
 static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
 {
 	struct acm *acm = (struct acm *)urb->context;
+
 	dbg("Entering acm_write_bulk with status %d\n", urb->status);
 
-	if (!ACM_READY(acm))
-		goto out;
-
-	if (urb->status)
-		dbg("nonzero write bulk status received: %d", urb->status);
-
-	schedule_work(&acm->work);
-out:
-	acm->ready_for_write = 1;
+	acm_write_done(acm);
+	acm_write_start(acm);
+	if (ACM_READY(acm))
+		schedule_work(&acm->work);
 }
 
 static void acm_softint(void *private)
@@ -351,32 +452,33 @@
 {
 	struct acm *acm = tty->driver_data;
 	int stat;
+	unsigned long flags;
+	int wbn;
+	struct acm_wb *wb;
+
 	dbg("Entering acm_tty_write to write %d bytes,\n", count);
 
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	if (!acm->ready_for_write)
-		return 0;
 	if (!count)
 		return 0;
 
-	count = (count > acm->writesize) ? acm->writesize : count;
-
-	dbg("Get %d bytes...", count);
-	memcpy(acm->write_buffer, buf, count);
-	dbg("  Successfully copied.\n");
-
-	acm->writeurb->transfer_buffer_length = count;
-	acm->writeurb->dev = acm->dev;
-
-	acm->ready_for_write = 0;
-	stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
-	if (stat < 0) {
-		dbg("usb_submit_urb(write bulk) failed");
-		acm->ready_for_write = 1;
-		return stat;
+	spin_lock_irqsave(&acm->write_lock, flags);
+	if ((wbn = acm_wb_alloc(acm)) < 0) {
+		spin_unlock_irqrestore(&acm->write_lock, flags);
+		acm_write_start(acm);
+		return 0;
 	}
+	wb = &acm->wb[wbn];
 
+	count = (count > acm->writesize) ? acm->writesize : count;
+	dbg("Get %d bytes...", count);
+	memcpy(wb->buf, buf, count);
+	wb->len = count;
+	spin_unlock_irqrestore(&acm->write_lock, flags);
+
+	if ((stat = acm_write_start(acm)) < 0)
+		return stat;
 	return count;
 }
 
@@ -385,7 +487,11 @@
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	return !acm->ready_for_write ? 0 : acm->writesize;
+	/*
+	 * Do not let the line discipline to know that we have a reserve,
+	 * or it might get too enthusiastic.
+	 */
+	return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
 }
 
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@@ -393,7 +499,10 @@
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
+	/*
+	 * This is inaccurate (overcounts), but it works.
+	 */
+	return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
 }
 
 static void acm_tty_throttle(struct tty_struct *tty)
@@ -526,6 +635,39 @@
  * USB probe and disconnect routines.
  */
 
+/* Little helper: write buffers free */
+static void acm_write_buffers_free(struct acm *acm)
+{
+	int i;
+	struct acm_wb *wb;
+
+	for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+		usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
+	}
+}
+
+/* Little helper: write buffers allocate */
+static int acm_write_buffers_alloc(struct acm *acm)
+{
+	int i;
+	struct acm_wb *wb;
+
+	for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+		wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
+		    &wb->dmah);
+		if (!wb->buf) {
+			while (i != 0) {
+				--i;
+				--wb;
+				usb_buffer_free(acm->dev, acm->writesize,
+				    wb->buf, wb->dmah);
+			}
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
 static int acm_probe (struct usb_interface *intf,
 		      const struct usb_device_id *id)
 {
@@ -700,7 +842,8 @@
 	acm->bh.data = (unsigned long) acm;
 	INIT_WORK(&acm->work, acm_softint, acm);
 	spin_lock_init(&acm->throttle_lock);
-	acm->ready_for_write = 1;
+	spin_lock_init(&acm->write_lock);
+	acm->write_ready = 1;
 
 	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
 	if (!buf) {
@@ -716,12 +859,10 @@
 	}
 	acm->read_buffer = buf;
 
-	buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma);
-	if (!buf) {
+	if (acm_write_buffers_alloc(acm) < 0) {
 		dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
 		goto alloc_fail4;
 	}
-	acm->write_buffer = buf;	
 
 	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!acm->ctrlurb) {
@@ -750,9 +891,9 @@
 	acm->readurb->transfer_dma = acm->read_dma;
 
 	usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
-			  acm->write_buffer, acm->writesize, acm_write_bulk, acm);
+			  NULL, acm->writesize, acm_write_bulk, acm);
 	acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
-	acm->writeurb->transfer_dma = acm->write_dma;
+	/* acm->writeurb->transfer_dma = 0; */
 
 	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 
@@ -775,7 +916,7 @@
 alloc_fail6:
 	usb_free_urb(acm->ctrlurb);
 alloc_fail5:
-	usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+	acm_write_buffers_free(acm);
 alloc_fail4:
 	usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
 alloc_fail3:
@@ -806,7 +947,7 @@
 
 	flush_scheduled_work(); /* wait for acm_softint */
 
-	usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+	acm_write_buffers_free(acm);
 	usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
 	usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 9009114..963a5df 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -51,14 +51,34 @@
  * Internal driver structures.
  */
 
+/*
+ * The only reason to have several buffers is to accomodate assumptions
+ * in line disciplines. They ask for empty space amount, receive our URB size,
+ * and proceed to issue several 1-character writes, assuming they will fit.
+ * The very first write takes a complete URB. Fortunately, this only happens
+ * when processing onlcr, so we only need 2 buffers.
+ */
+#define ACM_NWB  2
+struct acm_wb {
+	unsigned char *buf;
+	dma_addr_t dmah;
+	int len;
+	int use;
+};
+
 struct acm {
 	struct usb_device *dev;				/* the corresponding usb device */
 	struct usb_interface *control;			/* control interface */
 	struct usb_interface *data;			/* data interface */
 	struct tty_struct *tty;				/* the corresponding tty */
 	struct urb *ctrlurb, *readurb, *writeurb;	/* urbs */
-	u8 *ctrl_buffer, *read_buffer, *write_buffer;	/* buffers of urbs */
-	dma_addr_t ctrl_dma, read_dma, write_dma;	/* dma handles of buffers */
+	u8 *ctrl_buffer, *read_buffer;			/* buffers of urbs */
+	dma_addr_t ctrl_dma, read_dma;			/* dma handles of buffers */
+	struct acm_wb wb[ACM_NWB];
+	int write_current;				/* current write buffer */
+	int write_used;					/* number of non-empty write buffers */
+	int write_ready;				/* write urb is not running */
+	spinlock_t write_lock;
 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
 	struct tasklet_struct bh;			/* rx processing */
@@ -71,7 +91,6 @@
 	unsigned int minor;				/* acm minor number */
 	unsigned char throttle;				/* throttled by tty layer */
 	unsigned char clocal;				/* termios CLOCAL */
-	unsigned char ready_for_write;			/* write urb can be used */
 	unsigned char resubmit_to_unthrottle;		/* throtteling has disabled the read urb */
 	unsigned int ctrl_caps;				/* control capabilities from the class specific header */
 };
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index bba22e9..7ce43fb 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -379,6 +379,8 @@
 	usblp->writeurb->transfer_buffer_length = 0;
 	usblp->wcomplete = 1; /* we begin writeable */
 	usblp->rcomplete = 0;
+	usblp->writeurb->status = 0;
+	usblp->readurb->status = 0;
 
 	if (usblp->bidir) {
 		usblp->readcount = 0;
@@ -751,6 +753,7 @@
 				schedule();
 			} else {
 				set_current_state(TASK_RUNNING);
+				down(&usblp->sem);
 				break;
 			}
 			down (&usblp->sem);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 6bfab4b..787c27a 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -784,16 +784,16 @@
  		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
  			if (usb_interface_claimed(actconfig->interface[i])) {
 				dev_warn (&ps->dev->dev,
-					"usbfs: interface %d claimed "
+					"usbfs: interface %d claimed by %s "
 					"while '%s' sets config #%d\n",
 					actconfig->interface[i]
 						->cur_altsetting
 						->desc.bInterfaceNumber,
+					actconfig->interface[i]
+						->dev.driver->name,
 					current->comm, u);
-#if 0	/* FIXME:  enable in 2.6.10 or so */
  				status = -EBUSY;
 				break;
-#endif
 			}
  		}
  	}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0da2373..83e732a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -519,119 +519,120 @@
 /*-------------------------------------------------------------------------*/
 
 /*
- * Root Hub interrupt transfers are synthesized with a timer.
- * Completions are called in_interrupt() but not in_irq().
+ * Root Hub interrupt transfers are polled using a timer if the
+ * driver requests it; otherwise the driver is responsible for
+ * calling usb_hcd_poll_rh_status() when an event occurs.
  *
- * Note: some root hubs (including common UHCI based designs) can't
- * correctly issue port change IRQs.  They're the ones that _need_ a
- * timer; most other root hubs don't.  Some systems could save a
- * lot of battery power by eliminating these root hub timer IRQs.
+ * Completions are called in_interrupt(), but they may or may not
+ * be in_irq().
  */
-
-static void rh_report_status (unsigned long ptr);
-
-static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
-{
-	int	len = 1 + (urb->dev->maxchild / 8);
-
-	/* rh_timer protected by hcd_data_lock */
-	if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
-		dev_dbg (hcd->self.controller,
-				"not queuing rh status urb, stat %d\n",
-				urb->status);
-		return -EINVAL;
-	}
-
-	init_timer (&hcd->rh_timer);
-	hcd->rh_timer.function = rh_report_status;
-	hcd->rh_timer.data = (unsigned long) urb;
-	/* USB 2.0 spec says 256msec; this is close enough */
-	hcd->rh_timer.expires = jiffies + HZ/4;
-	add_timer (&hcd->rh_timer);
-	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */
-	return 0;
-}
-
-/* timer callback */
-
-static void rh_report_status (unsigned long ptr)
+void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
 {
 	struct urb	*urb;
-	struct usb_hcd	*hcd;
-	int		length = 0;
+	int		length;
 	unsigned long	flags;
+	char		buffer[4];	/* Any root hubs with > 31 ports? */
 
-	urb = (struct urb *) ptr;
-	local_irq_save (flags);
-	spin_lock (&urb->lock);
-
-	/* do nothing if the urb's been unlinked */
-	if (!urb->dev
-			|| urb->status != -EINPROGRESS
-			|| (hcd = urb->dev->bus->hcpriv) == NULL) {
-		spin_unlock (&urb->lock);
-		local_irq_restore (flags);
+	if (!hcd->uses_new_polling && !hcd->status_urb)
 		return;
-	}
 
-	/* complete the status urb, or retrigger the timer */
-	spin_lock (&hcd_data_lock);
-	if (urb->dev->state == USB_STATE_CONFIGURED) {
-		length = hcd->driver->hub_status_data (
-					hcd, urb->transfer_buffer);
-		if (length > 0) {
-			hcd->rh_timer.data = 0;
-			urb->actual_length = length;
-			urb->status = 0;
-			urb->hcpriv = NULL;
+	length = hcd->driver->hub_status_data(hcd, buffer);
+	if (length > 0) {
+
+		/* try to complete the status urb */
+		local_irq_save (flags);
+		spin_lock(&hcd_root_hub_lock);
+		urb = hcd->status_urb;
+		if (urb) {
+			spin_lock(&urb->lock);
+			if (urb->status == -EINPROGRESS) {
+				hcd->poll_pending = 0;
+				hcd->status_urb = NULL;
+				urb->status = 0;
+				urb->hcpriv = NULL;
+				urb->actual_length = length;
+				memcpy(urb->transfer_buffer, buffer, length);
+			} else		/* urb has been unlinked */
+				length = 0;
+			spin_unlock(&urb->lock);
 		} else
-			mod_timer (&hcd->rh_timer, jiffies + HZ/4);
-	}
-	spin_unlock (&hcd_data_lock);
-	spin_unlock (&urb->lock);
+			length = 0;
+		spin_unlock(&hcd_root_hub_lock);
 
-	/* local irqs are always blocked in completions */
-	if (length > 0)
-		usb_hcd_giveback_urb (hcd, urb, NULL);
-	local_irq_restore (flags);
+		/* local irqs are always blocked in completions */
+		if (length > 0)
+			usb_hcd_giveback_urb (hcd, urb, NULL);
+		else
+			hcd->poll_pending = 1;
+		local_irq_restore (flags);
+	}
+
+	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
+	 * exceed that limit if HZ is 100. */
+	if (hcd->uses_new_polling ? hcd->poll_rh :
+			(length == 0 && hcd->status_urb != NULL))
+		mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
+}
+EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
+
+/* timer callback */
+static void rh_timer_func (unsigned long _hcd)
+{
+	usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
 }
 
 /*-------------------------------------------------------------------------*/
 
+static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
+{
+	int		retval;
+	unsigned long	flags;
+	int		len = 1 + (urb->dev->maxchild / 8);
+
+	spin_lock_irqsave (&hcd_root_hub_lock, flags);
+	if (urb->status != -EINPROGRESS)	/* already unlinked */
+		retval = urb->status;
+	else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+		dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
+		retval = -EINVAL;
+	} else {
+		hcd->status_urb = urb;
+		urb->hcpriv = hcd;	/* indicate it's queued */
+
+		if (!hcd->uses_new_polling)
+			mod_timer (&hcd->rh_timer, jiffies +
+					msecs_to_jiffies(250));
+
+		/* If a status change has already occurred, report it ASAP */
+		else if (hcd->poll_pending)
+			mod_timer (&hcd->rh_timer, jiffies);
+		retval = 0;
+	}
+	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+	return retval;
+}
+
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-	if (usb_pipeint (urb->pipe)) {
-		int		retval;
-		unsigned long	flags;
-
-		spin_lock_irqsave (&hcd_data_lock, flags);
-		retval = rh_status_urb (hcd, urb);
-		spin_unlock_irqrestore (&hcd_data_lock, flags);
-		return retval;
-	}
+	if (usb_pipeint (urb->pipe))
+		return rh_queue_status (hcd, urb);
 	if (usb_pipecontrol (urb->pipe))
 		return rh_call_control (hcd, urb);
-	else
-		return -EINVAL;
+	return -EINVAL;
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* Asynchronous unlinks of root-hub control URBs are legal, but they
+ * don't do anything.  Status URB unlinks must be made in process context
+ * with interrupts enabled.
+ */
 static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
-	unsigned long	flags;
+	if (usb_pipeendpoint(urb->pipe) == 0) {	/* Control URB */
+		if (in_interrupt())
+			return 0;		/* nothing to do */
 
-	/* note:  always a synchronous unlink */
-	if ((unsigned long) urb == hcd->rh_timer.data) {
-		del_timer_sync (&hcd->rh_timer);
-		hcd->rh_timer.data = 0;
-
-		local_irq_save (flags);
-		urb->hcpriv = NULL;
-		usb_hcd_giveback_urb (hcd, urb, NULL);
-		local_irq_restore (flags);
-
-	} else if (usb_pipeendpoint(urb->pipe) == 0) {
 		spin_lock_irq(&urb->lock);	/* from usb_kill_urb */
 		++urb->reject;
 		spin_unlock_irq(&urb->lock);
@@ -642,8 +643,22 @@
 		spin_lock_irq(&urb->lock);
 		--urb->reject;
 		spin_unlock_irq(&urb->lock);
-	} else
-		return -EINVAL;
+
+	} else {				/* Status URB */
+		if (!hcd->uses_new_polling)
+			del_timer_sync (&hcd->rh_timer);
+		local_irq_disable ();
+		spin_lock (&hcd_root_hub_lock);
+		if (urb == hcd->status_urb) {
+			hcd->status_urb = NULL;
+			urb->hcpriv = NULL;
+		} else
+			urb = NULL;		/* wasn't fully queued */
+		spin_unlock (&hcd_root_hub_lock);
+		if (urb)
+			usb_hcd_giveback_urb (hcd, urb, NULL);
+		local_irq_enable ();
+	}
 
 	return 0;
 }
@@ -817,30 +832,22 @@
 }
 
 /**
- * usb_hcd_register_root_hub - called by HCD to register its root hub 
+ * register_root_hub - called by usb_add_hcd() to register a root hub
  * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  *
- * The USB host controller calls this function to register the root hub
- * properly with the USB subsystem.  It sets up the device properly in
- * the device tree and stores the root_hub pointer in the bus structure,
- * then calls usb_new_device() to register the usb device.  It also
- * assigns the root hub's USB address (always 1).
+ * This function registers the root hub with the USB subsystem.  It sets up
+ * the device properly in the device tree and stores the root_hub pointer
+ * in the bus structure, then calls usb_new_device() to register the usb
+ * device.  It also assigns the root hub's USB address (always 1).
  */
-int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
+static int register_root_hub (struct usb_device *usb_dev,
+		struct usb_hcd *hcd)
 {
 	struct device *parent_dev = hcd->self.controller;
 	const int devnum = 1;
 	int retval;
 
-	/* hcd->driver->start() reported can_wakeup, probably with
-	 * assistance from board's boot firmware.
-	 * NOTE:  normal devices won't enable wakeup by default.
-	 */
-	if (hcd->can_wakeup)
-		dev_dbg (parent_dev, "supports USB remote wakeup\n");
-	hcd->remote_wakeup = hcd->can_wakeup;
-
 	usb_dev->devnum = devnum;
 	usb_dev->bus->devnum_next = devnum + 1;
 	memset (&usb_dev->bus->devmap.devicemap, 0,
@@ -883,7 +890,16 @@
 
 	return retval;
 }
-EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
+
+void usb_enable_root_hub_irq (struct usb_bus *bus)
+{
+	struct usb_hcd *hcd;
+
+	hcd = container_of (bus, struct usb_hcd, self);
+	if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
+			hcd->state != HC_STATE_HALT)
+		hcd->driver->hub_irq_enable (hcd);
+}
 
 
 /*-------------------------------------------------------------------------*/
@@ -1348,7 +1364,8 @@
 
 	hcd = udev->bus->hcpriv;
 
-	WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
+	WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
+			udev->state != USB_STATE_NOTATTACHED);
 
 	local_irq_disable ();
 
@@ -1612,6 +1629,8 @@
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	if (hcd->rh_registered) {
+		hcd->poll_rh = 0;
+		del_timer(&hcd->rh_timer);
 
 		/* make khubd clean up old urbs and devices */
 		usb_set_device_state (hcd->self.root_hub,
@@ -1665,6 +1684,8 @@
 	hcd->self.bus_name = bus_name;
 
 	init_timer(&hcd->rh_timer);
+	hcd->rh_timer.function = rh_timer_func;
+	hcd->rh_timer.data = (unsigned long) hcd;
 
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1694,7 +1715,8 @@
 int usb_add_hcd(struct usb_hcd *hcd,
 		unsigned int irqnum, unsigned long irqflags)
 {
-	int	retval;
+	int retval;
+	struct usb_device *rhdev;
 
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
@@ -1710,7 +1732,7 @@
 	}
 
 	if ((retval = usb_register_bus(&hcd->self)) < 0)
-		goto err1;
+		goto err_register_bus;
 
 	if (hcd->driver->irq) {
 		char	buf[8], *bufp = buf;
@@ -1727,7 +1749,7 @@
 				hcd->irq_descr, hcd)) != 0) {
 			dev_err(hcd->self.controller,
 					"request interrupt %s failed\n", bufp);
-			goto err2;
+			goto err_request_irq;
 		}
 		hcd->irq = irqnum;
 		dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
@@ -1743,19 +1765,55 @@
 					(unsigned long long)hcd->rsrc_start);
 	}
 
+	/* Allocate the root hub before calling hcd->driver->start(),
+	 * but don't register it until afterward so that the hardware
+	 * is running.
+	 */
+	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+		dev_err(hcd->self.controller, "unable to allocate root hub\n");
+		retval = -ENOMEM;
+		goto err_allocate_root_hub;
+	}
+	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+			USB_SPEED_FULL;
+
+	/* Although in principle hcd->driver->start() might need to use rhdev,
+	 * none of the current drivers do.
+	 */
 	if ((retval = hcd->driver->start(hcd)) < 0) {
 		dev_err(hcd->self.controller, "startup error %d\n", retval);
-		goto err3;
+		goto err_hcd_driver_start;
 	}
 
+	/* hcd->driver->start() reported can_wakeup, probably with
+	 * assistance from board's boot firmware.
+	 * NOTE:  normal devices won't enable wakeup by default.
+	 */
+	if (hcd->can_wakeup)
+		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+	hcd->remote_wakeup = hcd->can_wakeup;
+
+	if ((retval = register_root_hub(rhdev, hcd)) != 0)
+		goto err_register_root_hub;
+
+	if (hcd->uses_new_polling && hcd->poll_rh)
+		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
- err3:
+ err_register_root_hub:
+	hcd->driver->stop(hcd);
+
+ err_hcd_driver_start:
+	usb_put_dev(rhdev);
+
+ err_allocate_root_hub:
 	if (hcd->irq >= 0)
 		free_irq(irqnum, hcd);
- err2:
+
+ err_request_irq:
 	usb_deregister_bus(&hcd->self);
- err1:
+
+ err_register_bus:
 	hcd_buffer_destroy(hcd);
 	return retval;
 } 
@@ -1782,6 +1840,9 @@
 	spin_unlock_irq (&hcd_root_hub_lock);
 	usb_disconnect(&hcd->self.root_hub);
 
+	hcd->poll_rh = 0;
+	del_timer_sync(&hcd->rh_timer);
+
 	hcd->driver->stop(hcd);
 	hcd->state = HC_STATE_HALT;
 
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 325a516..8dc13cd 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -65,7 +65,8 @@
 	const char		*product_desc;	/* product/vendor string */
 	char			irq_descr[24];	/* driver + bus # */
 
-	struct timer_list	rh_timer;	/* drives root hub */
+	struct timer_list	rh_timer;	/* drives root-hub polling */
+	struct urb		*status_urb;	/* the current status urb */
 
 	/*
 	 * hardware info/state
@@ -76,10 +77,17 @@
 	unsigned		remote_wakeup:1;/* sw should use wakeup? */
 	unsigned		rh_registered:1;/* is root hub registered? */
 
+	/* The next flag is a stopgap, to be removed when all the HCDs
+	 * support the new root-hub polling mechanism. */
+	unsigned		uses_new_polling:1;
+	unsigned		poll_rh:1;	/* poll for rh status? */
+	unsigned		poll_pending:1;	/* status has changed? */
+
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
 	u64			rsrc_start;	/* memory/io resource start */
 	u64			rsrc_len;	/* memory/io resource length */
+	unsigned		power_budget;	/* in mA, 0 = no limit */
 
 #define HCD_BUFFER_POOLS	4
 	struct dma_pool		*pool [HCD_BUFFER_POOLS];
@@ -207,6 +215,8 @@
 	int		(*hub_suspend)(struct usb_hcd *);
 	int		(*hub_resume)(struct usb_hcd *);
 	int		(*start_port_reset)(struct usb_hcd *, unsigned port_num);
+	void		(*hub_irq_enable)(struct usb_hcd *);
+		/* Needed only if port-change IRQs are level-triggered */
 };
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
@@ -243,7 +253,9 @@
 
 /* generic bus glue, needed for host controllers that don't use PCI */
 extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+
 extern void usb_hc_died (struct usb_hcd *hcd);
+extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
 
 /* -------------------------------------------------------------------------- */
 
@@ -341,9 +353,6 @@
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 
-extern int usb_hcd_register_root_hub (struct usb_device *usb_dev,
-		struct usb_hcd *hcd);
-
 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
 
 extern void usb_set_device_state(struct usb_device *udev,
@@ -360,6 +369,8 @@
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
 extern void usb_bus_put (struct usb_bus *bus);
 
+extern void usb_enable_root_hub_irq (struct usb_bus *bus);
+
 extern int usb_find_interface_driver (struct usb_device *dev,
 	struct usb_interface *interface);
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index a8d879a..32ff321 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -643,15 +643,21 @@
 		message = "can't get hub status";
 		goto fail;
 	}
-	cpu_to_le16s(&hubstatus);
-	if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+	le16_to_cpus(&hubstatus);
+	if (hdev == hdev->bus->root_hub) {
+		struct usb_hcd *hcd =
+				container_of(hdev->bus, struct usb_hcd, self);
+
+		hub->power_budget = min(500u, hcd->power_budget) / 2;
+	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
 		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
 			hub->descriptor->bHubContrCurrent);
 		hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
 					/ 2;
+	}
+	if (hub->power_budget)
 		dev_dbg(hub_dev, "%dmA bus power budget for children\n",
 			hub->power_budget * 2);
-	}
 
 
 	ret = hub_hub_status(hub, &hubstatus, &hubchange);
@@ -1727,7 +1733,7 @@
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (intf->dev.power.power_state == PMSG_SUSPEND)
+			if (intf->dev.power.power_state == PMSG_ON)
 				continue;
 			if (!intf->dev.driver) {
 				/* FIXME maybe force to alt 0 */
@@ -2787,6 +2793,11 @@
 
 		hub->activating = 0;
 
+		/* If this is a root hub, tell the HCD it's okay to
+		 * re-enable port-change interrupts now. */
+		if (!hdev->parent)
+			usb_enable_root_hub_irq(hdev->bus);
+
 loop:
 		usb_unlock_device(hdev);
 		usb_put_intf(intf);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index d114b84..53bf564 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -224,15 +224,4 @@
 	struct work_struct	leds;
 };
 
-/* use this for low-powered root hubs */
-static inline void
-hub_set_power_budget (struct usb_device *hubdev, unsigned mA)
-{
-	struct usb_hub	*hub;
-
-	hub = (struct usb_hub *)
-		usb_get_intfdata (hubdev->actconfig->interface[0]);
-	hub->power_budget = min(mA,(unsigned)500)/2;
-}
-
 #endif /* __LINUX_HUB_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3b24f9f..ff075a5 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -53,6 +53,9 @@
 	   driver on a new board.   Enable these files by choosing "Y"
 	   here.  If in doubt, or to conserve kernel memory, say "N".
 
+config	USB_GADGET_SELECTED
+	boolean
+
 #
 # USB Peripheral Controller Support
 #
@@ -85,6 +88,7 @@
 	tristate
 	depends on USB_GADGET_NET2280
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 config USB_GADGET_PXA2XX
 	boolean "PXA 25x or IXP 4xx"
@@ -105,6 +109,7 @@
 	tristate
 	depends on USB_GADGET_PXA2XX
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 # if there's only one gadget driver, using only two bulk endpoints,
 # don't waste memory for the other endpoints
@@ -134,6 +139,7 @@
 	tristate
 	depends on USB_GADGET_GOKU
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 
 config USB_GADGET_LH7A40X
@@ -146,6 +152,7 @@
 	tristate
 	depends on USB_GADGET_LH7A40X
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 
 config USB_GADGET_OMAP
@@ -167,6 +174,7 @@
 	tristate
 	depends on USB_GADGET_OMAP
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 config USB_OTG
 	boolean "OTG Support"
@@ -207,6 +215,7 @@
 	tristate
 	depends on USB_GADGET_DUMMY_HCD
 	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
@@ -226,7 +235,7 @@
 #
 choice
 	tristate "USB Gadget Drivers"
-	depends on USB_GADGET
+	depends on USB_GADGET && USB_GADGET_SELECTED
 	default USB_ETH
 	help
 	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c039d2f..4d69267 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -65,7 +65,7 @@
 
 
 #define DRIVER_DESC	"USB Host+Gadget Emulator"
-#define DRIVER_VERSION	"17 Dec 2004"
+#define DRIVER_VERSION	"02 May 2005"
 
 static const char	driver_name [] = "dummy_hcd";
 static const char	driver_desc [] = "USB Host+Gadget Emulator";
@@ -141,6 +141,8 @@
 };
 #define DUMMY_ENDPOINTS	(sizeof(ep_name)/sizeof(char *))
 
+/*-------------------------------------------------------------------------*/
+
 #define FIFO_SIZE		64
 
 struct urbp {
@@ -148,6 +150,13 @@
 	struct list_head	urbp_list;
 };
 
+
+enum dummy_rh_state {
+	DUMMY_RH_RESET,
+	DUMMY_RH_SUSPENDED,
+	DUMMY_RH_RUNNING
+};
+
 struct dummy {
 	spinlock_t			lock;
 
@@ -161,12 +170,18 @@
 	struct dummy_request		fifo_req;
 	u8				fifo_buf [FIFO_SIZE];
 	u16				devstatus;
+	unsigned			udc_suspended:1;
+	unsigned			pullup:1;
+	unsigned			active:1;
+	unsigned			old_active:1;
 
 	/*
 	 * MASTER/HOST side support
 	 */
+	enum dummy_rh_state		rh_state;
 	struct timer_list		timer;
 	u32				port_status;
+	u32				old_status;
 	unsigned			resuming:1;
 	unsigned long			re_timeout;
 
@@ -189,6 +204,11 @@
 	return dummy_to_hcd(dum)->self.controller;
 }
 
+static inline struct device *udc_dev (struct dummy *dum)
+{
+	return dum->gadget.dev.parent;
+}
+
 static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 {
 	return container_of (ep->gadget, struct dummy, gadget);
@@ -208,16 +228,98 @@
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * This "hardware" may look a bit odd in diagnostics since it's got both
- * host and device sides; and it binds different drivers to each side.
- */
-static struct platform_device		the_pdev;
+/* SLAVE/GADGET SIDE UTILITY ROUTINES */
 
-static struct device_driver dummy_driver = {
-	.name		= (char *) driver_name,
-	.bus		= &platform_bus_type,
-};
+/* called with spinlock held */
+static void nuke (struct dummy *dum, struct dummy_ep *ep)
+{
+	while (!list_empty (&ep->queue)) {
+		struct dummy_request	*req;
+
+		req = list_entry (ep->queue.next, struct dummy_request, queue);
+		list_del_init (&req->queue);
+		req->req.status = -ESHUTDOWN;
+
+		spin_unlock (&dum->lock);
+		req->req.complete (&ep->ep, &req->req);
+		spin_lock (&dum->lock);
+	}
+}
+
+/* caller must hold lock */
+static void
+stop_activity (struct dummy *dum)
+{
+	struct dummy_ep	*ep;
+
+	/* prevent any more requests */
+	dum->address = 0;
+
+	/* The timer is left running so that outstanding URBs can fail */
+
+	/* nuke any pending requests first, so driver i/o is quiesced */
+	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
+		nuke (dum, ep);
+
+	/* driver now does any non-usb quiescing necessary */
+}
+
+/* caller must hold lock */
+static void
+set_link_state (struct dummy *dum)
+{
+	dum->active = 0;
+	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
+		dum->port_status = 0;
+
+	/* UDC suspend must cause a disconnect */
+	else if (!dum->pullup || dum->udc_suspended) {
+		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+					USB_PORT_STAT_ENABLE |
+					USB_PORT_STAT_LOW_SPEED |
+					USB_PORT_STAT_HIGH_SPEED |
+					USB_PORT_STAT_SUSPEND);
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+	} else {
+		dum->port_status |= USB_PORT_STAT_CONNECTION;
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
+			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+				dum->rh_state != DUMMY_RH_SUSPENDED)
+			dum->active = 1;
+	}
+
+	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
+		dum->resuming = 0;
+
+	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+				dum->driver) {
+			stop_activity (dum);
+			spin_unlock (&dum->lock);
+			dum->driver->disconnect (&dum->gadget);
+			spin_lock (&dum->lock);
+		}
+	} else if (dum->active != dum->old_active) {
+		if (dum->old_active && dum->driver->suspend) {
+			spin_unlock (&dum->lock);
+			dum->driver->suspend (&dum->gadget);
+			spin_lock (&dum->lock);
+		} else if (!dum->old_active && dum->driver->resume) {
+			spin_unlock (&dum->lock);
+			dum->driver->resume (&dum->gadget);
+			spin_lock (&dum->lock);
+		}
+	}
+
+	dum->old_status = dum->port_status;
+	dum->old_active = dum->active;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -324,7 +426,7 @@
 	_ep->maxpacket = max;
 	ep->desc = desc;
 
-	dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
 		_ep->name,
 		desc->bEndpointAddress & 0x0f,
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
@@ -345,22 +447,6 @@
 	return retval;
 }
 
-/* called with spinlock held */
-static void nuke (struct dummy *dum, struct dummy_ep *ep)
-{
-	while (!list_empty (&ep->queue)) {
-		struct dummy_request	*req;
-
-		req = list_entry (ep->queue.next, struct dummy_request, queue);
-		list_del_init (&req->queue);
-		req->req.status = -ESHUTDOWN;
-
-		spin_unlock (&dum->lock);
-		req->req.complete (&ep->ep, &req->req);
-		spin_lock (&dum->lock);
-	}
-}
-
 static int dummy_disable (struct usb_ep *_ep)
 {
 	struct dummy_ep		*ep;
@@ -379,7 +465,7 @@
 	nuke (dum, ep);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
-	dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
 	return retval;
 }
 
@@ -474,7 +560,7 @@
 		return -ESHUTDOWN;
 
 #if 0
-	dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
 			ep, _req, _ep->name, _req->length, _req->buf);
 #endif
 
@@ -537,7 +623,7 @@
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	if (retval == 0) {
-		dev_dbg (dummy_dev(dum),
+		dev_dbg (udc_dev(dum),
 				"dequeued req %p from %s, len %d buf %p\n",
 				req, _ep->name, _req->length, _req->buf);
 		_req->complete (_ep, _req);
@@ -601,13 +687,21 @@
 	struct dummy	*dum;
 
 	dum = gadget_to_dummy (_gadget);
-	if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
-			|| !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
+	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
+				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
 		return -EINVAL;
+	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+		return -ENOLINK;
+	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+			 dum->rh_state != DUMMY_RH_SUSPENDED)
+		return -EIO;
+
+	/* FIXME: What if the root hub is suspended but the port isn't? */
 
 	/* hub notices our request, issues downstream resume, etc */
 	dum->resuming = 1;
-	dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+	dum->re_timeout = jiffies + msecs_to_jiffies(20);
+	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
 	return 0;
 }
 
@@ -623,10 +717,26 @@
 	return 0;
 }
 
+static int dummy_pullup (struct usb_gadget *_gadget, int value)
+{
+	struct dummy	*dum;
+	unsigned long	flags;
+
+	dum = gadget_to_dummy (_gadget);
+	spin_lock_irqsave (&dum->lock, flags);
+	dum->pullup = (value != 0);
+	set_link_state (dum);
+	spin_unlock_irqrestore (&dum->lock, flags);
+
+	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	return 0;
+}
+
 static const struct usb_gadget_ops dummy_ops = {
 	.get_frame	= dummy_g_get_frame,
 	.wakeup		= dummy_wakeup,
 	.set_selfpowered = dummy_set_selfpowered,
+	.pullup		= dummy_pullup,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -641,7 +751,7 @@
 		return 0;
 	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
 }
-DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
 /*-------------------------------------------------------------------------*/
 
@@ -659,38 +769,6 @@
  * for each driver that registers:  just add to a big root hub.
  */
 
-static void
-dummy_udc_release (struct device *dev)
-{
-}
-
-static void
-dummy_pdev_release (struct device *dev)
-{
-}
-
-static int
-dummy_register_udc (struct dummy *dum)
-{
-	int		rc;
-
-	strcpy (dum->gadget.dev.bus_id, "udc");
-	dum->gadget.dev.parent = dummy_dev(dum);
-	dum->gadget.dev.release = dummy_udc_release;
-
-	rc = device_register (&dum->gadget.dev);
-	if (rc == 0)
-		device_create_file (&dum->gadget.dev, &dev_attr_function);
-	return rc;
-}
-
-static void
-dummy_unregister_udc (struct dummy *dum)
-{
-	device_remove_file (&dum->gadget.dev, &dev_attr_function);
-	device_unregister (&dum->gadget.dev);
-}
-
 int
 usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
@@ -709,12 +787,8 @@
 	 * SLAVE side init ... the layer above hardware, which
 	 * can't enumerate without help from the driver we're binding.
 	 */
-	dum->gadget.name = gadget_name;
-	dum->gadget.ops = &dummy_ops;
-	dum->gadget.is_dualspeed = 1;
 
 	dum->devstatus = 0;
-	dum->resuming = 0;
 
 	INIT_LIST_HEAD (&dum->gadget.ep_list);
 	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
@@ -740,7 +814,7 @@
 
 	dum->driver = driver;
 	dum->gadget.dev.driver = &driver->driver;
-	dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
+	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
 			driver->driver.name);
 	if ((retval = driver->bind (&dum->gadget)) != 0) {
 		dum->driver = NULL;
@@ -748,42 +822,21 @@
 		return retval;
 	}
 
-	// FIXME: Check these calls for errors and re-order
 	driver->driver.bus = dum->gadget.dev.parent->bus;
 	driver_register (&driver->driver);
-
 	device_bind_driver (&dum->gadget.dev);
 
 	/* khubd will enumerate this in a while */
-	dum->port_status |= USB_PORT_STAT_CONNECTION
-		| (1 << USB_PORT_FEAT_C_CONNECTION);
+	spin_lock_irq (&dum->lock);
+	dum->pullup = 1;
+	set_link_state (dum);
+	spin_unlock_irq (&dum->lock);
+
+	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_register_driver);
 
-/* caller must hold lock */
-static void
-stop_activity (struct dummy *dum, struct usb_gadget_driver *driver)
-{
-	struct dummy_ep	*ep;
-
-	/* prevent any more requests */
-	dum->address = 0;
-
-	/* The timer is left running so that outstanding URBs can fail */
-
-	/* nuke any pending requests first, so driver i/o is quiesced */
-	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
-		nuke (dum, ep);
-
-	/* driver now does any non-usb quiescing necessary */
-	if (driver) {
-		spin_unlock (&dum->lock);
-		driver->disconnect (&dum->gadget);
-		spin_lock (&dum->lock);
-	}
-}
-
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
@@ -795,35 +848,138 @@
 	if (!driver || driver != dum->driver)
 		return -EINVAL;
 
-	dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
 			driver->driver.name);
 
 	spin_lock_irqsave (&dum->lock, flags);
-	stop_activity (dum, driver);
-	dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE |
-			USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
-	dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+	dum->pullup = 0;
+	set_link_state (dum);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 	driver->unbind (&dum->gadget);
 	dum->driver = NULL;
 
 	device_release_driver (&dum->gadget.dev);
-
 	driver_unregister (&driver->driver);
 
+	spin_lock_irqsave (&dum->lock, flags);
+	dum->pullup = 0;
+	set_link_state (dum);
+	spin_unlock_irqrestore (&dum->lock, flags);
+
+	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 }
 EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 #undef is_enabled
 
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
 int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
 {
 	return -ENOSYS;
 }
 EXPORT_SYMBOL (net2280_set_fifo_mode);
 
+
+/* The gadget structure is stored inside the hcd structure and will be
+ * released along with it. */
+static void
+dummy_gadget_release (struct device *dev)
+{
+#if 0		/* usb_bus_put isn't EXPORTed! */
+	struct dummy	*dum = gadget_dev_to_dummy (dev);
+
+	usb_bus_put (&dummy_to_hcd (dum)->self);
+#endif
+}
+
+static int dummy_udc_probe (struct device *dev)
+{
+	struct dummy	*dum = the_controller;
+	int		rc;
+
+	dum->gadget.name = gadget_name;
+	dum->gadget.ops = &dummy_ops;
+	dum->gadget.is_dualspeed = 1;
+
+	/* maybe claim OTG support, though we won't complete HNP */
+	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
+
+	strcpy (dum->gadget.dev.bus_id, "gadget");
+	dum->gadget.dev.parent = dev;
+	dum->gadget.dev.release = dummy_gadget_release;
+	rc = device_register (&dum->gadget.dev);
+	if (rc < 0)
+		return rc;
+
+#if 0		/* usb_bus_get isn't EXPORTed! */
+	usb_bus_get (&dummy_to_hcd (dum)->self);
+#endif
+
+	dev_set_drvdata (dev, dum);
+	device_create_file (&dum->gadget.dev, &dev_attr_function);
+	return rc;
+}
+
+static int dummy_udc_remove (struct device *dev)
+{
+	struct dummy	*dum = dev_get_drvdata (dev);
+
+	dev_set_drvdata (dev, NULL);
+	device_remove_file (&dum->gadget.dev, &dev_attr_function);
+	device_unregister (&dum->gadget.dev);
+	return 0;
+}
+
+static int dummy_udc_suspend (struct device *dev, pm_message_t state,
+		u32 level)
+{
+	struct dummy	*dum = dev_get_drvdata(dev);
+
+	if (level != SUSPEND_DISABLE)
+		return 0;
+
+	dev_dbg (dev, "%s\n", __FUNCTION__);
+	spin_lock_irq (&dum->lock);
+	dum->udc_suspended = 1;
+	set_link_state (dum);
+	spin_unlock_irq (&dum->lock);
+
+	dev->power.power_state = state;
+	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	return 0;
+}
+
+static int dummy_udc_resume (struct device *dev, u32 level)
+{
+	struct dummy	*dum = dev_get_drvdata(dev);
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	dev_dbg (dev, "%s\n", __FUNCTION__);
+	spin_lock_irq (&dum->lock);
+	dum->udc_suspended = 0;
+	set_link_state (dum);
+	spin_unlock_irq (&dum->lock);
+
+	dev->power.power_state = PMSG_ON;
+	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	return 0;
+}
+
+static struct device_driver dummy_udc_driver = {
+	.name		= (char *) gadget_name,
+	.bus		= &platform_bus_type,
+	.probe		= dummy_udc_probe,
+	.remove		= dummy_udc_remove,
+	.suspend	= dummy_udc_suspend,
+	.resume		= dummy_udc_resume,
+};
+
 /*-------------------------------------------------------------------------*/
 
 /* MASTER/HOST SIDE DRIVER
@@ -880,7 +1036,16 @@
 
 static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
-	/* giveback happens automatically in timer callback */
+	struct dummy	*dum;
+	unsigned long	flags;
+
+	/* giveback happens automatically in timer callback,
+	 * so make sure the callback happens */
+	dum = hcd_to_dummy (hcd);
+	spin_lock_irqsave (&dum->lock, flags);
+	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+		mod_timer (&dum->timer, jiffies);
+	spin_unlock_irqrestore (&dum->lock, flags);
 	return 0;
 }
 
@@ -1025,7 +1190,6 @@
 
 		/* high bandwidth mode */
 		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
-		tmp = le16_to_cpu (tmp);
 		tmp = (tmp >> 11) & 0x03;
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;
@@ -1123,7 +1287,8 @@
 		if (urb->status != -EINPROGRESS) {
 			/* likely it was just unlinked */
 			goto return_urb;
-		}
+		} else if (dum->rh_state != DUMMY_RH_RUNNING)
+			continue;
 		type = usb_pipetype (urb->pipe);
 
 		/* used up this frame's non-periodic bandwidth?
@@ -1168,12 +1333,14 @@
 			struct usb_ctrlrequest		setup;
 			int				value = 1;
 			struct dummy_ep			*ep2;
+			unsigned			w_index;
+			unsigned			w_value;
 
 			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
-			le16_to_cpus (&setup.wIndex);
-			le16_to_cpus (&setup.wValue);
-			le16_to_cpus (&setup.wLength);
-			if (setup.wLength != urb->transfer_buffer_length) {
+			w_index = le16_to_cpu(setup.wIndex);
+			w_value = le16_to_cpu(setup.wValue);
+			if (le16_to_cpu(setup.wLength) !=
+					urb->transfer_buffer_length) {
 				maybe_set_status (urb, -EOVERFLOW);
 				goto return_urb;
 			}
@@ -1182,7 +1349,7 @@
 			list_for_each_entry (req, &ep->queue, queue) {
 				list_del_init (&req->queue);
 				req->req.status = -EOVERFLOW;
-				dev_dbg (dummy_dev(dum), "stale req = %p\n",
+				dev_dbg (udc_dev(dum), "stale req = %p\n",
 						req);
 
 				spin_unlock (&dum->lock);
@@ -1203,31 +1370,40 @@
 			case USB_REQ_SET_ADDRESS:
 				if (setup.bRequestType != Dev_Request)
 					break;
-				dum->address = setup.wValue;
+				dum->address = w_value;
 				maybe_set_status (urb, 0);
-				dev_dbg (dummy_dev(dum), "set_address = %d\n",
-						setup.wValue);
+				dev_dbg (udc_dev(dum), "set_address = %d\n",
+						w_value);
 				value = 0;
 				break;
 			case USB_REQ_SET_FEATURE:
 				if (setup.bRequestType == Dev_Request) {
 					value = 0;
-					switch (setup.wValue) {
+					switch (w_value) {
 					case USB_DEVICE_REMOTE_WAKEUP:
 						break;
+					case USB_DEVICE_B_HNP_ENABLE:
+						dum->gadget.b_hnp_enable = 1;
+						break;
+					case USB_DEVICE_A_HNP_SUPPORT:
+						dum->gadget.a_hnp_support = 1;
+						break;
+					case USB_DEVICE_A_ALT_HNP_SUPPORT:
+						dum->gadget.a_alt_hnp_support
+							= 1;
+						break;
 					default:
 						value = -EOPNOTSUPP;
 					}
 					if (value == 0) {
 						dum->devstatus |=
-							(1 << setup.wValue);
+							(1 << w_value);
 						maybe_set_status (urb, 0);
 					}
 
 				} else if (setup.bRequestType == Ep_Request) {
 					// endpoint halt
-					ep2 = find_endpoint (dum,
-							setup.wIndex);
+					ep2 = find_endpoint (dum, w_index);
 					if (!ep2) {
 						value = -EOPNOTSUPP;
 						break;
@@ -1239,7 +1415,7 @@
 				break;
 			case USB_REQ_CLEAR_FEATURE:
 				if (setup.bRequestType == Dev_Request) {
-					switch (setup.wValue) {
+					switch (w_value) {
 					case USB_DEVICE_REMOTE_WAKEUP:
 						dum->devstatus &= ~(1 <<
 							USB_DEVICE_REMOTE_WAKEUP);
@@ -1252,8 +1428,7 @@
 					}
 				} else if (setup.bRequestType == Ep_Request) {
 					// endpoint halt
-					ep2 = find_endpoint (dum,
-							setup.wIndex);
+					ep2 = find_endpoint (dum, w_index);
 					if (!ep2) {
 						value = -EOPNOTSUPP;
 						break;
@@ -1279,7 +1454,7 @@
 					if (urb->transfer_buffer_length > 0) {
 						if (setup.bRequestType ==
 								Ep_InRequest) {
-	ep2 = find_endpoint (dum, setup.wIndex);
+	ep2 = find_endpoint (dum, w_index);
 	if (!ep2) {
 		value = -EOPNOTSUPP;
 		break;
@@ -1321,7 +1496,7 @@
 
 			if (value < 0) {
 				if (value != -EOPNOTSUPP)
-					dev_dbg (dummy_dev(dum),
+					dev_dbg (udc_dev(dum),
 						"setup --> %d\n",
 						value);
 				maybe_set_status (urb, -EPIPE);
@@ -1377,12 +1552,12 @@
 		goto restart;
 	}
 
-	/* want a 1 msec delay here */
-	if (!list_empty (&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
-	else {
+	if (list_empty (&dum->urbp_list)) {
 		usb_put_dev (dum->udev);
 		dum->udev = NULL;
+	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
+		/* want a 1 msec delay here */
+		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
 	}
 
 	spin_unlock_irqrestore (&dum->lock, flags);
@@ -1391,29 +1566,39 @@
 /*-------------------------------------------------------------------------*/
 
 #define PORT_C_MASK \
-	 ((1 << USB_PORT_FEAT_C_CONNECTION) \
-	| (1 << USB_PORT_FEAT_C_ENABLE) \
-	| (1 << USB_PORT_FEAT_C_SUSPEND) \
-	| (1 << USB_PORT_FEAT_C_OVER_CURRENT) \
-	| (1 << USB_PORT_FEAT_C_RESET))
+	((USB_PORT_STAT_C_CONNECTION \
+	| USB_PORT_STAT_C_ENABLE \
+	| USB_PORT_STAT_C_SUSPEND \
+	| USB_PORT_STAT_C_OVERCURRENT \
+	| USB_PORT_STAT_C_RESET) << 16)
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
 	struct dummy		*dum;
 	unsigned long		flags;
-	int			retval;
+	int			retval = 0;
 
 	dum = hcd_to_dummy (hcd);
 
 	spin_lock_irqsave (&dum->lock, flags);
-	if (!(dum->port_status & PORT_C_MASK))
-		retval = 0;
-	else {
+	if (hcd->state != HC_STATE_RUNNING)
+		goto done;
+
+	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
+		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		set_link_state (dum);
+	}
+
+	if ((dum->port_status & PORT_C_MASK) != 0) {
 		*buf = (1 << 1);
 		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-			dum->port_status);
+				dum->port_status);
 		retval = 1;
+		if (dum->rh_state == DUMMY_RH_SUSPENDED)
+			usb_hcd_resume_root_hub (hcd);
 	}
+done:
 	spin_unlock_irqrestore (&dum->lock, flags);
 	return retval;
 }
@@ -1424,7 +1609,8 @@
 	memset (desc, 0, sizeof *desc);
 	desc->bDescriptorType = 0x29;
 	desc->bDescLength = 9;
-	desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001);
+	desc->wHubCharacteristics = (__force __u16)
+			(__constant_cpu_to_le16 (0x0001));
 	desc->bNbrPorts = 1;
 	desc->bitmap [0] = 0xff;
 	desc->bitmap [1] = 0xff;
@@ -1442,6 +1628,9 @@
 	int		retval = 0;
 	unsigned long	flags;
 
+	if (hcd->state != HC_STATE_RUNNING)
+		return -ETIMEDOUT;
+
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
 	switch (typeReq) {
@@ -1450,27 +1639,27 @@
 	case ClearPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {
+			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
 				dum->resuming = 1;
 				dum->re_timeout = jiffies +
-							msecs_to_jiffies(20);
+						msecs_to_jiffies(20);
 			}
 			break;
 		case USB_PORT_FEAT_POWER:
-			dum->port_status = 0;
-			dum->resuming = 0;
-			stop_activity(dum, dum->driver);
-			break;
+			if (dum->port_status & USB_PORT_STAT_POWER)
+				dev_dbg (dummy_dev(dum), "power-off\n");
+			/* FALLS THROUGH */
 		default:
 			dum->port_status &= ~(1 << wValue);
+			set_link_state (dum);
 		}
 		break;
 	case GetHubDescriptor:
 		hub_descriptor ((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
-		*(u32 *) buf = __constant_cpu_to_le32 (0);
+		*(__le32 *) buf = __constant_cpu_to_le32 (0);
 		break;
 	case GetPortStatus:
 		if (wIndex != 1)
@@ -1479,23 +1668,16 @@
 		/* whoever resets or resumes must GetPortStatus to
 		 * complete it!!
 		 */
-		if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
-			dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
-			dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
-			dum->resuming = 0;
-			dum->re_timeout = 0;
-			if (dum->driver && dum->driver->resume) {
-				spin_unlock (&dum->lock);
-				dum->driver->resume (&dum->gadget);
-				spin_lock (&dum->lock);
-			}
+		if (dum->resuming &&
+				time_after_eq (jiffies, dum->re_timeout)) {
+			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
 		}
-		if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0
-				&& time_after (jiffies, dum->re_timeout)) {
-			dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);
-			dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);
-			dum->re_timeout = 0;
-			if (dum->driver) {
+		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
+				time_after_eq (jiffies, dum->re_timeout)) {
+			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
+			dum->port_status &= ~USB_PORT_STAT_RESET;
+			if (dum->pullup) {
 				dum->port_status |= USB_PORT_STAT_ENABLE;
 				/* give it the best speed we agree on */
 				dum->gadget.speed = dum->driver->speed;
@@ -1516,8 +1698,9 @@
 				}
 			}
 		}
-		((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-		((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+		set_link_state (dum);
+		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
 		break;
 	case SetHubFeature:
 		retval = -EPIPE;
@@ -1525,36 +1708,37 @@
 	case SetPortFeature:
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))
-					== 0) {
-				dum->port_status |=
-						(1 << USB_PORT_FEAT_SUSPEND);
-				if (dum->driver && dum->driver->suspend) {
-					spin_unlock (&dum->lock);
-					dum->driver->suspend (&dum->gadget);
-					spin_lock (&dum->lock);
-				}
+			if (dum->active) {
+				dum->port_status |= USB_PORT_STAT_SUSPEND;
+
+				/* HNP would happen here; for now we
+				 * assume b_bus_req is always true.
+				 */
+				set_link_state (dum);
+				if (((1 << USB_DEVICE_B_HNP_ENABLE)
+						& dum->devstatus) != 0)
+					dev_dbg (dummy_dev(dum),
+							"no HNP yet!\n");
 			}
 			break;
+		case USB_PORT_FEAT_POWER:
+			dum->port_status |= USB_PORT_STAT_POWER;
+			set_link_state (dum);
+			break;
 		case USB_PORT_FEAT_RESET:
-			/* if it's already running, disconnect first */
-			if (dum->port_status & USB_PORT_STAT_ENABLE) {
-				dum->port_status &= ~(USB_PORT_STAT_ENABLE
-						| USB_PORT_STAT_LOW_SPEED
-						| USB_PORT_STAT_HIGH_SPEED);
-				if (dum->driver) {
-					dev_dbg (dummy_dev(dum),
-							"disconnect\n");
-					stop_activity (dum, dum->driver);
-				}
-
-				/* FIXME test that code path! */
-			}
+			/* if it's already enabled, disable */
+			dum->port_status &= ~(USB_PORT_STAT_ENABLE
+					| USB_PORT_STAT_LOW_SPEED
+					| USB_PORT_STAT_HIGH_SPEED);
+			dum->devstatus = 0;
 			/* 50msec reset signaling */
 			dum->re_timeout = jiffies + msecs_to_jiffies(50);
-			/* FALLTHROUGH */
+			/* FALLS THROUGH */
 		default:
-			dum->port_status |= (1 << wValue);
+			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
+				dum->port_status |= (1 << wValue);
+				set_link_state (dum);
+			}
 		}
 		break;
 
@@ -1567,9 +1751,35 @@
 		retval = -EPIPE;
 	}
 	spin_unlock_irqrestore (&dum->lock, flags);
+
+	if ((dum->port_status & PORT_C_MASK) != 0)
+		usb_hcd_poll_rh_status (hcd);
 	return retval;
 }
 
+static int dummy_hub_suspend (struct usb_hcd *hcd)
+{
+	struct dummy *dum = hcd_to_dummy (hcd);
+
+	spin_lock_irq (&dum->lock);
+	dum->rh_state = DUMMY_RH_SUSPENDED;
+	set_link_state (dum);
+	spin_unlock_irq (&dum->lock);
+	return 0;
+}
+
+static int dummy_hub_resume (struct usb_hcd *hcd)
+{
+	struct dummy *dum = hcd_to_dummy (hcd);
+
+	spin_lock_irq (&dum->lock);
+	dum->rh_state = DUMMY_RH_RUNNING;
+	set_link_state (dum);
+	if (!list_empty(&dum->urbp_list))
+		mod_timer (&dum->timer, jiffies);
+	spin_unlock_irq (&dum->lock);
+	return 0;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -1625,8 +1835,6 @@
 static int dummy_start (struct usb_hcd *hcd)
 {
 	struct dummy		*dum;
-	struct usb_device	*root;
-	int			retval;
 
 	dum = hcd_to_dummy (hcd);
 
@@ -1639,38 +1847,22 @@
 	init_timer (&dum->timer);
 	dum->timer.function = dummy_timer;
 	dum->timer.data = (unsigned long) dum;
+	dum->rh_state = DUMMY_RH_RUNNING;
 
 	INIT_LIST_HEAD (&dum->urbp_list);
 
-	root = usb_alloc_dev (NULL, &hcd->self, 0);
-	if (!root)
-		return -ENOMEM;
-
-	/* root hub enters addressed state... */
-	hcd->state = HC_STATE_RUNNING;
-	root->speed = USB_SPEED_HIGH;
-
-	/* ...then configured, so khubd sees us. */
-	if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) {
-		goto err1;
-	}
-
 	/* only show a low-power port: just 8mA */
-	hub_set_power_budget (root, 8);
+	hcd->power_budget = 8;
+	hcd->state = HC_STATE_RUNNING;
+	hcd->uses_new_polling = 1;
 
-	if ((retval = dummy_register_udc (dum)) != 0)
-		goto err2;
+#ifdef CONFIG_USB_OTG
+	hcd->self.otg_port = 1;
+#endif
 
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
 	device_create_file (dummy_dev(dum), &dev_attr_urbs);
 	return 0;
-
- err2:
-	usb_disconnect (&hcd->self.root_hub);
- err1:
-	usb_put_dev (root);
-	hcd->state = HC_STATE_QUIESCING;
-	return retval;
 }
 
 static void dummy_stop (struct usb_hcd *hcd)
@@ -1680,10 +1872,7 @@
 	dum = hcd_to_dummy (hcd);
 
 	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-
 	usb_gadget_unregister_driver (dum->driver);
-	dummy_unregister_udc (dum);
-
 	dev_info (dummy_dev(dum), "stopped\n");
 }
 
@@ -1711,9 +1900,11 @@
 
 	.hub_status_data = 	dummy_hub_status,
 	.hub_control = 		dummy_hub_control,
+	.hub_suspend =		dummy_hub_suspend,
+	.hub_resume =		dummy_hub_resume,
 };
 
-static int dummy_probe (struct device *dev)
+static int dummy_hcd_probe (struct device *dev)
 {
 	struct usb_hcd		*hcd;
 	int			retval;
@@ -1733,7 +1924,7 @@
 	return retval;
 }
 
-static void dummy_remove (struct device *dev)
+static int dummy_hcd_remove (struct device *dev)
 {
 	struct usb_hcd		*hcd;
 
@@ -1741,35 +1932,87 @@
 	usb_remove_hcd (hcd);
 	usb_put_hcd (hcd);
 	the_controller = NULL;
+	return 0;
 }
 
+static int dummy_hcd_suspend (struct device *dev, pm_message_t state,
+		u32 level)
+{
+	struct usb_hcd		*hcd;
+
+	if (level != SUSPEND_DISABLE)
+		return 0;
+
+	dev_dbg (dev, "%s\n", __FUNCTION__);
+	hcd = dev_get_drvdata (dev);
+
+#ifndef CONFIG_USB_SUSPEND
+	/* Otherwise this would never happen */
+	usb_lock_device (hcd->self.root_hub);
+	dummy_hub_suspend (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	hcd->state = HC_STATE_SUSPENDED;
+	return 0;
+}
+
+static int dummy_hcd_resume (struct device *dev, u32 level)
+{
+	struct usb_hcd		*hcd;
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	dev_dbg (dev, "%s\n", __FUNCTION__);
+	hcd = dev_get_drvdata (dev);
+	hcd->state = HC_STATE_RUNNING;
+
+#ifndef CONFIG_USB_SUSPEND
+	/* Otherwise this would never happen */
+	usb_lock_device (hcd->self.root_hub);
+	dummy_hub_resume (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	usb_hcd_poll_rh_status (hcd);
+	return 0;
+}
+
+static struct device_driver dummy_hcd_driver = {
+	.name		= (char *) driver_name,
+	.bus		= &platform_bus_type,
+	.probe		= dummy_hcd_probe,
+	.remove		= dummy_hcd_remove,
+	.suspend	= dummy_hcd_suspend,
+	.resume		= dummy_hcd_resume,
+};
+
 /*-------------------------------------------------------------------------*/
 
-static int dummy_pdev_detect (void)
-{
-	int			retval;
+/* These don't need to do anything because the pdev structures are
+ * statically allocated. */
+static void
+dummy_udc_release (struct device *dev) {}
 
-	retval = driver_register (&dummy_driver);
-	if (retval < 0)
-		return retval;
+static void
+dummy_hcd_release (struct device *dev) {}
 
-	the_pdev.name = "hc";
-	the_pdev.dev.driver = &dummy_driver;
-	the_pdev.dev.release = dummy_pdev_release;
+static struct platform_device		the_udc_pdev = {
+	.name		= (char *) gadget_name,
+	.id		= -1,
+	.dev		= {
+		.release	= dummy_udc_release,
+	},
+};
 
-	retval = platform_device_register (&the_pdev);
-	if (retval < 0)
-		driver_unregister (&dummy_driver);
-	return retval;
-}
-
-static void dummy_pdev_remove (void)
-{
-	platform_device_unregister (&the_pdev);
-	driver_unregister (&dummy_driver);
-}
-
-/*-------------------------------------------------------------------------*/
+static struct platform_device		the_hcd_pdev = {
+	.name		= (char *) driver_name,
+	.id		= -1,
+	.dev		= {
+		.release	= dummy_hcd_release,
+	},
+};
 
 static int __init init (void)
 {
@@ -1777,17 +2020,39 @@
 
 	if (usb_disabled ())
 		return -ENODEV;
-	if ((retval = dummy_pdev_detect ()) != 0)
+
+	retval = driver_register (&dummy_hcd_driver);
+	if (retval < 0)
 		return retval;
-	if ((retval = dummy_probe (&the_pdev.dev)) != 0)
-		dummy_pdev_remove ();
+
+	retval = driver_register (&dummy_udc_driver);
+	if (retval < 0)
+		goto err_register_udc_driver;
+
+	retval = platform_device_register (&the_hcd_pdev);
+	if (retval < 0)
+		goto err_register_hcd;
+
+	retval = platform_device_register (&the_udc_pdev);
+	if (retval < 0)
+		goto err_register_udc;
+	return retval;
+
+err_register_udc:
+	platform_device_unregister (&the_hcd_pdev);
+err_register_hcd:
+	driver_unregister (&dummy_udc_driver);
+err_register_udc_driver:
+	driver_unregister (&dummy_hcd_driver);
 	return retval;
 }
 module_init (init);
 
 static void __exit cleanup (void)
 {
-	dummy_remove (&the_pdev.dev);
-	dummy_pdev_remove ();
+	platform_device_unregister (&the_udc_pdev);
+	platform_device_unregister (&the_hcd_pdev);
+	driver_unregister (&dummy_udc_driver);
+	driver_unregister (&dummy_hcd_driver);
 }
 module_exit (cleanup);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 3f783cb..5bb53ae 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -84,18 +84,19 @@
  */
 
 #define DRIVER_DESC		"Ethernet Gadget"
-#define DRIVER_VERSION		"Equinox 2004"
+#define DRIVER_VERSION		"May Day 2005"
 
 static const char shortname [] = "ether";
 static const char driver_desc [] = DRIVER_DESC;
 
 #define RX_EXTRA	20		/* guard against rx overflows */
 
-#ifdef	CONFIG_USB_ETH_RNDIS
 #include "rndis.h"
-#else
-#define rndis_init() 0
-#define rndis_exit() do{}while(0)
+
+#ifndef	CONFIG_USB_ETH_RNDIS
+#define rndis_uninit(x)		do{}while(0)
+#define rndis_deregister(c)	do{}while(0)
+#define rndis_exit()		do{}while(0)
 #endif
 
 /* CDC and RNDIS support the same host-chosen outgoing packet filters. */
@@ -140,9 +141,6 @@
  * It also ASSUMES a self-powered device, without remote wakeup,
  * although remote wakeup support would make sense.
  */
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_STATUS_NAME;
 
 /*-------------------------------------------------------------------------*/
 
@@ -312,6 +310,7 @@
 #define	FS_BPS		(19 *  64 * 1 * 1000 * 8)
 
 #ifdef CONFIG_USB_GADGET_DUALSPEED
+#define	DEVSPEED	USB_SPEED_HIGH
 
 static unsigned qmult = 5;
 module_param (qmult, uint, S_IRUGO|S_IWUSR);
@@ -330,6 +329,8 @@
 }
 
 #else	/* full speed (low speed doesn't do bulk) */
+#define	DEVSPEED	USB_SPEED_FULL
+
 #define qlen(gadget) DEFAULT_QLEN
 
 static inline int BITRATE(struct usb_gadget *g)
@@ -395,7 +396,8 @@
 #define STRING_SUBSET			8
 #define STRING_RNDIS			9
 
-#define USB_BUFSIZ	256		/* holds our biggest descriptor */
+/* holds our biggest descriptor (or RNDIS response) */
+#define USB_BUFSIZ	256
 
 /*
  * This device advertises one configuration, eth_config, unless RNDIS
@@ -538,7 +540,7 @@
 	.bDataInterface = 	0x01,
 };
 
-static struct usb_cdc_acm_descriptor acm_descriptor = {
+static const struct usb_cdc_acm_descriptor acm_descriptor = {
 	.bLength =  		sizeof acm_descriptor,
 	.bDescriptorType = 	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
@@ -846,7 +848,7 @@
 #else
 
 /* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+#define ep_desc(g,hs,fs) (((void)(g)), (fs))
 
 static inline void __init hs_subset_descriptors(void)
 {
@@ -946,10 +948,31 @@
 static void eth_start (struct eth_dev *dev, int gfp_flags);
 static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags);
 
-#ifdef	DEV_CONFIG_CDC
-static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
+static int
+set_ether_config (struct eth_dev *dev, int gfp_flags)
 {
-	const struct usb_endpoint_descriptor	*d;
+	int					result = 0;
+	struct usb_gadget			*gadget = dev->gadget;
+
+	/* status endpoint used for RNDIS and (optionally) CDC */
+	if (!subset_active(dev) && dev->status_ep) {
+		dev->status = ep_desc (gadget, &hs_status_desc,
+						&fs_status_desc);
+		dev->status_ep->driver_data = dev;
+
+		result = usb_ep_enable (dev->status_ep, dev->status);
+		if (result != 0) {
+			DEBUG (dev, "enable %s --> %d\n", 
+				dev->status_ep->name, result);
+			goto done;
+		}
+	}
+
+	dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+	dev->in_ep->driver_data = dev;
+
+	dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+	dev->out_ep->driver_data = dev;
 
 	/* With CDC,  the host isn't allowed to use these two data
 	 * endpoints in the default altsetting for the interface.
@@ -959,135 +982,33 @@
 	 * a side effect of setting a packet filter.  Deactivation is
 	 * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
 	 */
-
-	/* one endpoint writes data back IN to the host */
-	if (strcmp (ep->name, EP_IN_NAME) == 0) {
-		d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
-		ep->driver_data = dev;
-		dev->in = d;
-
-	/* one endpoint just reads OUT packets */
-	} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-		d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
-		ep->driver_data = dev;
-		dev->out = d;
-
-	/* optional status/notification endpoint */
-	} else if (EP_STATUS_NAME &&
-			strcmp (ep->name, EP_STATUS_NAME) == 0) {
-		int			result;
-
-		d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc);
-		result = usb_ep_enable (ep, d);
-		if (result < 0)
-			return result;
-
-		ep->driver_data = dev;
-		dev->status = d;
-	}
-	return 0;
-}
-#endif
-
-#if	defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
-{
-	int					result;
-	const struct usb_endpoint_descriptor	*d;
-
-	/* CDC subset is simpler:  if the device is there,
-	 * it's live with rx and tx endpoints.
-	 *
-	 * Do this as a shortcut for RNDIS too.
-	 */
-
-	/* one endpoint writes data back IN to the host */
-	if (strcmp (ep->name, EP_IN_NAME) == 0) {
-		d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
-		result = usb_ep_enable (ep, d);
-		if (result < 0)
-			return result;
-
-		ep->driver_data = dev;
-		dev->in = d;
-
-	/* one endpoint just reads OUT packets */
-	} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-		d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
-		result = usb_ep_enable (ep, d);
-		if (result < 0)
-			return result;
-
-		ep->driver_data = dev;
-		dev->out = d;
-	}
-
-	return 0;
-}
-#endif
-
-static int
-set_ether_config (struct eth_dev *dev, int gfp_flags)
-{
-	int			result = 0;
-	struct usb_ep		*ep;
-	struct usb_gadget	*gadget = dev->gadget;
-
-	gadget_for_each_ep (ep, gadget) {
-#ifdef	DEV_CONFIG_CDC
-		if (!dev->rndis && dev->cdc) {
-			result = ether_alt_ep_setup (dev, ep);
-			if (result == 0)
-				continue;
-		}
-#endif
-
-#ifdef	CONFIG_USB_ETH_RNDIS
-		if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) {
-			const struct usb_endpoint_descriptor	*d;
-			d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
-			result = usb_ep_enable (ep, d);
-			if (result == 0) {
-				ep->driver_data = dev;
-				dev->status = d;
-				continue;
-			}
-		} else
-#endif
-
-		{
-#if	defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-			result = ether_ep_setup (dev, ep);
-			if (result == 0)
-				continue;
-#endif
+	if (!cdc_active(dev)) {
+		result = usb_ep_enable (dev->in_ep, dev->in);
+		if (result != 0) {
+			DEBUG(dev, "enable %s --> %d\n", 
+				dev->in_ep->name, result);
+			goto done;
 		}
 
-		/* stop on error */
-		ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
-		break;
+		result = usb_ep_enable (dev->out_ep, dev->out);
+		if (result != 0) {
+			DEBUG (dev, "enable %s --> %d\n", 
+				dev->in_ep->name, result);
+			goto done;
+		}
 	}
-	if (!result && (!dev->in_ep || !dev->out_ep))
-		result = -ENODEV;
 
+done:
 	if (result == 0)
 		result = alloc_requests (dev, qlen (gadget), gfp_flags);
 
 	/* on error, disable any endpoints  */
 	if (result < 0) {
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-		if (dev->status)
+		if (!subset_active(dev))
 			(void) usb_ep_disable (dev->status_ep);
-#endif
 		dev->status = NULL;
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-		if (dev->rndis || !dev->cdc) {
-			if (dev->in)
-				(void) usb_ep_disable (dev->in_ep);
-			if (dev->out)
-				(void) usb_ep_disable (dev->out_ep);
-		}
-#endif
+		(void) usb_ep_disable (dev->in_ep);
+		(void) usb_ep_disable (dev->out_ep);
 		dev->in = NULL;
 		dev->out = NULL;
 	} else
@@ -1095,8 +1016,7 @@
 	/* activate non-CDC configs right away
 	 * this isn't strictly according to the RNDIS spec
 	 */
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-	if (dev->rndis || !dev->cdc) {
+	if (!cdc_active (dev)) {
 		netif_carrier_on (dev->net);
 		if (netif_running (dev->net)) {
 			spin_unlock (&dev->lock);
@@ -1104,7 +1024,6 @@
 			spin_lock (&dev->lock);
 		}
 	}
-#endif
 
 	if (result == 0)
 		DEBUG (dev, "qlen %d\n", qlen (gadget));
@@ -1124,6 +1043,7 @@
 
 	netif_stop_queue (dev->net);
 	netif_carrier_off (dev->net);
+	rndis_uninit(dev->rndis_config);
 
 	/* disable endpoints, forcing (synchronous) completion of
 	 * pending i/o.  then free the requests.
@@ -1150,6 +1070,8 @@
 	if (dev->status) {
 		usb_ep_disable (dev->status_ep);
 	}
+	dev->rndis = 0;
+	dev->cdc_filter = 0;
 	dev->config = 0;
 }
 
@@ -1162,9 +1084,6 @@
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
 
-	if (number == dev->config)
-		return 0;
-
 	if (gadget_is_sa1100 (gadget)
 			&& dev->config
 			&& atomic_read (&dev->tx_qlen) != 0) {
@@ -1174,12 +1093,8 @@
 	}
 	eth_reset_config (dev);
 
-	/* default:  pass all packets, no multicast filtering */
-	dev->cdc_filter = DEFAULT_FILTER;
-
 	switch (number) {
 	case DEV_CONFIG_VALUE:
-		dev->rndis = 0;
 		result = set_ether_config (dev, gfp_flags);
 		break;
 #ifdef	CONFIG_USB_ETH_RNDIS
@@ -1218,9 +1133,9 @@
 		dev->config = number;
 		INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
 				speed, number, power, driver_desc,
-				dev->rndis
+				rndis_active(dev)
 					? "RNDIS"
-					: (dev->cdc
+					: (cdc_active(dev)
 						? "CDC Ethernet"
 						: "CDC Ethernet Subset"));
 	}
@@ -1231,6 +1146,13 @@
 
 #ifdef	DEV_CONFIG_CDC
 
+/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+ * only to notify the host about link status changes (which we support) or
+ * report completion of some encapsulated command (as used in RNDIS).  Since
+ * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+ * command mechanism; and only one status request is ever queued.
+ */
+
 static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	struct usb_cdc_notification	*event = req->buf;
@@ -1259,7 +1181,7 @@
 	} else if (value != -ECONNRESET)
 		DEBUG (dev, "event %02x --> %d\n",
 			event->bNotificationType, value);
-	event->bmRequestType = 0xff;
+	req->context = NULL;
 }
 
 static void issue_start_status (struct eth_dev *dev)
@@ -1276,6 +1198,8 @@
 	 * a "cancel the whole queue" primitive since any
 	 * unlink-one primitive has way too many error modes.
 	 * here, we "know" toggle is already clear...
+	 *
+	 * FIXME iff req->context != null just dequeue it
 	 */
 	usb_ep_disable (dev->status_ep);
 	usb_ep_enable (dev->status_ep, dev->status);
@@ -1292,6 +1216,8 @@
 
 	req->length = sizeof *event;
 	req->complete = eth_status_complete;
+	req->context = dev;
+
 	value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
 	if (value < 0)
 		DEBUG (dev, "status buf queue --> %d\n", value);
@@ -1351,9 +1277,9 @@
 	struct eth_dev		*dev = get_gadget_data (gadget);
 	struct usb_request	*req = dev->req;
 	int			value = -EOPNOTSUPP;
-	u16			wIndex = (__force u16) ctrl->wIndex;
-	u16			wValue = (__force u16) ctrl->wValue;
-	u16			wLength = (__force u16) ctrl->wLength;
+	u16			wIndex = le16_to_cpu(ctrl->wIndex);
+	u16			wValue = le16_to_cpu(ctrl->wValue);
+	u16			wLength = le16_to_cpu(ctrl->wLength);
 
 	/* descriptors just go into the pre-allocated ep0 buffer,
 	 * while config change events may enable network traffic.
@@ -1424,7 +1350,7 @@
 				|| !dev->config
 				|| wIndex > 1)
 			break;
-		if (!dev->cdc && wIndex != 0)
+		if (!cdc_active(dev) && wIndex != 0)
 			break;
 		spin_lock (&dev->lock);
 
@@ -1456,9 +1382,11 @@
 
 			/* CDC requires the data transfers not be done from
 			 * the default interface setting ... also, setting
-			 * the non-default interface clears filters etc.
+			 * the non-default interface resets filters etc.
 			 */
 			if (wValue == 1) {
+				if (!cdc_active (dev))
+					break;
 				usb_ep_enable (dev->in_ep, dev->in);
 				usb_ep_enable (dev->out_ep, dev->out);
 				dev->cdc_filter = DEFAULT_FILTER;
@@ -1492,11 +1420,11 @@
 				|| !dev->config
 				|| wIndex > 1)
 			break;
-		if (!(dev->cdc || dev->rndis) && wIndex != 0)
+		if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
 			break;
 
 		/* for CDC, iff carrier is on, data interface is active. */
-		if (dev->rndis || wIndex != 1)
+		if (rndis_active(dev) || wIndex != 1)
 			*(u8 *)req->buf = 0;
 		else
 			*(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
@@ -1509,8 +1437,7 @@
 		 * wValue = packet filter bitmap
 		 */
 		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
-				|| !dev->cdc
-				|| dev->rndis
+				|| !cdc_active(dev)
 				|| wLength != 0
 				|| wIndex > 1)
 			break;
@@ -1534,7 +1461,7 @@
 	 */
 	case USB_CDC_SEND_ENCAPSULATED_COMMAND:
 		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
-				|| !dev->rndis
+				|| !rndis_active(dev)
 				|| wLength > USB_BUFSIZ
 				|| wValue
 				|| rndis_control_intf.bInterfaceNumber
@@ -1549,7 +1476,7 @@
 	case USB_CDC_GET_ENCAPSULATED_RESPONSE:
 		if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
 					== ctrl->bRequestType
-				&& dev->rndis
+				&& rndis_active(dev)
 				// && wLength >= 0x0400
 				&& !wValue
 				&& rndis_control_intf.bInterfaceNumber
@@ -1688,10 +1615,8 @@
 	 */
 	size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
 	size += dev->out_ep->maxpacket - 1;
-#ifdef CONFIG_USB_ETH_RNDIS
-	if (dev->rndis)
+	if (rndis_active(dev))
 		size += sizeof (struct rndis_packet_msg_type);
-#endif	
 	size -= size % dev->out_ep->maxpacket;
 
 	if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
@@ -1735,11 +1660,9 @@
 	/* normal completion */
 	case 0:
 		skb_put (skb, req->actual);
-#ifdef CONFIG_USB_ETH_RNDIS
 		/* we know MaxPacketsPerTransfer == 1 here */
-		if (dev->rndis)
+		if (rndis_active(dev))
 			status = rndis_rm_hdr (skb);
-#endif
 		if (status < 0
 				|| ETH_HLEN > skb->len
 				|| skb->len > ETH_FRAME_LEN) {
@@ -1859,8 +1782,6 @@
 	struct usb_request	*req;
 	unsigned long		flags;
 
-	clear_bit (WORK_RX_MEMORY, &dev->todo);
-
 	/* fill unused rxq slots with some skb */
 	spin_lock_irqsave (&dev->lock, flags);
 	while (!list_empty (&dev->rx_reqs)) {
@@ -1883,11 +1804,9 @@
 {
 	struct eth_dev		*dev = _dev;
 
-	if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
+	if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) {
 		if (netif_running (dev->net))
 			rx_fill (dev, GFP_KERNEL);
-		else
-			clear_bit (WORK_RX_MEMORY, &dev->todo);
 	}
 
 	if (dev->todo)
@@ -1971,8 +1890,7 @@
 	 * or the hardware can't use skb buffers.
 	 * or there's not enough space for any RNDIS headers we need
 	 */
-#ifdef CONFIG_USB_ETH_RNDIS
-	if (dev->rndis) {
+	if (rndis_active(dev)) {
 		struct sk_buff	*skb_rndis;
 
 		skb_rndis = skb_realloc_headroom (skb,
@@ -1985,7 +1903,6 @@
 		rndis_add_hdr (skb);
 		length = skb->len;
 	}
-#endif
 	req->buf = skb->data;
 	req->context = skb;
 	req->complete = tx_complete;
@@ -2018,9 +1935,7 @@
 	}
 
 	if (retval) {
-#ifdef CONFIG_USB_ETH_RNDIS
 drop:
-#endif
 		dev->stats.tx_dropped++;
 		dev_kfree_skb_any (skb);
 		spin_lock_irqsave (&dev->lock, flags);
@@ -2036,27 +1951,31 @@
 
 #ifdef CONFIG_USB_ETH_RNDIS
 
-static void rndis_send_media_state (struct eth_dev *dev, int connect)
-{
-	if (!dev)
-		return;
-	
-	if (connect) {
-		if (rndis_signal_connect (dev->rndis_config))
-			return;
-	} else {
-		if (rndis_signal_disconnect (dev->rndis_config))
-			return;
-	}
-}
+/* The interrupt endpoint is used in RNDIS to notify the host when messages
+ * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
+ * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
+ * REMOTE_NDIS_KEEPALIVE_MSG.
+ *
+ * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
+ * normally just one notification will be queued.
+ */
+
+static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned);
+static void eth_req_free (struct usb_ep *ep, struct usb_request *req);
 
 static void
 rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
 {
+	struct eth_dev          *dev = ep->driver_data;
+
 	if (req->status || req->actual != req->length)
-		DEBUG ((struct eth_dev *) ep->driver_data,
+		DEBUG (dev,
 			"rndis control ack complete --> %d, %d/%d\n",
 			req->status, req->actual, req->length);
+	req->context = NULL;
+
+	if (req != dev->stat_req)
+		eth_req_free(ep, req);
 }
 
 static int rndis_control_ack (struct net_device *net)
@@ -2071,11 +1990,19 @@
 		return -ENODEV;
 	}
 
+	/* in case queue length > 1 */
+	if (resp->context) {
+		resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);
+		if (!resp)
+			return -ENOMEM;
+	}
+
 	/* Send RNDIS RESPONSE_AVAILABLE notification;
 	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
 	 */
 	resp->length = 8;
 	resp->complete = rndis_control_ack_complete;
+	resp->context = dev;
 	
 	*((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
 	*((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
@@ -2089,6 +2016,10 @@
 	return 0;
 }
 
+#else
+
+#define	rndis_control_ack	NULL
+
 #endif	/* RNDIS */
 
 static void eth_start (struct eth_dev *dev, int gfp_flags)
@@ -2101,14 +2032,12 @@
 	/* and open the tx floodgates */ 
 	atomic_set (&dev->tx_qlen, 0);
 	netif_wake_queue (dev->net);
-#ifdef CONFIG_USB_ETH_RNDIS
-	if (dev->rndis) {
+	if (rndis_active(dev)) {
 		rndis_set_param_medium (dev->rndis_config,
 					NDIS_MEDIUM_802_3,
 					BITRATE(dev->gadget)/100);
-		rndis_send_media_state (dev, 1);
+		(void) rndis_signal_connect (dev->rndis_config);
 	}
-#endif	
 }
 
 static int eth_open (struct net_device *net)
@@ -2149,28 +2078,27 @@
 		}
 	}
 	
-#ifdef	CONFIG_USB_ETH_RNDIS
-	if (dev->rndis) {
+	if (rndis_active(dev)) {
 		rndis_set_param_medium (dev->rndis_config,
 					NDIS_MEDIUM_802_3, 0);
-		rndis_send_media_state (dev, 0);
+		(void) rndis_signal_disconnect (dev->rndis_config);
 	}
-#endif
 
 	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size)
+static struct usb_request *
+eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags)
 {
 	struct usb_request	*req;
 
-	req = usb_ep_alloc_request (ep, GFP_KERNEL);
+	req = usb_ep_alloc_request (ep, gfp_flags);
 	if (!req)
 		return NULL;
 
-	req->buf = kmalloc (size, GFP_KERNEL);
+	req->buf = kmalloc (size, gfp_flags);
 	if (!req->buf) {
 		usb_ep_free_request (ep, req);
 		req = NULL;
@@ -2192,10 +2120,8 @@
 	struct eth_dev		*dev = get_gadget_data (gadget);
 
 	DEBUG (dev, "unbind\n");
-#ifdef CONFIG_USB_ETH_RNDIS
 	rndis_deregister (dev->rndis_config);
 	rndis_exit ();
-#endif
 
 	/* we've already been disconnected ... no i/o is active */
 	if (dev->req) {
@@ -2368,13 +2294,11 @@
 			gadget->name);
 		return -ENODEV;
 	}
-	EP_IN_NAME = in_ep->name;
 	in_ep->driver_data = in_ep;	/* claim */
 	
 	out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	if (!out_ep)
 		goto autoconf_fail;
-	EP_OUT_NAME = out_ep->name;
 	out_ep->driver_data = out_ep;	/* claim */
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -2384,7 +2308,6 @@
 	if (cdc || rndis) {
 		status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
 		if (status_ep) {
-			EP_STATUS_NAME = status_ep->name;
 			status_ep->driver_data = status_ep;	/* claim */
 		} else if (rndis) {
 			dev_err (&gadget->dev,
@@ -2426,7 +2349,7 @@
 	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
 	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-	if (EP_STATUS_NAME)
+	if (status_ep)
 		hs_status_desc.bEndpointAddress =
 				fs_status_desc.bEndpointAddress;
 #endif
@@ -2499,20 +2422,23 @@
 	SET_ETHTOOL_OPS(net, &ops);
 
 	/* preallocate control message data and buffer */
-	dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ);
+	dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
 	if (!dev->req)
 		goto fail;
 	dev->req->complete = eth_setup_complete;
 
 	/* ... and maybe likewise for status transfer */
+#ifdef DEV_CONFIG_CDC
 	if (dev->status_ep) {
 		dev->stat_req = eth_req_alloc (dev->status_ep,
-					STATUS_BYTECOUNT);
+					STATUS_BYTECOUNT, GFP_KERNEL);
 		if (!dev->stat_req) {
 			eth_req_free (gadget->ep0, dev->req);
 			goto fail;
 		}
+		dev->stat_req->context = NULL;
 	}
+#endif
 
 	/* finish hookup to lower layer ... */
 	dev->gadget = gadget;
@@ -2526,16 +2452,16 @@
 	netif_stop_queue (dev->net);
 	netif_carrier_off (dev->net);
 
- 	// SET_NETDEV_DEV (dev->net, &gadget->dev);
+ 	SET_NETDEV_DEV (dev->net, &gadget->dev);
  	status = register_netdev (dev->net);
 	if (status < 0)
 		goto fail1;
 
 	INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
 	INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,
-		EP_OUT_NAME, EP_IN_NAME,
-		EP_STATUS_NAME ? " STATUS " : "",
-		EP_STATUS_NAME ? EP_STATUS_NAME : ""
+		out_ep->name, in_ep->name,
+		status_ep ? " STATUS " : "",
+		status_ep ? status_ep->name : ""
 		);
 	INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
 		net->dev_addr [0], net->dev_addr [1],
@@ -2548,7 +2474,6 @@
 			dev->host_mac [2], dev->host_mac [3],
 			dev->host_mac [4], dev->host_mac [5]);
 
-#ifdef	CONFIG_USB_ETH_RNDIS
 	if (rndis) {
 		u32	vendorID = 0;
 
@@ -2565,7 +2490,7 @@
 		/* these set up a lot of the OIDs that RNDIS needs */
 		rndis_set_host_mac (dev->rndis_config, dev->host_mac);
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
-					 &dev->stats))
+					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
 		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
 					    manufacturer))
@@ -2576,7 +2501,6 @@
 			goto fail0;
 		INFO (dev, "RNDIS ready\n");
 	}
-#endif	
 
 	return status;
 
@@ -2610,11 +2534,8 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver eth_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed		= USB_SPEED_HIGH,
-#else
-	.speed		= USB_SPEED_FULL,
-#endif
+	.speed		= DEVSPEED,
+
 	.function	= (char *) driver_desc,
 	.bind		= eth_bind,
 	.unbind		= eth_unbind,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index a9be851..4f57085 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -81,6 +81,10 @@
  *	removable		Default false, boolean for removable media
  *	luns=N			Default N = number of filenames, number of
  *					LUNs to support
+ *	stall			Default determined according to the type of
+ *					USB device controller (usually true),
+ *					boolean to permit the driver to halt
+ *					bulk endpoints
  *	transport=XXX		Default BBB, transport name (CB, CBI, or BBB)
  *	protocol=YYY		Default SCSI, protocol name (RBC, 8020 or
  *					ATAPI, QIC, UFI, 8070, or SCSI;
@@ -91,14 +95,10 @@
  *	buflen=N		Default N=16384, buffer size used (will be
  *					rounded down to a multiple of
  *					PAGE_CACHE_SIZE)
- *	stall			Default determined according to the type of
- *					USB device controller (usually true),
- *					boolean to permit the driver to halt
- *					bulk endpoints
  *
  * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
- * "removable", and "luns" options are available; default values are used
- * for everything else.
+ * "removable", "luns", and "stall" options are available; default values
+ * are used for everything else.
  *
  * The pathnames of the backing files and the ro settings are available in
  * the attribute files "file" and "ro" in the lun<n> subdirectory of the
@@ -342,14 +342,15 @@
 	int		num_ros;
 	unsigned int	nluns;
 
+	int		removable;
+	int		can_stall;
+
 	char		*transport_parm;
 	char		*protocol_parm;
-	int		removable;
 	unsigned short	vendor;
 	unsigned short	product;
 	unsigned short	release;
 	unsigned int	buflen;
-	int		can_stall;
 
 	int		transport_type;
 	char		*transport_name;
@@ -360,11 +361,11 @@
 	.transport_parm		= "BBB",
 	.protocol_parm		= "SCSI",
 	.removable		= 0,
+	.can_stall		= 1,
 	.vendor			= DRIVER_VENDOR_ID,
 	.product		= DRIVER_PRODUCT_ID,
 	.release		= 0xffff,	// Use controller chip type
 	.buflen			= 16384,
-	.can_stall		= 1,
 	};
 
 
@@ -380,6 +381,9 @@
 module_param_named(removable, mod_data.removable, bool, S_IRUGO);
 MODULE_PARM_DESC(removable, "true to simulate removable media");
 
+module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
+MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+
 
 /* In the non-TEST version, only the module parameters listed above
  * are available. */
@@ -404,9 +408,6 @@
 module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
 MODULE_PARM_DESC(buflen, "I/O buffer size");
 
-module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
-MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
-
 #endif /* CONFIG_USB_FILE_STORAGE_TEST */
 
 
@@ -818,7 +819,7 @@
 	buf[0] = val >> 24;
 	buf[1] = val >> 16;
 	buf[2] = val >> 8;
-	buf[3] = val;
+	buf[3] = val & 0xff;
 }
 
 
@@ -1276,8 +1277,8 @@
 {
 	struct usb_request	*req = fsg->ep0req;
 	int			value = -EOPNOTSUPP;
-	u16			w_index = ctrl->wIndex;
-	u16			w_length = ctrl->wLength;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
 
 	if (!fsg->config)
 		return value;
@@ -1312,7 +1313,7 @@
 			}
 			VDBG(fsg, "get max LUN\n");
 			*(u8 *) req->buf = fsg->nluns - 1;
-			value = min(w_length, (u16) 1);
+			value = 1;
 			break;
 		}
 	}
@@ -1344,7 +1345,7 @@
 			"unknown class-specific control req "
 			"%02x.%02x v%04x i%04x l%u\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			ctrl->wValue, w_index, w_length);
+			le16_to_cpu(ctrl->wValue), w_index, w_length);
 	return value;
 }
 
@@ -1358,9 +1359,8 @@
 {
 	struct usb_request	*req = fsg->ep0req;
 	int			value = -EOPNOTSUPP;
-	u16			w_index = ctrl->wIndex;
-	u16			w_value = ctrl->wValue;
-	u16			w_length = ctrl->wLength;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
 
 	/* Usually this just stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will also reconfigure hardware. */
@@ -1374,7 +1374,7 @@
 
 		case USB_DT_DEVICE:
 			VDBG(fsg, "get device descriptor\n");
-			value = min(w_length, (u16) sizeof device_desc);
+			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -1382,7 +1382,7 @@
 			VDBG(fsg, "get device qualifier\n");
 			if (!fsg->gadget->is_dualspeed)
 				break;
-			value = min(w_length, (u16) sizeof dev_qualifier);
+			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
 			break;
 
@@ -1401,8 +1401,6 @@
 					req->buf,
 					w_value >> 8,
 					w_value & 0xff);
-			if (value >= 0)
-				value = min(w_length, (u16) value);
 			break;
 
 		case USB_DT_STRING:
@@ -1411,8 +1409,6 @@
 			/* wIndex == language code */
 			value = usb_gadget_get_string(&stringtab,
 					w_value & 0xff, req->buf);
-			if (value >= 0)
-				value = min(w_length, (u16) value);
 			break;
 		}
 		break;
@@ -1438,7 +1434,7 @@
 			break;
 		VDBG(fsg, "get configuration\n");
 		*(u8 *) req->buf = fsg->config;
-		value = min(w_length, (u16) 1);
+		value = 1;
 		break;
 
 	case USB_REQ_SET_INTERFACE:
@@ -1466,14 +1462,14 @@
 		}
 		VDBG(fsg, "get interface\n");
 		*(u8 *) req->buf = 0;
-		value = min(w_length, (u16) 1);
+		value = 1;
 		break;
 
 	default:
 		VDBG(fsg,
 			"unknown control req %02x.%02x v%04x i%04x l%u\n",
 			ctrl->bRequestType, ctrl->bRequest,
-			w_value, w_index, w_length);
+			w_value, w_index, le16_to_cpu(ctrl->wLength));
 	}
 
 	return value;
@@ -1485,6 +1481,7 @@
 {
 	struct fsg_dev		*fsg = get_gadget_data(gadget);
 	int			rc;
+	int			w_length = le16_to_cpu(ctrl->wLength);
 
 	++fsg->ep0_req_tag;		// Record arrival of a new request
 	fsg->ep0req->context = NULL;
@@ -1498,9 +1495,9 @@
 
 	/* Respond with data/status or defer until later? */
 	if (rc >= 0 && rc != DELAYED_STATUS) {
+		rc = min(rc, w_length);
 		fsg->ep0req->length = rc;
-		fsg->ep0req->zero = (rc < ctrl->wLength &&
-				(rc % gadget->ep0->maxpacket) == 0);
+		fsg->ep0req->zero = rc < w_length;
 		fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
 				"ep0-in" : "ep0-out");
 		rc = ep0_queue(fsg);
@@ -2660,7 +2657,7 @@
 		}
 	}
 
-	/* Check that the LUN values are oonsistent */
+	/* Check that the LUN values are consistent */
 	if (transport_is_bbb()) {
 		if (fsg->lun != lun)
 			DBG(fsg, "using LUN %d from CBW, "
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 005db7c..ed773a9 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -70,7 +70,7 @@
  * seem to behave quite as expected.  Used by default.
  *
  * OUT dma documents design problems handling the common "short packet"
- * transfer termination policy; it couldn't enabled by default, even
+ * transfer termination policy; it couldn't be enabled by default, even
  * if the OUT-dma abort problems had a resolution.
  */
 static unsigned use_dma = 1;
@@ -313,7 +313,7 @@
 #if	defined(CONFIG_X86)
 #define USE_KMALLOC
 
-#elif	defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif	defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
 #define USE_KMALLOC
 
 #elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -1524,9 +1524,12 @@
 	/* read SETUP packet and enter DATA stage */
 	ctrl.bRequestType = readl(&regs->bRequestType);
 	ctrl.bRequest = readl(&regs->bRequest);
-	ctrl.wValue  = (readl(&regs->wValueH)  << 8) | readl(&regs->wValueL);
-	ctrl.wIndex  = (readl(&regs->wIndexH)  << 8) | readl(&regs->wIndexL);
-	ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
+	ctrl.wValue  = cpu_to_le16((readl(&regs->wValueH)  << 8)
+					| readl(&regs->wValueL));
+	ctrl.wIndex  = cpu_to_le16((readl(&regs->wIndexH)  << 8)
+					| readl(&regs->wIndexL));
+	ctrl.wLength = cpu_to_le16((readl(&regs->wLengthH) << 8)
+					| readl(&regs->wLengthL));
 	writel(0, &regs->SetupRecv);
 
 	nuke(&dev->ep[0], 0);
@@ -1548,18 +1551,20 @@
 		case USB_REQ_CLEAR_FEATURE:
 			switch (ctrl.bRequestType) {
 			case USB_RECIP_ENDPOINT:
-				tmp = ctrl.wIndex & 0x0f;
+				tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
 				/* active endpoint */
 				if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
 					goto stall;
-				if (ctrl.wIndex & USB_DIR_IN) {
+				if (ctrl.wIndex & __constant_cpu_to_le16(
+						USB_DIR_IN)) {
 					if (!dev->ep[tmp].is_in)
 						goto stall;
 				} else {
 					if (dev->ep[tmp].is_in)
 						goto stall;
 				}
-				if (ctrl.wValue != USB_ENDPOINT_HALT)
+				if (ctrl.wValue != __constant_cpu_to_le16(
+						USB_ENDPOINT_HALT))
 					goto stall;
 				if (tmp)
 					goku_clear_halt(&dev->ep[tmp]);
@@ -1571,7 +1576,7 @@
 				return;
 			case USB_RECIP_DEVICE:
 				/* device remote wakeup: always clear */
-				if (ctrl.wValue != 1)
+				if (ctrl.wValue != __constant_cpu_to_le16(1))
 					goto stall;
 				VDBG(dev, "clear dev remote wakeup\n");
 				goto succeed;
@@ -1589,14 +1594,15 @@
 #ifdef USB_TRACE
 	VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
 		ctrl.bRequestType, ctrl.bRequest,
-		ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+		le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
+		le16_to_cpu(ctrl.wLength));
 #endif
 
 	/* hw wants to know when we're configured (or not) */
 	dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
 				&& ctrl.bRequestType == USB_RECIP_DEVICE);
 	if (unlikely(dev->req_config))
-		dev->configured = (ctrl.wValue != 0);
+		dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0));
 
 	/* delegate everything to the gadget driver.
 	 * it may respond after this irq handler returns.
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 1e5e6dd..0208153 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -417,8 +417,8 @@
 		goto free1;
 
 	value = ep_io (data, kbuf, len);
-	VDEBUG (data->dev, "%s read %d OUT, status %d\n",
-		data->name, len, value);
+	VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
+		data->name, len, (int) value);
 	if (value >= 0 && copy_to_user (buf, kbuf, value))
 		value = -EFAULT;
 
@@ -465,8 +465,8 @@
 	}
 
 	value = ep_io (data, kbuf, len);
-	VDEBUG (data->dev, "%s write %d IN, status %d\n",
-		data->name, len, value);
+	VDEBUG (data->dev, "%s write %zu IN, status %d\n",
+		data->name, len, (int) value);
 free1:
 	up (&data->lock);
 	kfree (kbuf);
@@ -1318,8 +1318,8 @@
 	struct usb_request		*req = dev->req;
 	int				value = -EOPNOTSUPP;
 	struct usb_gadgetfs_event	*event;
-	u16				w_value = ctrl->wValue;
-	u16				w_length = ctrl->wLength;
+	u16				w_value = le16_to_cpu(ctrl->wValue);
+	u16				w_length = le16_to_cpu(ctrl->wLength);
 
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h
index c553bbf..09e3ee4 100644
--- a/drivers/usb/gadget/ndis.h
+++ b/drivers/usb/gadget/ndis.h
@@ -47,17 +47,17 @@
 #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
 
 struct NDIS_PNP_CAPABILITIES {
-	u32					Flags;
+	__le32					Flags;
 	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
 };
 
 struct NDIS_PM_PACKET_PATTERN {
-	u32	Priority;
-	u32	Reserved;
-	u32	MaskSize;
-	u32	PatternOffset;
-	u32	PatternSize;
-	u32	PatternFlags;
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
 };
 
 
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index e47e398..13a3dbc 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -448,7 +448,7 @@
 #elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #define USE_KMALLOC
 
-#elif	defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif	defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
 #define USE_KMALLOC
 
 /* FIXME there are other cases, including an x86-64 one ...  */
@@ -1113,7 +1113,7 @@
 		if (ep->in_fifo_validate)
 			dmactl |= (1 << DMA_FIFO_VALIDATE);
 		list_for_each_entry (entry, &ep->queue, queue) {
-			u32		dmacount;
+			__le32		dmacount;
 
 			if (entry == req)
 				continue;
@@ -1238,7 +1238,7 @@
 				&ep->dma->dmadesc);
 			if (req->td->dmacount & dma_done_ie)
 				writel (readl (&ep->dma->dmacount)
-						| dma_done_ie,
+						| le32_to_cpu(dma_done_ie),
 					&ep->dma->dmacount);
 		} else {
 			struct net2280_request	*prev;
@@ -1779,6 +1779,9 @@
 	list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
 }
 
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
 /**
  * net2280_set_fifo_mode - change allocation of fifo buffers
  * @gadget: access to the net2280 device that will be updated
@@ -2382,9 +2385,9 @@
 		cpu_to_le32s (&u.raw [0]);
 		cpu_to_le32s (&u.raw [1]);
 
-		le16_to_cpus (&u.r.wValue);
-		le16_to_cpus (&u.r.wIndex);
-		le16_to_cpus (&u.r.wLength);
+#define	w_value		le16_to_cpup (&u.r.wValue)
+#define	w_index		le16_to_cpup (&u.r.wIndex)
+#define	w_length	le16_to_cpup (&u.r.wLength)
 
 		/* ack the irq */
 		writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@@ -2413,25 +2416,25 @@
 		switch (u.r.bRequest) {
 		case USB_REQ_GET_STATUS: {
 			struct net2280_ep	*e;
-			u16			status;
+			__le32			status;
 
 			/* hw handles device and interface status */
 			if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
 				goto delegate;
-			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
-					|| u.r.wLength > 2)
+			if ((e = get_ep_by_addr (dev, w_index)) == 0
+					|| w_length > 2)
 				goto do_stall;
 
 			if (readl (&e->regs->ep_rsp)
 					& (1 << SET_ENDPOINT_HALT))
-				status = __constant_cpu_to_le16 (1);
+				status = __constant_cpu_to_le32 (1);
 			else
-				status = __constant_cpu_to_le16 (0);
+				status = __constant_cpu_to_le32 (0);
 
 			/* don't bother with a request object! */
 			writel (0, &dev->epregs [0].ep_irqenb);
-			set_fifo_bytecount (ep, u.r.wLength);
-			writel (status, &dev->epregs [0].ep_data);
+			set_fifo_bytecount (ep, w_length);
+			writel ((__force u32)status, &dev->epregs [0].ep_data);
 			allow_status (ep);
 			VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);
 			goto next_endpoints;
@@ -2443,10 +2446,10 @@
 			/* hw handles device features */
 			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
 				goto delegate;
-			if (u.r.wValue != USB_ENDPOINT_HALT
-					|| u.r.wLength != 0)
+			if (w_value != USB_ENDPOINT_HALT
+					|| w_length != 0)
 				goto do_stall;
-			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+			if ((e = get_ep_by_addr (dev, w_index)) == 0)
 				goto do_stall;
 			clear_halt (e);
 			allow_status (ep);
@@ -2460,10 +2463,10 @@
 			/* hw handles device features */
 			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
 				goto delegate;
-			if (u.r.wValue != USB_ENDPOINT_HALT
-					|| u.r.wLength != 0)
+			if (w_value != USB_ENDPOINT_HALT
+					|| w_length != 0)
 				goto do_stall;
-			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+			if ((e = get_ep_by_addr (dev, w_index)) == 0)
 				goto do_stall;
 			set_halt (e);
 			allow_status (ep);
@@ -2473,10 +2476,10 @@
 			break;
 		default:
 delegate:
-			VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+			VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
 				"ep_cfg %08x\n",
 				u.r.bRequestType, u.r.bRequest,
-				u.r.wValue, u.r.wIndex,
+				w_value, w_index, w_length,
 				readl (&ep->regs->ep_cfg));
 			spin_unlock (&dev->lock);
 			tmp = dev->driver->setup (&dev->gadget, &u.r);
@@ -2497,6 +2500,10 @@
 		 */
 	}
 
+#undef	w_value
+#undef	w_index
+#undef	w_length
+
 next_endpoints:
 	/* endpoint data irq ? */
 	scratch = stat & 0x7f;
@@ -2653,7 +2660,7 @@
 				restart_dma (ep);
 			else if (ep->is_in && use_dma_chaining) {
 				struct net2280_request	*req;
-				u32			dmacount;
+				__le32			dmacount;
 
 				/* the descriptor at the head of the chain
 				 * may still have VALID_BIT clear; that's
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 98cbcbc..a2b812a 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -52,7 +52,6 @@
 #include <asm/mach-types.h>
 
 #include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 
 #include "omap_udc.h"
@@ -167,7 +166,7 @@
 	maxp = le16_to_cpu (desc->wMaxPacketSize);
 	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
 				&& maxp != ep->maxpacket)
-			|| desc->wMaxPacketSize > ep->maxpacket
+			|| le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
 			|| !desc->wMaxPacketSize) {
 		DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
 		return -ERANGE;
@@ -214,7 +213,7 @@
 	ep->has_dma = 0;
 	ep->lch = -1;
 	use_ep(ep, UDC_EP_SEL);
-	UDC_CTRL_REG = UDC_RESET_EP;
+	UDC_CTRL_REG = udc->clr_halt;
 	ep->ackwait = 0;
 	deselect_ep();
 
@@ -253,7 +252,7 @@
 	}
 
 	spin_lock_irqsave(&ep->udc->lock, flags);
-	ep->desc = 0;
+	ep->desc = NULL;
 	nuke (ep, -ESHUTDOWN);
 	ep->ep.maxpacket = ep->maxpacket;
 	ep->has_dma = 0;
@@ -388,8 +387,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define	FIFO_FULL	(UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
-#define	FIFO_UNWRITABLE	(UDC_EP_HALTED | FIFO_FULL)
+#define UDC_FIFO_FULL		(UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
+#define UDC_FIFO_UNWRITABLE	(UDC_EP_HALTED | UDC_FIFO_FULL)
 
 #define FIFO_EMPTY	(UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
 #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
@@ -433,7 +432,7 @@
 
 	/* PIO-IN isn't double buffered except for iso */
 	ep_stat = UDC_STAT_FLG_REG;
-	if (ep_stat & FIFO_UNWRITABLE)
+	if (ep_stat & UDC_FIFO_UNWRITABLE)
 		return 0;
 
 	count = ep->ep.maxpacket;
@@ -504,7 +503,7 @@
 		if (ep_stat & UDC_EP_HALTED)
 			break;
 
-		if (ep_stat & FIFO_FULL)
+		if (ep_stat & UDC_FIFO_FULL)
 			avail = ep->ep.maxpacket;
 		else  {
 			avail = UDC_RXFSTAT_REG;
@@ -538,6 +537,32 @@
 
 /*-------------------------------------------------------------------------*/
 
+static inline dma_addr_t dma_csac(unsigned lch)
+{
+	dma_addr_t	csac;
+
+	/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+	 * read before the DMA controller finished disabling the channel.
+	 */
+	csac = omap_readw(OMAP_DMA_CSAC(lch));
+	if (csac == 0)
+		csac = omap_readw(OMAP_DMA_CSAC(lch));
+	return csac;
+}
+
+static inline dma_addr_t dma_cdac(unsigned lch)
+{
+	dma_addr_t	cdac;
+
+	/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+	 * read before the DMA controller finished disabling the channel.
+	 */
+	cdac = omap_readw(OMAP_DMA_CDAC(lch));
+	if (cdac == 0)
+		cdac = omap_readw(OMAP_DMA_CDAC(lch));
+	return cdac;
+}
+
 static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
 {
 	dma_addr_t	end;
@@ -548,7 +573,7 @@
 	if (cpu_is_omap15xx())
 		return 0;
 
-	end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+	end = dma_csac(ep->lch);
 	if (end == ep->dma_counter)
 		return 0;
 
@@ -559,14 +584,14 @@
 }
 
 #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
-		? OMAP_DMA_CSAC(x) /* really: CPC */ \
-		: OMAP_DMA_CDAC(x))
+		? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
+		: dma_cdac(x))
 
 static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
 {
 	dma_addr_t	end;
 
-	end = omap_readw(DMA_DEST_LAST(ep->lch));
+	end = DMA_DEST_LAST(ep->lch);
 	if (end == ep->dma_counter)
 		return 0;
 
@@ -593,7 +618,7 @@
 				: OMAP_DMA_SYNC_ELEMENT;
 
 	/* measure length in either bytes or packets */
-	if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+	if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
 			|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
 		txdma_ctrl = UDC_TXN_EOT | length;
 		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
@@ -602,15 +627,15 @@
 		length = min(length / ep->maxpacket,
 				(unsigned) UDC_TXN_TSC + 1);
  		txdma_ctrl = length;
-		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-				ep->ep.maxpacket, length, sync_mode);
+		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+				ep->ep.maxpacket >> 1, length, sync_mode);
 		length *= ep->maxpacket;
 	}
 	omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
 		OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
 
 	omap_start_dma(ep->lch);
-	ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
+	ep->dma_counter = dma_csac(ep->lch);
 	UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
 	UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
 	req->dma_bytes = length;
@@ -650,12 +675,12 @@
 	packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
 	packets = min(packets, (unsigned)UDC_RXN_TC + 1);
 	req->dma_bytes = packets * ep->ep.maxpacket;
-	omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-			ep->ep.maxpacket, packets,
+	omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+			ep->ep.maxpacket >> 1, packets,
 			OMAP_DMA_SYNC_ELEMENT);
 	omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
 		OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
-	ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
+	ep->dma_counter = DMA_DEST_LAST(ep->lch);
 
 	UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
 	UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -763,7 +788,7 @@
 		reg = UDC_TXDMA_CFG_REG;
 	else
 		reg = UDC_RXDMA_CFG_REG;
-	reg |= 1 << 12;		/* "pulse" activated */
+	reg |= UDC_DMA_REQ;		/* "pulse" activated */
 
 	ep->dma_channel = 0;
 	ep->lch = -1;
@@ -787,6 +812,11 @@
 			ep->ep.name, dma_error, ep, &ep->lch);
 		if (status == 0) {
 			UDC_TXDMA_CFG_REG = reg;
+			/* EMIFF */
+			omap_set_dma_src_burst_mode(ep->lch,
+						OMAP_DMA_DATA_BURST_4);
+			omap_set_dma_src_data_pack(ep->lch, 1);
+			/* TIPB */
 			omap_set_dma_dest_params(ep->lch,
 				OMAP_DMA_PORT_TIPB,
 				OMAP_DMA_AMODE_CONSTANT,
@@ -797,10 +827,15 @@
 			ep->ep.name, dma_error, ep, &ep->lch);
 		if (status == 0) {
 			UDC_RXDMA_CFG_REG = reg;
+			/* TIPB */
 			omap_set_dma_src_params(ep->lch,
 				OMAP_DMA_PORT_TIPB,
 				OMAP_DMA_AMODE_CONSTANT,
 				(unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+			/* EMIFF */
+			omap_set_dma_dest_burst_mode(ep->lch,
+						OMAP_DMA_DATA_BURST_4);
+			omap_set_dma_dest_data_pack(ep->lch, 1);
 		}
 	}
 	if (status)
@@ -856,7 +891,7 @@
 	if (!list_empty(&ep->queue))
 		req = container_of(ep->queue.next, struct omap_req, queue);
 	else
-		req = 0;
+		req = NULL;
 
 	active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
 
@@ -865,9 +900,13 @@
 			(ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
 			ep->dma_channel - 1, req);
 
+	/* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before
+	 * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them.
+	 */
+
 	/* wait till current packet DMA finishes, and fifo empties */
 	if (ep->bEndpointAddress & USB_DIR_IN) {
-		UDC_TXDMA_CFG_REG &= ~mask;
+		UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
 		if (req) {
 			finish_in_dma(ep, req, -ECONNRESET);
@@ -880,7 +919,7 @@
 		while (UDC_TXDMA_CFG_REG & mask)
 			udelay(10);
 	} else {
-		UDC_RXDMA_CFG_REG &= ~mask;
+		UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
 		/* dma empties the fifo */
 		while (UDC_RXDMA_CFG_REG & mask)
@@ -997,18 +1036,19 @@
 					UDC_IRQ_EN_REG = irq_en;
 				}
 
-				/* STATUS is reverse direction */
-				UDC_EP_NUM_REG = is_in
-						? UDC_EP_SEL
-						: (UDC_EP_SEL|UDC_EP_DIR);
+				/* STATUS for zero length DATA stages is
+				 * always an IN ... even for IN transfers,
+				 * a wierd case which seem to stall OMAP.
+				 */
+				UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
 				UDC_CTRL_REG = UDC_CLR_EP;
 				UDC_CTRL_REG = UDC_SET_FIFO_EN;
-				UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR;
+				UDC_EP_NUM_REG = UDC_EP_DIR;
 
 				/* cleanup */
 				udc->ep0_pending = 0;
 				done(ep, req, 0);
-				req = 0;
+				req = NULL;
 
 			/* non-empty DATA stage */
 			} else if (is_in) {
@@ -1029,7 +1069,7 @@
 			(is_in ? next_in_dma : next_out_dma)(ep, req);
 		else if (req) {
 			if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
-				req = 0;
+				req = NULL;
 			deselect_ep();
 			if (!is_in) {
 				UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1041,7 +1081,7 @@
 
 irq_wait:
 	/* irq handler advances the queue */
-	if (req != 0)
+	if (req != NULL)
 		list_add_tail(&req->queue, &ep->queue);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1140,7 +1180,7 @@
 				dma_channel_claim(ep, channel);
 		} else {
 			use_ep(ep, 0);
-			UDC_CTRL_REG = UDC_RESET_EP;
+			UDC_CTRL_REG = ep->udc->clr_halt;
 			ep->ackwait = 0;
 			if (!(ep->bEndpointAddress & USB_DIR_IN)) {
 				UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1238,6 +1278,8 @@
 
 static void pullup_enable(struct omap_udc *udc)
 {
+	udc->gadget.dev.parent->power.power_state = PMSG_ON;
+	udc->gadget.dev.power.power_state = PMSG_ON;
 	UDC_SYSCON1_REG |= UDC_PULLUP_EN;
 #ifndef CONFIG_USB_OTG
 	if (!cpu_is_omap15xx())
@@ -1382,7 +1424,7 @@
 static void ep0_irq(struct omap_udc *udc, u16 irq_src)
 {
 	struct omap_ep	*ep0 = &udc->ep[0];
-	struct omap_req	*req = 0;
+	struct omap_req	*req = NULL;
 
 	ep0->irqs++;
 
@@ -1438,7 +1480,7 @@
 				if (req)
 					done(ep0, req, 0);
 			}
-			req = 0;
+			req = NULL;
 		} else if (stat & UDC_STALL) {
 			UDC_CTRL_REG = UDC_CLR_HALT;
 			UDC_EP_NUM_REG = UDC_EP_DIR;
@@ -1511,9 +1553,10 @@
 			u.word[3] = UDC_DATA_REG;
 			UDC_EP_NUM_REG = 0;
 		} while (UDC_IRQ_SRC_REG & UDC_SETUP);
-		le16_to_cpus (&u.r.wValue);
-		le16_to_cpus (&u.r.wIndex);
-		le16_to_cpus (&u.r.wLength);
+
+#define	w_value		le16_to_cpup (&u.r.wValue)
+#define	w_index		le16_to_cpup (&u.r.wIndex)
+#define	w_length	le16_to_cpup (&u.r.wLength)
 
 		/* Delegate almost all control requests to the gadget driver,
 		 * except for a handful of ch9 status/feature requests that
@@ -1529,11 +1572,11 @@
 			/* udc needs to know when ep != 0 is valid */
 			if (u.r.bRequestType != USB_RECIP_DEVICE)
 				goto delegate;
-			if (u.r.wLength != 0)
+			if (w_length != 0)
 				goto do_stall;
 			udc->ep0_set_config = 1;
-			udc->ep0_reset_config = (u.r.wValue == 0);
-			VDBG("set config %d\n", u.r.wValue);
+			udc->ep0_reset_config = (w_value == 0);
+			VDBG("set config %d\n", w_value);
 
 			/* update udc NOW since gadget driver may start
 			 * queueing requests immediately; clear config
@@ -1549,23 +1592,28 @@
 			/* clear endpoint halt */
 			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
 				goto delegate;
-			if (u.r.wValue != USB_ENDPOINT_HALT
-					|| u.r.wLength != 0)
+			if (w_value != USB_ENDPOINT_HALT
+					|| w_length != 0)
 				goto do_stall;
-			ep = &udc->ep[u.r.wIndex & 0xf];
+			ep = &udc->ep[w_index & 0xf];
 			if (ep != ep0) {
-				if (u.r.wIndex & USB_DIR_IN)
+				if (w_index & USB_DIR_IN)
 					ep += 16;
 				if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
 						|| !ep->desc)
 					goto do_stall;
 				use_ep(ep, 0);
-				UDC_CTRL_REG = UDC_RESET_EP;
+				UDC_CTRL_REG = udc->clr_halt;
 				ep->ackwait = 0;
 				if (!(ep->bEndpointAddress & USB_DIR_IN)) {
 					UDC_CTRL_REG = UDC_SET_FIFO_EN;
 					ep->ackwait = 1 + ep->double_buf;
 				}
+				/* NOTE:  assumes the host behaves sanely,
+				 * only clearing real halts.  Else we may
+				 * need to kill pending transfers and then
+				 * restart the queue... very messy for DMA!
+				 */
 			}
 			VDBG("%s halt cleared by host\n", ep->name);
 			goto ep0out_status_stage;
@@ -1573,11 +1621,11 @@
 			/* set endpoint halt */
 			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
 				goto delegate;
-			if (u.r.wValue != USB_ENDPOINT_HALT
-					|| u.r.wLength != 0)
+			if (w_value != USB_ENDPOINT_HALT
+					|| w_length != 0)
 				goto do_stall;
-			ep = &udc->ep[u.r.wIndex & 0xf];
-			if (u.r.wIndex & USB_DIR_IN)
+			ep = &udc->ep[w_index & 0xf];
+			if (w_index & USB_DIR_IN)
 				ep += 16;
 			if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
 					|| ep == ep0 || !ep->desc)
@@ -1615,13 +1663,13 @@
 			UDC_CTRL_REG = UDC_SET_FIFO_EN;
 			UDC_EP_NUM_REG = UDC_EP_DIR;
 			status = 0;
-			VDBG("GET_STATUS, interface %d\n", u.r.wIndex);
+			VDBG("GET_STATUS, interface %d\n", w_index);
 			/* next, status stage */
 			break;
 		default:
 delegate:
 			/* activate the ep0out fifo right away */
-			if (!udc->ep0_in && u.r.wLength) {
+			if (!udc->ep0_in && w_length) {
 				UDC_EP_NUM_REG = 0;
 				UDC_CTRL_REG = UDC_SET_FIFO_EN;
 			}
@@ -1632,7 +1680,11 @@
 			 */
 			VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
 				u.r.bRequestType, u.r.bRequest,
-				u.r.wValue, u.r.wIndex, u.r.wLength);
+				w_value, w_index, w_length);
+
+#undef	w_value
+#undef	w_index
+#undef	w_length
 
 			/* The gadget driver may return an error here,
 			 * causing an immediate protocol stall.
@@ -2013,7 +2065,7 @@
 	udc->softconnect = 1;
 
 	/* hook up the driver */
-	driver->driver.bus = 0;
+	driver->driver.bus = NULL;
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -2021,8 +2073,8 @@
 	status = driver->bind (&udc->gadget);
 	if (status) {
 		DBG("bind to %s --> %d\n", driver->driver.name, status);
-		udc->gadget.dev.driver = 0;
-		udc->driver = 0;
+		udc->gadget.dev.driver = NULL;
+		udc->driver = NULL;
 		goto done;
 	}
 	DBG("bound to driver %s\n", driver->driver.name);
@@ -2035,8 +2087,8 @@
 		if (status < 0) {
 			ERR("can't bind to transceiver\n");
 			driver->unbind (&udc->gadget);
-			udc->gadget.dev.driver = 0;
-			udc->driver = 0;
+			udc->gadget.dev.driver = NULL;
+			udc->driver = NULL;
 			goto done;
 		}
 	} else {
@@ -2071,7 +2123,7 @@
 		omap_vbus_session(&udc->gadget, 0);
 
 	if (udc->transceiver)
-		(void) otg_set_peripheral(udc->transceiver, 0);
+		(void) otg_set_peripheral(udc->transceiver, NULL);
 	else
 		pullup_disable(udc);
 
@@ -2080,9 +2132,8 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	driver->unbind(&udc->gadget);
-	udc->gadget.dev.driver = 0;
-	udc->driver = 0;
-
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
 
 	DBG("unregistered driver '%s'\n", driver->driver.name);
 	return status;
@@ -2178,14 +2229,14 @@
 
 	tmp = OTG_REV_REG;
 	trans = USB_TRANSCEIVER_CTRL_REG;
-	seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
+	seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n",
 		tmp >> 4, tmp & 0xf, trans);
 	tmp = OTG_SYSCON_1_REG;
 	seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
 			FOURBITS "\n", tmp,
 		trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
 		trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
-		(USB0_TRX_MODE(tmp) == 0)
+		(USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710())
 			? "internal"
 			: trx_mode(USB0_TRX_MODE(tmp), 1),
 		(tmp & OTG_IDLE_EN) ? " !otg" : "",
@@ -2235,6 +2286,7 @@
 	seq_printf(s, "otg_outctrl %04x" "\n", tmp);
 	tmp = OTG_TEST_REG;
 	seq_printf(s, "otg_test    %04x" "\n", tmp);
+	return 0;
 }
 
 static int proc_udc_show(struct seq_file *s, void *_)
@@ -2378,7 +2430,7 @@
 
 static int proc_udc_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, proc_udc_show, 0);
+	return single_open(file, proc_udc_show, NULL);
 }
 
 static struct file_operations proc_ops = {
@@ -2399,7 +2451,7 @@
 
 static void remove_proc_file(void)
 {
-	remove_proc_entry(proc_filename, 0);
+	remove_proc_entry(proc_filename, NULL);
 }
 
 #else
@@ -2414,6 +2466,10 @@
 /* Before this controller can enumerate, we need to pick an endpoint
  * configuration, or "fifo_mode"  That involves allocating 2KB of packet
  * buffer space among the endpoints we'll be operating.
+ *
+ * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
+ * UDC_SYSCON_1_REG.CFG_LOCK is set can now work.  We won't use that
+ * capability yet though.
  */
 static unsigned __init
 omap_ep_setup(char *name, u8 addr, u8 type,
@@ -2505,7 +2561,7 @@
 {
 	complete(udc->done);
 	kfree (udc);
-	udc = 0;
+	udc = NULL;
 }
 
 static int __init
@@ -2577,23 +2633,33 @@
 	case 1:
 		OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
 		OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+		OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
+
 		OMAP_BULK_EP("ep3in",  USB_DIR_IN  | 3);
 		OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
+		OMAP_INT_EP("ep10in",  USB_DIR_IN  | 10, 16);
 
 		OMAP_BULK_EP("ep5in",  USB_DIR_IN  | 5);
 		OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+		OMAP_INT_EP("ep11in",  USB_DIR_IN  | 11, 16);
+
 		OMAP_BULK_EP("ep6in",  USB_DIR_IN  | 6);
 		OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
+		OMAP_INT_EP("ep12in",  USB_DIR_IN  | 12, 16);
 
 		OMAP_BULK_EP("ep7in",  USB_DIR_IN  | 7);
 		OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+		OMAP_INT_EP("ep13in",  USB_DIR_IN  | 13, 16);
+		OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16);
+
 		OMAP_BULK_EP("ep8in",  USB_DIR_IN  | 8);
 		OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
+		OMAP_INT_EP("ep14in",  USB_DIR_IN  | 14, 16);
+		OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16);
 
-		OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
-		OMAP_INT_EP("ep10out", USB_DIR_IN  | 10, 16);
-		OMAP_INT_EP("ep11in",  USB_DIR_IN  | 9, 16);
-		OMAP_INT_EP("ep12out", USB_DIR_IN  | 10, 16);
+		OMAP_BULK_EP("ep15in",  USB_DIR_IN  | 15);
+		OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15);
+
 		break;
 
 #ifdef	USE_ISO
@@ -2640,8 +2706,8 @@
 	struct platform_device	*odev = to_platform_device(dev);
 	int			status = -ENODEV;
 	int			hmc;
-	struct otg_transceiver	*xceiv = 0;
-	const char		*type = 0;
+	struct otg_transceiver	*xceiv = NULL;
+	const char		*type = NULL;
 	struct omap_usb_config	*config = dev->platform_data;
 
 	/* NOTE:  "knows" the order of the resources! */
@@ -2676,54 +2742,78 @@
 			FUNC_MUX_CTRL_0_REG = tmp;
 		}
 	} else {
+		/* The transceiver may package some GPIO logic or handle
+		 * loopback and/or transceiverless setup; if we find one,
+		 * use it.  Except for OTG, we don't _need_ to talk to one;
+		 * but not having one probably means no VBUS detection.
+		 */
+		xceiv = otg_get_transceiver();
+		if (xceiv)
+			type = xceiv->label;
+		else if (config->otg) {
+			DBG("OTG requires external transceiver!\n");
+			goto cleanup0;
+		}
+
 		hmc = HMC_1610;
 		switch (hmc) {
+		case 0:			/* POWERUP DEFAULT == 0 */
+		case 4:
+		case 12:
+		case 20:
+			if (!cpu_is_omap1710()) {
+				type = "integrated";
+				break;
+			}
+			/* FALL THROUGH */
 		case 3:
 		case 11:
 		case 16:
 		case 19:
 		case 25:
-			xceiv = otg_get_transceiver();
 			if (!xceiv) {
 				DBG("external transceiver not registered!\n");
-				if (config->otg)
-					goto cleanup0;
-				type = "(unknown external)";
-			} else
-				type = xceiv->label;
-			break;
-		case 0:			/* POWERUP DEFAULT == 0 */
-		case 4:
-		case 12:
-		case 20:
-			type = "INTEGRATED";
+				type = "unknown";
+			}
 			break;
 		case 21:			/* internal loopback */
-			type = "(loopback)";
+			type = "loopback";
 			break;
 		case 14:			/* transceiverless */
-			type = "(none)";
+			if (cpu_is_omap1710())
+				goto bad_on_1710;
+			/* FALL THROUGH */
+		case 13:
+		case 15:
+			type = "no";
 			break;
 
 		default:
+bad_on_1710:
 			ERR("unrecognized UDC HMC mode %d\n", hmc);
-			return -ENODEV;
+			goto cleanup0;
 		}
 	}
-	INFO("hmc mode %d, transceiver %s\n", hmc, type);
+	INFO("hmc mode %d, %s transceiver\n", hmc, type);
 
 	/* a "gadget" abstracts/virtualizes the controller */
 	status = omap_udc_setup(odev, xceiv);
 	if (status) {
 		goto cleanup0;
 	}
-	xceiv = 0;
+	xceiv = NULL;
 	// "udc" is now valid
 	pullup_disable(udc);
 #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 	udc->gadget.is_otg = (config->otg != 0);
 #endif
 
+	/* starting with omap1710 es2.0, clear toggle is a separate bit */
+	if (UDC_REV_REG >= 0x61)
+		udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
+	else
+		udc->clr_halt = UDC_RESET_EP;
+
 	/* USB general purpose IRQ:  ep0, state changes, dma, etc */
 	status = request_irq(odev->resource[1].start, omap_udc_irq,
 			SA_SAMPLE_RANDOM, driver_name, udc);
@@ -2765,7 +2855,7 @@
 
 cleanup1:
 	kfree (udc);
-	udc = 0;
+	udc = NULL;
 
 cleanup0:
 	if (xceiv)
@@ -2788,7 +2878,7 @@
 	pullup_disable(udc);
 	if (udc->transceiver) {
 		put_device(udc->transceiver->dev);
-		udc->transceiver = 0;
+		udc->transceiver = NULL;
 	}
 	UDC_SYSCON1_REG = 0;
 
@@ -2809,13 +2899,32 @@
 	return 0;
 }
 
-static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
+/* suspend/resume/wakeup from sysfs (echo > power/state) or when the
+ * system is forced into deep sleep
+ *
+ * REVISIT we should probably reject suspend requests when there's a host
+ * session active, rather than disconnecting, at least on boards that can
+ * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT).  And in any case, we need to
+ * make host resumes and VBUS detection trigger OMAP wakeup events; that
+ * may involve talking to an external transceiver (e.g. isp1301).
+ */
+static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level)
 {
-	if (level != 0)
-		return 0;
+	u32	devstat;
 
-	DBG("suspend, state %d\n", state);
-	omap_pullup(&udc->gadget, 0);
+	if (level != SUSPEND_POWER_DOWN)
+		return 0;
+	devstat = UDC_DEVSTAT_REG;
+
+	/* we're requesting 48 MHz clock if the pullup is enabled
+	 * (== we're attached to the host) and we're not suspended,
+	 * which would prevent entry to deep sleep...
+	 */
+	if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
+		WARN("session active; suspend requires disconnect\n");
+		omap_pullup(&udc->gadget, 0);
+	}
+
 	udc->gadget.dev.power.power_state = PMSG_SUSPEND;
 	udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
 	return 0;
@@ -2823,7 +2932,7 @@
 
 static int omap_udc_resume(struct device *dev, u32 level)
 {
-	if (level != 0)
+	if (level != RESUME_POWER_ON)
 		return 0;
 
 	DBG("resume + wakeup/SRP\n");
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index c9e6854..652ee46 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -20,6 +20,7 @@
 #define	UDC_CTRL_REG			UDC_REG(0x0C)	/* Endpoint control */
 #	define	UDC_CLR_HALT		(1 << 7)
 #	define	UDC_SET_HALT		(1 << 6)
+#	define	UDC_CLRDATA_TOGGLE	(1 << 3)
 #	define	UDC_SET_FIFO_EN		(1 << 2)
 #	define	UDC_CLR_EP		(1 << 1)
 #	define	UDC_RESET_EP		(1 << 0)
@@ -99,6 +100,7 @@
 
 /* DMA configuration registers:  up to three channels in each direction.  */
 #define	UDC_RXDMA_CFG_REG		UDC_REG(0x40)	/* 3 eps for RX DMA */
+#	define	UDC_DMA_REQ		(1 << 12)
 #define	UDC_TXDMA_CFG_REG		UDC_REG(0x44)	/* 3 eps for TX DMA */
 #define	UDC_DATA_DMA_REG		UDC_REG(0x48)	/* rx/tx fifo addr */
 
@@ -162,6 +164,7 @@
 	spinlock_t			lock;
 	struct omap_ep			ep[32];
 	u16				devstat;
+	u16				clr_halt;
 	struct otg_transceiver		*transceiver;
 	struct list_head		iso;
 	unsigned			softconnect:1;
@@ -171,7 +174,6 @@
 	unsigned			ep0_set_config:1;
 	unsigned			ep0_reset_config:1;
 	unsigned			ep0_setup:1;
-
 	struct completion		*done;
 };
 
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b8b4524..6a0b957 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -1,6 +1,6 @@
 /*
  * linux/drivers/usb/gadget/pxa2xx_udc.c
- * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
+ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
  *
  * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
  * Copyright (C) 2003 Robert Schwebel, Pengutronix
@@ -63,7 +63,7 @@
 
 
 /*
- * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
  * series processors.  The UDC for the IXP 4xx series is very similar.
  * There are fifteen endpoints, in addition to ep0.
  *
@@ -79,8 +79,8 @@
  * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
  */
 
-#define	DRIVER_VERSION	"14-Dec-2003"
-#define	DRIVER_DESC	"PXA 2xx USB Device Controller driver"
+#define	DRIVER_VERSION	"4-May-2005"
+#define	DRIVER_DESC	"PXA 25x USB Device Controller driver"
 
 
 static const char driver_name [] = "pxa2xx_udc";
@@ -290,6 +290,7 @@
 static int pxa2xx_ep_disable (struct usb_ep *_ep)
 {
 	struct pxa2xx_ep	*ep;
+	unsigned long		flags;
 
 	ep = container_of (_ep, struct pxa2xx_ep, ep);
 	if (!_ep || !ep->desc) {
@@ -297,6 +298,8 @@
 			_ep ? ep->ep.name : NULL);
 		return -EINVAL;
 	}
+	local_irq_save(flags);
+
 	nuke (ep, -ESHUTDOWN);
 
 #ifdef	USE_DMA
@@ -313,6 +316,7 @@
 	ep->desc = NULL;
 	ep->stopped = 1;
 
+	local_irq_restore(flags);
 	DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
 	return 0;
 }
@@ -971,10 +975,10 @@
 			kick_dma(ep, req);
 #endif
 		/* can the FIFO can satisfy the request immediately? */
-		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
-				&& (*ep->reg_udccs & UDCCS_BI_TFS) != 0
-				&& write_fifo(ep, req)) {
-			req = NULL;
+		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+			if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+					&& write_fifo(ep, req))
+				req = NULL;
 		} else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
 				&& read_fifo(ep, req)) {
 			req = NULL;
@@ -1290,7 +1294,7 @@
 		"%s version: %s\nGadget driver: %s\nHost %s\n\n",
 		driver_name, DRIVER_VERSION SIZE_STR DMASTR,
 		dev->driver ? dev->driver->driver.name : "(none)",
-		is_usb_connected() ? "full speed" : "disconnected");
+		is_vbus_present() ? "full speed" : "disconnected");
 	size -= t;
 	next += t;
 
@@ -1339,7 +1343,7 @@
 		next += t;
 	}
 
-	if (!is_usb_connected() || !dev->driver)
+	if (!is_vbus_present() || !dev->driver)
 		goto done;
 
 	t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
@@ -1454,7 +1458,7 @@
 	UFNRH = UFNRH_SIM;
 
 	/* if hardware supports it, disconnect from usb */
-	make_usb_disappear();
+	pullup_off();
 
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
@@ -1567,7 +1571,7 @@
 	UICR0 &= ~UICR0_IM0;
 
 	/* if hardware supports it, pullup D+ and wait for reset */
-	let_usb_appear();
+	pullup_on();
 }
 
 
@@ -2052,10 +2056,10 @@
 		if (unlikely(udccr & UDCCR_SUSIR)) {
 			udc_ack_int_UDCCR(UDCCR_SUSIR);
 			handled = 1;
-			DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected()
+			DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
 				? "" : "+disconnect");
 
-			if (!is_usb_connected())
+			if (!is_vbus_present())
 				stop_activity(dev, dev->driver);
 			else if (dev->gadget.speed != USB_SPEED_UNKNOWN
 					&& dev->driver
@@ -2073,7 +2077,7 @@
 			if (dev->gadget.speed != USB_SPEED_UNKNOWN
 					&& dev->driver
 					&& dev->driver->resume
-					&& is_usb_connected())
+					&& is_vbus_present())
 				dev->driver->resume(&dev->gadget);
 		}
 
@@ -2509,7 +2513,7 @@
 	udc_disable(dev);
 	udc_reinit(dev);
 
-	dev->vbus = is_usb_connected();
+	dev->vbus = is_vbus_present();
 
 	/* irq setup after old hardware state is cleaned up */
 	retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
@@ -2555,6 +2559,12 @@
 
 	return 0;
 }
+
+static void pxa2xx_udc_shutdown(struct device *_dev)
+{
+	pullup_off();
+}
+
 static int __exit pxa2xx_udc_remove(struct device *_dev)
 {
 	struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
@@ -2624,6 +2634,7 @@
 	.name		= "pxa2xx-udc",
 	.bus		= &platform_bus_type,
 	.probe		= pxa2xx_udc_probe,
+	.shutdown	= pxa2xx_udc_shutdown,
 	.remove		= __exit_p(pxa2xx_udc_remove),
 	.suspend	= pxa2xx_udc_suspend,
 	.resume		= pxa2xx_udc_resume,
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 1f3a7d9..d0bc396 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,23 +177,23 @@
 
 static struct pxa2xx_udc *the_controller;
 
-/* one GPIO should be used to detect host disconnect */
-static inline int is_usb_connected(void)
+/* one GPIO should be used to detect VBUS from the host */
+static inline int is_vbus_present(void)
 {
 	if (!the_controller->mach->udc_is_connected)
 		return 1;
 	return the_controller->mach->udc_is_connected();
 }
 
-/* one GPIO should force the host to see this device (or not) */
-static inline void make_usb_disappear(void)
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static inline void pullup_off(void)
 {
 	if (!the_controller->mach->udc_command)
 		return;
 	the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
 }
 
-static inline void let_usb_appear(void)
+static inline void pullup_on(void)
 {
 	if (!the_controller->mach->udc_command)
 		return;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 7457268..06b6eba 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -41,6 +41,7 @@
 
 
 #undef	RNDIS_PM
+#undef	RNDIS_WAKEUP
 #undef	VERBOSE
 
 #include "rndis.h"
@@ -60,7 +61,7 @@
 	} while (0)
 static int rndis_debug = 0;
 
-module_param (rndis_debug, bool, 0);
+module_param (rndis_debug, int, 0);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
 
 #else
@@ -78,22 +79,103 @@
 static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
 
 /* Function Prototypes */
-static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
-static int rndis_query_response (int configNr, rndis_query_msg_type *buf);
-static int rndis_set_response (int configNr, rndis_set_msg_type *buf);
-static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf);
-static int rndis_keepalive_response (int configNr, 
-				     rndis_keepalive_msg_type *buf);
-
 static rndis_resp_t *rndis_add_response (int configNr, u32 length);
 
 
+/* supported OIDs */
+static const u32 oid_supported_list [] = 
+{
+	/* the general stuff */
+	OID_GEN_SUPPORTED_LIST,
+	OID_GEN_HARDWARE_STATUS,
+	OID_GEN_MEDIA_SUPPORTED,
+	OID_GEN_MEDIA_IN_USE,
+	OID_GEN_MAXIMUM_FRAME_SIZE,
+	OID_GEN_LINK_SPEED,
+	OID_GEN_TRANSMIT_BLOCK_SIZE,
+	OID_GEN_RECEIVE_BLOCK_SIZE,
+	OID_GEN_VENDOR_ID,
+	OID_GEN_VENDOR_DESCRIPTION,
+	OID_GEN_VENDOR_DRIVER_VERSION,
+	OID_GEN_CURRENT_PACKET_FILTER,
+	OID_GEN_MAXIMUM_TOTAL_SIZE,
+	OID_GEN_MEDIA_CONNECT_STATUS,
+	OID_GEN_PHYSICAL_MEDIUM,
+#if 0
+	OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
+	
+	/* the statistical stuff */
+	OID_GEN_XMIT_OK,
+	OID_GEN_RCV_OK,
+	OID_GEN_XMIT_ERROR,
+	OID_GEN_RCV_ERROR,
+	OID_GEN_RCV_NO_BUFFER,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_GEN_DIRECTED_BYTES_XMIT,
+	OID_GEN_DIRECTED_FRAMES_XMIT,
+	OID_GEN_MULTICAST_BYTES_XMIT,
+	OID_GEN_MULTICAST_FRAMES_XMIT,
+	OID_GEN_BROADCAST_BYTES_XMIT,
+	OID_GEN_BROADCAST_FRAMES_XMIT,
+	OID_GEN_DIRECTED_BYTES_RCV,
+	OID_GEN_DIRECTED_FRAMES_RCV,
+	OID_GEN_MULTICAST_BYTES_RCV,
+	OID_GEN_MULTICAST_FRAMES_RCV,
+	OID_GEN_BROADCAST_BYTES_RCV,
+	OID_GEN_BROADCAST_FRAMES_RCV,
+	OID_GEN_RCV_CRC_ERROR,
+	OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+    	/* mandatory 802.3 */
+	/* the general stuff */
+	OID_802_3_PERMANENT_ADDRESS,
+	OID_802_3_CURRENT_ADDRESS,
+	OID_802_3_MULTICAST_LIST,
+	OID_802_3_MAC_OPTIONS,
+	OID_802_3_MAXIMUM_LIST_SIZE,
+	
+	/* the statistical stuff */
+	OID_802_3_RCV_ERROR_ALIGNMENT,
+	OID_802_3_XMIT_ONE_COLLISION,
+	OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_802_3_XMIT_DEFERRED,
+	OID_802_3_XMIT_MAX_COLLISIONS,
+	OID_802_3_RCV_OVERRUN,
+	OID_802_3_XMIT_UNDERRUN,
+	OID_802_3_XMIT_HEARTBEAT_FAILURE,
+	OID_802_3_XMIT_TIMES_CRS_LOST,
+	OID_802_3_XMIT_LATE_COLLISIONS,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* PM and wakeup are mandatory for USB: */
+
+	/* power management */
+	OID_PNP_CAPABILITIES,
+	OID_PNP_QUERY_POWER,
+	OID_PNP_SET_POWER,
+
+#ifdef	RNDIS_WAKEUP
+	/* wake up host */
+	OID_PNP_ENABLE_WAKE_UP,
+	OID_PNP_ADD_WAKE_UP_PATTERN,
+	OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif	/* RNDIS_WAKEUP */
+#endif	/* RNDIS_PM */
+};
+
+
 /* NDIS Functions */
-static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
+static int
+gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+		rndis_resp_t *r)
 {
 	int 			retval = -ENOTSUPP;
-	u32 			length = 0;
-	__le32			*tmp;
+	u32 			length = 4;	/* usually */
+	__le32			*outbuf;
 	int			i, count;
 	rndis_query_cmplt_type	*resp;
 
@@ -101,7 +183,22 @@
 	resp = (rndis_query_cmplt_type *) r->buf;
 
 	if (!resp) return -ENOMEM;
-	
+
+	if (buf_len && rndis_debug > 1) {
+		DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+				le32_to_cpup((__le32 *)&buf[i]),
+				le32_to_cpup((__le32 *)&buf[i + 4]),
+				le32_to_cpup((__le32 *)&buf[i + 8]),
+				le32_to_cpup((__le32 *)&buf[i + 12]));
+		}
+	}
+
+	/* response goes here, right after the header */
+	outbuf = (__le32 *) &resp[1];
+	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
+
 	switch (OID) {
 
 	/* general oids (table 4-1) */
@@ -111,42 +208,36 @@
 		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
 		length = sizeof (oid_supported_list);
 		count  = length / sizeof (u32);
-		tmp = (__le32 *) ((u8 *)resp + 24);
 		for (i = 0; i < count; i++)
-			tmp[i] = cpu_to_le32 (oid_supported_list[i]);
+			outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_HARDWARE_STATUS:
 		DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
-		length = 4;
 		/* Bogus question! 
 		 * Hardware must be ready to receive high level protocols.
 		 * BTW: 
 		 * reddite ergo quae sunt Caesaris Caesari
 		 * et quae sunt Dei Deo!
 		 */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_MEDIA_SUPPORTED:
 		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr].medium);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_MEDIA_IN_USE:
 		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
-		length = 4;
 		/* one medium, one transport... (maybe you do it better) */
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr].medium);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
@@ -154,25 +245,21 @@
 	case OID_GEN_MAXIMUM_FRAME_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_LINK_SPEED:
-//		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
-		length = 4;
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].media_state
-			== NDIS_MEDIA_STATE_DISCONNECTED)
-		    *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+				== NDIS_MEDIA_STATE_DISCONNECTED)
+			*outbuf = __constant_cpu_to_le32 (0);
 		else
-		    *((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].speed);
 		retval = 0;
 		break;
@@ -181,8 +268,7 @@
 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
 		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -192,8 +278,7 @@
 	case OID_GEN_RECEIVE_BLOCK_SIZE:
 		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -202,8 +287,7 @@
 	/* mandatory */
 	case OID_GEN_VENDOR_ID:
 		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
+		*outbuf = cpu_to_le32 (
 			rndis_per_dev_params [configNr].vendorID);
 		retval = 0;
 		break;
@@ -212,51 +296,44 @@
 	case OID_GEN_VENDOR_DESCRIPTION:
 		DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
 		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
-		memcpy ((u8 *) resp + 24, 
+		memcpy (outbuf,
 			rndis_per_dev_params [configNr].vendorDescr, length);
 		retval = 0;
 		break;
 
 	case OID_GEN_VENDOR_DRIVER_VERSION:
 		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
-		length = 4;
 		/* Created as LE */
-		*((__le32 *) resp + 6) = rndis_driver_version;
+		*outbuf = rndis_driver_version;
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_CURRENT_PACKET_FILTER:
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params[configNr].filter);
+		*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
-					RNDIS_MAX_TOTAL_SIZE);
+		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_MEDIA_CONNECT_STATUS:
-		DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr]
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 						.media_state);
 		retval = 0;
 		break;
 
 	case OID_GEN_PHYSICAL_MEDIUM:
 		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 
@@ -266,8 +343,7 @@
 	 */
 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
 		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
+		*outbuf = __constant_cpu_to_le32(
 			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
 			| NDIS_MAC_OPTION_FULL_DUPLEX);
 		retval = 0;
@@ -277,62 +353,49 @@
 
 	/* mandatory */
 	case OID_GEN_XMIT_OK:
-		DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->tx_packets - 
 			    rndis_per_dev_params [configNr].stats->tx_errors -
 			    rndis_per_dev_params [configNr].stats->tx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 
 	/* mandatory */
 	case OID_GEN_RCV_OK:
-		DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->rx_packets - 
 			    rndis_per_dev_params [configNr].stats->rx_errors -
 			    rndis_per_dev_params [configNr].stats->rx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_XMIT_ERROR:
-		DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_RCV_ERROR:
-		DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -340,13 +403,9 @@
 	case OID_GEN_RCV_NO_BUFFER:
 		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 
@@ -359,8 +418,7 @@
 		 * divided by weight of Alpha Centauri
 		 */
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -369,9 +427,6 @@
 					 .stats->tx_dropped)
 				* 123);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -379,8 +434,7 @@
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
 		/* dito */
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -389,144 +443,105 @@
 					 .stats->tx_dropped)
 				/ 123);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast*1234);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42*255);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_DIRECTED_BYTES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_DIRECTED_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast * 1111);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42*255);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_RCV_CRC_ERROR:
 		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_crc_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
 		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 #endif	/* RNDIS_OPTIONAL_STATS */
@@ -538,13 +553,10 @@
 		DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
-			memcpy ((u8 *) resp + 24,
+			memcpy (outbuf,
 				rndis_per_dev_params [configNr].host_mac,
 				length);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -553,7 +565,7 @@
 		DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
-			memcpy ((u8 *) resp + 24,
+			memcpy (outbuf,
 				rndis_per_dev_params [configNr].host_mac,
 				length);
 			retval = 0;
@@ -563,18 +575,16 @@
 	/* mandatory */
 	case OID_802_3_MULTICAST_LIST:
 		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
-		length = 4;
 		/* Multicast base address only */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
+		*outbuf = __constant_cpu_to_le32 (0xE0000000);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_802_3_MAXIMUM_LIST_SIZE:
 		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
-		 length = 4;
 		/* Multicast base address only */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
+		*outbuf = __constant_cpu_to_le32 (1);
 		retval = 0;
 		break;
 		
@@ -587,11 +597,8 @@
 	/* mandatory */
 	case OID_802_3_RCV_ERROR_ALIGNMENT:
 		DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
-		if (rndis_per_dev_params [configNr].stats)
-		{
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+		if (rndis_per_dev_params [configNr].stats) {
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_frame_errors);
 			retval = 0;
 		}
@@ -600,16 +607,14 @@
 	/* mandatory */
 	case OID_802_3_XMIT_ONE_COLLISION:
 		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_802_3_XMIT_MORE_COLLISIONS:
 		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -655,27 +660,18 @@
 	case OID_PNP_CAPABILITIES:
 		DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
 
-		/* just PM, and remote wakeup on link status change
-		 * (not magic packet or pattern match)
-		 */
+		/* for now, no wakeup capabilities */
 		length = sizeof (struct NDIS_PNP_CAPABILITIES);
-		memset (resp, 0, length);
-		{
-			struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
-
-			caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
-			caps->WakeUpCapabilities.MinLinkChangeWakeUp 
-				 = NdisDeviceStateD3;
-
-			/* FIXME then use usb_gadget_wakeup(), and
-			 * set USB_CONFIG_ATT_WAKEUP in config desc
-			 */
-		}
+		memset(outbuf, 0, length);
 		retval = 0;
 		break;
 	case OID_PNP_QUERY_POWER:
-		DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
-		/* sure, handle any power state that maps to USB suspend */
+		DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+				le32_to_cpup((__le32 *) buf) - 1);
+		/* only suspend is a real power state, and
+		 * it can't be entered by OID_PNP_SET_POWER...
+		 */
+		length = 0;
 		retval = 0;
 		break;
 #endif
@@ -684,11 +680,12 @@
 		printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", 
 			 __FUNCTION__, OID);
 	}
+	if (retval < 0)
+		length = 0;
 	
-	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
 	resp->InformationBufferLength = cpu_to_le32 (length);
-	resp->MessageLength = cpu_to_le32 (24 + length);
-	r->length = 24 + length;
+	r->length = length + sizeof *resp;
+	resp->MessageLength = cpu_to_le32 (r->length);
 	return retval;
 }
 
@@ -705,45 +702,40 @@
 	if (!resp)
 		return -ENOMEM;
 
-	DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
-	for (i = 0; i < buf_len; i += 16) {
-		DEBUG ("%03d: "
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			"\n",
-			i,
-			buf[i], buf [i+1],
-				buf[i+2], buf[i+3],
-			buf[i+4], buf [i+5],
-				buf[i+6], buf[i+7],
-			buf[i+8], buf [i+9],
-				buf[i+10], buf[i+11],
-			buf[i+12], buf [i+13],
-				buf[i+14], buf[i+15]);
+	if (buf_len && rndis_debug > 1) {
+		DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+				le32_to_cpup((__le32 *)&buf[i]),
+				le32_to_cpup((__le32 *)&buf[i + 4]),
+				le32_to_cpup((__le32 *)&buf[i + 8]),
+				le32_to_cpup((__le32 *)&buf[i + 12]));
+		}
 	}
 
+	params = &rndis_per_dev_params [configNr];
 	switch (OID) {
 	case OID_GEN_CURRENT_PACKET_FILTER:
-		params = &rndis_per_dev_params [configNr];
-		retval = 0;
 
-		/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-		 * set the cdc_filter; it's not RNDIS-specific
+		/* these NDIS_PACKET_TYPE_* bitflags are shared with
+		 * cdc_filter; it's not RNDIS-specific
 		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
 		 *	PROMISCUOUS, DIRECTED,
 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
 		 */
-		params->filter = le32_to_cpup((__le32 *)buf);
+		*params->filter = (u16) le32_to_cpup((__le32 *)buf);
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
-			__FUNCTION__, params->filter);
+			__FUNCTION__, *params->filter);
 
 		/* this call has a significant side effect:  it's
 		 * what makes the packet flow start and stop, like
 		 * activating the CDC Ethernet altsetting.
 		 */
-		if (params->filter) {
+#ifdef	RNDIS_PM
+update_linkstate:
+#endif
+		retval = 0;
+		if (*params->filter) {
 			params->state = RNDIS_DATA_INITIALIZED;
 			netif_carrier_on(params->dev);
 			if (netif_running(params->dev))
@@ -776,21 +768,34 @@
 
 #ifdef	RNDIS_PM
 	case OID_PNP_SET_POWER:
-		DEBUG ("OID_PNP_SET_POWER\n");
-		/* sure, handle any power state that maps to USB suspend */
-		retval = 0;
+		/* The only real power state is USB suspend, and RNDIS requests
+		 * can't enter it; this one isn't really about power.  After
+		 * resuming, Windows forces a reset, and then SET_POWER D0.
+		 * FIXME ... then things go batty; Windows wedges itself.
+		 */
+		i = le32_to_cpup((__force __le32 *)buf);
+		DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+		switch (i) {
+		case NdisDeviceStateD0:
+			*params->filter = params->saved_filter;
+			goto update_linkstate;
+		case NdisDeviceStateD3:
+		case NdisDeviceStateD2:
+		case NdisDeviceStateD1:
+			params->saved_filter = *params->filter;
+			retval = 0;
+			break;
+		}
 		break;
 
-	case OID_PNP_ENABLE_WAKE_UP:
-		/* always-connected ... */
-		DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
-		retval = 0;
-		break;
-
-	// no PM resume patterns supported (specified where?)
-	// so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
+#ifdef	RNDIS_WAKEUP
+	// no wakeup support advertised, so wakeup OIDs always fail:
+	//  - OID_PNP_ENABLE_WAKE_UP
+	//  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
 #endif
 
+#endif	/* RNDIS_PM */
+
 	default:
 		printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", 
 			 __FUNCTION__, OID, buf_len);
@@ -811,13 +816,10 @@
 	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
-	
-	if (!r) return -ENOMEM;
-	
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_init_cmplt_type *) r->buf;
 	
-	if (!resp) return -ENOMEM;
-	
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_INITIALIZE_CMPLT);
 	resp->MessageLength = __constant_cpu_to_le32 (52);
@@ -857,20 +859,22 @@
 	 * oid_supported_list is the largest answer 
 	 */
 	r = rndis_add_response (configNr, sizeof (oid_supported_list));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_query_cmplt_type *) r->buf;
 	
-	if (!resp) return -ENOMEM;
-	
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
-	resp->MessageLength = __constant_cpu_to_le32 (24);
 	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-	
-	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
+  	
+	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
+			le32_to_cpu(buf->InformationBufferOffset)
+					+ 8 + (u8 *) buf,
+			le32_to_cpu(buf->InformationBufferLength),
+			r)) {
 		/* OID not supported */
 		resp->Status = __constant_cpu_to_le32 (
 				RNDIS_STATUS_NOT_SUPPORTED);
+		resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
 		resp->InformationBufferLength = __constant_cpu_to_le32 (0);
 		resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
 	} else
@@ -889,10 +893,9 @@
 	rndis_resp_t		*r;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_set_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 
 	BufLength = le32_to_cpu (buf->InformationBufferLength);
 	BufOffset = le32_to_cpu (buf->InformationBufferOffset);
@@ -930,10 +933,9 @@
 	rndis_resp_t		*r;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_reset_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 	
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
 	resp->MessageLength = __constant_cpu_to_le32 (16);
@@ -957,8 +959,9 @@
 	/* host "should" check only in RNDIS_DATA_INITIALIZED state */
 
 	r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_keepalive_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 		
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_KEEPALIVE_CMPLT);
@@ -987,10 +990,9 @@
 	
 	r = rndis_add_response (configNr, 
 				sizeof (rndis_indicate_status_msg_type));
-	if (!r) return -ENOMEM;
-	
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_indicate_status_msg_type *) r->buf;
-	if (!resp) return -ENOMEM;
 	
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_INDICATE_STATUS_MSG);
@@ -1021,6 +1023,21 @@
 					  RNDIS_STATUS_MEDIA_DISCONNECT);
 }
 
+void rndis_uninit (int configNr)
+{
+	u8 *buf;
+	u32 length;
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return;
+	rndis_per_dev_params [configNr].used = 0;
+	rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+
+	/* drain the response queue */
+	while ((buf = rndis_get_next_response(configNr, &length)))
+		rndis_free_response(configNr, buf);
+}
+
 void rndis_set_host_mac (int configNr, const u8 *addr)
 {
 	rndis_per_dev_params [configNr].host_mac = addr;
@@ -1046,9 +1063,13 @@
 		return -ENOTSUPP;
 	params = &rndis_per_dev_params [configNr];
 	
+	/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+	 * and normal HC level polling to see if there's any IN traffic.
+	 */
+
 	/* For USB: responses may take up to 10 seconds */
-	switch (MsgType)
-	{
+	switch (MsgType) {
 	case REMOTE_NDIS_INITIALIZE_MSG:
 		DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
 			__FUNCTION__ );
@@ -1082,10 +1103,9 @@
 
 	case REMOTE_NDIS_KEEPALIVE_MSG:
 		/* For USB: host does this every 5 seconds */
-#ifdef	VERBOSE
-		DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
-			__FUNCTION__ );
-#endif
+		if (rndis_debug > 1)
+			DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
+				__FUNCTION__ );
 		return rndis_keepalive_response (configNr,
 						 (rndis_keepalive_msg_type *) 
 						 buf);
@@ -1152,7 +1172,8 @@
 }
 
 int rndis_set_param_dev (u8 configNr, struct net_device *dev, 
-			 struct net_device_stats *stats)
+			 struct net_device_stats *stats,
+			 u16 *cdc_filter)
 {
 	DEBUG("%s:\n", __FUNCTION__ );
 	if (!dev || !stats) return -1;
@@ -1160,6 +1181,7 @@
 	
 	rndis_per_dev_params [configNr].dev = dev;
 	rndis_per_dev_params [configNr].stats = stats;
+	rndis_per_dev_params [configNr].filter = cdc_filter;
 	
 	return 0;
 }
@@ -1178,7 +1200,7 @@
 
 int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 {
-	DEBUG("%s:\n", __FUNCTION__ );
+	DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 	
 	rndis_per_dev_params [configNr].medium = medium;
@@ -1242,6 +1264,7 @@
 {
 	rndis_resp_t	*r;
 	
+	/* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
 	r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
 	if (!r) return NULL;
 	
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 2b5b55d..95b4c63 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -69,90 +69,6 @@
 #define OID_PNP_ENABLE_WAKE_UP			0xFD010106
 
 
-/* supported OIDs */
-static const u32 oid_supported_list [] = 
-{
-	/* the general stuff */
-	OID_GEN_SUPPORTED_LIST,
-	OID_GEN_HARDWARE_STATUS,
-	OID_GEN_MEDIA_SUPPORTED,
-	OID_GEN_MEDIA_IN_USE,
-	OID_GEN_MAXIMUM_FRAME_SIZE,
-	OID_GEN_LINK_SPEED,
-	OID_GEN_TRANSMIT_BLOCK_SIZE,
-	OID_GEN_RECEIVE_BLOCK_SIZE,
-	OID_GEN_VENDOR_ID,
-	OID_GEN_VENDOR_DESCRIPTION,
-	OID_GEN_VENDOR_DRIVER_VERSION,
-	OID_GEN_CURRENT_PACKET_FILTER,
-	OID_GEN_MAXIMUM_TOTAL_SIZE,
-	OID_GEN_MEDIA_CONNECT_STATUS,
-	OID_GEN_PHYSICAL_MEDIUM,
-#if 0
-	OID_GEN_RNDIS_CONFIG_PARAMETER,
-#endif
-	
-	/* the statistical stuff */
-	OID_GEN_XMIT_OK,
-	OID_GEN_RCV_OK,
-	OID_GEN_XMIT_ERROR,
-	OID_GEN_RCV_ERROR,
-	OID_GEN_RCV_NO_BUFFER,
-#ifdef	RNDIS_OPTIONAL_STATS
-	OID_GEN_DIRECTED_BYTES_XMIT,
-	OID_GEN_DIRECTED_FRAMES_XMIT,
-	OID_GEN_MULTICAST_BYTES_XMIT,
-	OID_GEN_MULTICAST_FRAMES_XMIT,
-	OID_GEN_BROADCAST_BYTES_XMIT,
-	OID_GEN_BROADCAST_FRAMES_XMIT,
-	OID_GEN_DIRECTED_BYTES_RCV,
-	OID_GEN_DIRECTED_FRAMES_RCV,
-	OID_GEN_MULTICAST_BYTES_RCV,
-	OID_GEN_MULTICAST_FRAMES_RCV,
-	OID_GEN_BROADCAST_BYTES_RCV,
-	OID_GEN_BROADCAST_FRAMES_RCV,
-	OID_GEN_RCV_CRC_ERROR,
-	OID_GEN_TRANSMIT_QUEUE_LENGTH,
-#endif	/* RNDIS_OPTIONAL_STATS */
-
-    	/* mandatory 802.3 */
-	/* the general stuff */
-	OID_802_3_PERMANENT_ADDRESS,
-	OID_802_3_CURRENT_ADDRESS,
-	OID_802_3_MULTICAST_LIST,
-	OID_802_3_MAC_OPTIONS,
-	OID_802_3_MAXIMUM_LIST_SIZE,
-	
-	/* the statistical stuff */
-	OID_802_3_RCV_ERROR_ALIGNMENT,
-	OID_802_3_XMIT_ONE_COLLISION,
-	OID_802_3_XMIT_MORE_COLLISIONS,
-#ifdef	RNDIS_OPTIONAL_STATS
-	OID_802_3_XMIT_DEFERRED,
-	OID_802_3_XMIT_MAX_COLLISIONS,
-	OID_802_3_RCV_OVERRUN,
-	OID_802_3_XMIT_UNDERRUN,
-	OID_802_3_XMIT_HEARTBEAT_FAILURE,
-	OID_802_3_XMIT_TIMES_CRS_LOST,
-	OID_802_3_XMIT_LATE_COLLISIONS,
-#endif	/* RNDIS_OPTIONAL_STATS */
-
-#ifdef	RNDIS_PM
-	/* PM and wakeup are mandatory for USB: */
-
-	/* power management */
-	OID_PNP_CAPABILITIES,
-	OID_PNP_QUERY_POWER,
-	OID_PNP_SET_POWER,
-
-	/* wake up host */
-	OID_PNP_ENABLE_WAKE_UP,
-	OID_PNP_ADD_WAKE_UP_PATTERN,
-	OID_PNP_REMOVE_WAKE_UP_PATTERN,
-#endif
-};
-
-
 typedef struct rndis_init_msg_type 
 {
 	__le32	MessageType;
@@ -309,15 +225,18 @@
 typedef struct rndis_params
 {
 	u8			confignr;
-	int			used;
+	u8			used;
+	u16			saved_filter;
 	enum rndis_state	state;
-	u32			filter;
 	u32			medium;
 	u32			speed;
 	u32			media_state;
+
 	const u8		*host_mac;
+	u16			*filter;
 	struct net_device 	*dev;
 	struct net_device_stats *stats;
+
 	u32			vendorID;
 	const char		*vendorDescr;
 	int 			(*ack) (struct net_device *);
@@ -329,7 +248,8 @@
 int  rndis_register (int (*rndis_control_ack) (struct net_device *));
 void rndis_deregister (int configNr);
 int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
-			 struct net_device_stats *stats);
+			 struct net_device_stats *stats,
+			 u16 *cdc_filter);
 int  rndis_set_param_vendor (u8 configNr, u32 vendorID, 
 			    const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
@@ -338,6 +258,7 @@
 u8   *rndis_get_next_response (int configNr, u32 *length);
 void rndis_free_response (int configNr, u8 *buf);
 
+void rndis_uninit (int configNr);
 int  rndis_signal_connect (int configNr);
 int  rndis_signal_disconnect (int configNr);
 int  rndis_state (int configNr);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 4d591c7..9e4f1c6 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -300,18 +300,18 @@
 		u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
-	int kmalloc_flags);
+	unsigned kmalloc_flags);
 static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
 
 static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
-	int kmalloc_flags);
+	unsigned kmalloc_flags);
 static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
 
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags);
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags);
 static void gs_free_ports(struct gs_dev *dev);
 
 /* circular buffer */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags);
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags);
 static void gs_buf_free(struct gs_buf *gb);
 static void gs_buf_clear(struct gs_buf *gb);
 static unsigned int gs_buf_data_avail(struct gs_buf *gb);
@@ -1607,9 +1607,9 @@
 	int ret = -EOPNOTSUPP;
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = ctrl->wIndex;
-	u16 wValue = ctrl->wValue;
-	u16 wLength = ctrl->wLength;
+	u16 wIndex = le16_to_cpu(ctrl->wIndex);
+	u16 wValue = le16_to_cpu(ctrl->wValue);
+	u16 wLength = le16_to_cpu(ctrl->wLength);
 
 	switch (ctrl->bRequestType & USB_TYPE_MASK) {
 	case USB_TYPE_STANDARD:
@@ -1651,9 +1651,9 @@
 	int ret = -EOPNOTSUPP;
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = ctrl->wIndex;
-	u16 wValue = ctrl->wValue;
-	u16 wLength = ctrl->wLength;
+	u16 wIndex = le16_to_cpu(ctrl->wIndex);
+	u16 wValue = le16_to_cpu(ctrl->wValue);
+	u16 wLength = le16_to_cpu(ctrl->wLength);
 
 	switch (ctrl->bRequest) {
 	case USB_REQ_GET_DESCRIPTOR:
@@ -1782,9 +1782,9 @@
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct gs_port *port = dev->dev_port[0];	/* ACM only has one port */
 	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = ctrl->wIndex;
-	u16 wValue = ctrl->wValue;
-	u16 wLength = ctrl->wLength;
+	u16 wIndex = le16_to_cpu(ctrl->wIndex);
+	u16 wValue = le16_to_cpu(ctrl->wValue);
+	u16 wLength = le16_to_cpu(ctrl->wLength);
 
 	switch (ctrl->bRequest) {
 	case USB_CDC_REQ_SET_LINE_CODING:
@@ -2119,7 +2119,8 @@
  * Allocate a usb_request and its buffer.  Returns a pointer to the
  * usb_request or NULL if there is an error.
  */
-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags)
+static struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags)
 {
 	struct usb_request *req;
 
@@ -2159,7 +2160,8 @@
  * Allocates a request and its buffer, using the given
  * endpoint, buffer len, and kmalloc flags.
  */
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags)
+static struct gs_req_entry *
+gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags)
 {
 	struct gs_req_entry	*req;
 
@@ -2200,7 +2202,7 @@
  *
  * The device lock is normally held when calling this function.
  */
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags)
 {
 	int i;
 	struct gs_port *port;
@@ -2282,7 +2284,7 @@
  *
  * Allocate a circular buffer and all associated memory.
  */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags)
 {
 	struct gs_buf *gb;
 
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 6e49432..a6e035e 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -919,9 +919,9 @@
 	struct zero_dev		*dev = get_gadget_data (gadget);
 	struct usb_request	*req = dev->req;
 	int			value = -EOPNOTSUPP;
-	u16			w_index = ctrl->wIndex;
-	u16			w_value = ctrl->wValue;
-	u16			w_length = ctrl->wLength;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
 
 	/* usually this stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will reconfigure hardware.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 19e598c..ed1899d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -49,6 +49,19 @@
 
 	  This supports the EHCI implementation from TransDimension Inc.
 
+config USB_ISP116X_HCD
+	tristate "ISP116X HCD support"
+	depends on USB
+	default N
+	---help---
+	  The ISP1160 and ISP1161 chips are USB host controllers. Enable this
+	  option if your board has this chip. If unsure, say N.
+
+	  This driver does not support isochronous transfers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called isp116x-hcd.
+
 config USB_OHCI_HCD
 	tristate "OHCI HCD support"
 	depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 5dbd3e7..350d14f 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
+obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
 obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 2ff11d5..50cb018 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -254,7 +254,7 @@
 	}
 
 	return scnprintf (buf, len,
-		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+		"%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
 		label, label [0] ? " " : "", port, status,
 		(status & PORT_POWER) ? " POWER" : "",
 		(status & PORT_OWNER) ? " OWNER" : "",
@@ -644,9 +644,11 @@
 	if (bus->controller->power.power_state) {
 		size = scnprintf (next, size,
 			"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+			"%s\n"
 			"SUSPENDED (no register access)\n",
 			hcd->self.controller->bus->name,
-			hcd->self.controller->bus_id);
+			hcd->self.controller->bus_id,
+			hcd->product_desc);
 		goto done;
 	}
 
@@ -654,13 +656,53 @@
 	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	temp = scnprintf (next, size,
 		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+		"%s\n"
 		"EHCI %x.%02x, hcd state %d\n",
 		hcd->self.controller->bus->name,
 		hcd->self.controller->bus_id,
+		hcd->product_desc,
 		i >> 8, i & 0x0ff, hcd->state);
 	size -= temp;
 	next += temp;
 
+#ifdef	CONFIG_PCI
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	if (hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev	*pdev;
+		u32		offset, cap, cap2;
+		unsigned	count = 256/4;
+
+		pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+		offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+		while (offset && count--) {
+			pci_read_config_dword (pdev, offset, &cap);
+			switch (cap & 0xff) {
+			case 1:
+				temp = scnprintf (next, size,
+					"ownership %08x%s%s\n", cap,
+					(cap & (1 << 24)) ? " linux" : "",
+					(cap & (1 << 16)) ? " firmware" : "");
+				size -= temp;
+				next += temp;
+
+				offset += 4;
+				pci_read_config_dword (pdev, offset, &cap2);
+				temp = scnprintf (next, size,
+					"SMI sts/enable 0x%08x\n", cap2);
+				size -= temp;
+				next += temp;
+				break;
+			case 0:		/* illegal reserved capability */
+				cap = 0;
+				/* FALLTHROUGH */
+			default:		/* unknown */
+				break;
+			}
+			temp = (cap >> 8) & 0xff;
+		}
+	}
+#endif
+
 	// FIXME interpret both types of params
 	i = readl (&ehci->caps->hcs_params);
 	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
@@ -696,12 +738,19 @@
 	size -= temp;
 	next += temp;
 
-	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
-		temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
-				readl (&ehci->regs->port_status [i]));
+	for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
+		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+				readl (&ehci->regs->port_status [i - 1]));
 		temp = scnprintf (next, size, fmt, temp, scratch);
 		size -= temp;
 		next += temp;
+		if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
+			temp = scnprintf (next, size,
+					"    debug control %08x\n",
+					readl (&ehci->debug->control));
+			size -= temp;
+			next += temp;
+		}
 	}
 
 	if (ehci->reclaim) {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bc69bd7..35248a3 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -304,30 +304,31 @@
  */
 static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
 {
+	struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+
+	/* always say Linux will own the hardware */
+	pci_write_config_byte(pdev, where + 3, 1);
+
+	/* maybe wait a while for BIOS to respond */
 	if (cap & (1 << 16)) {
 		int msec = 5000;
-		struct pci_dev *pdev =
-				to_pci_dev(ehci_to_hcd(ehci)->self.controller);
 
-		/* request handoff to OS */
-		cap |= 1 << 24;
-		pci_write_config_dword(pdev, where, cap);
-
-		/* and wait a while for it to happen */
 		do {
 			msleep(10);
 			msec -= 10;
 			pci_read_config_dword(pdev, where, &cap);
 		} while ((cap & (1 << 16)) && msec);
 		if (cap & (1 << 16)) {
-			ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
+			ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
 				where, cap);
 			// some BIOS versions seem buggy...
 			// return 1;
 			ehci_warn (ehci, "continuing after BIOS bug...\n");
-			return 0;
-		} 
-		ehci_dbg (ehci, "BIOS handoff succeeded\n");
+			/* disable all SMIs, and clear "BIOS owns" flag */
+			pci_write_config_dword(pdev, where + 4, 0);
+			pci_write_config_byte(pdev, where + 2, 0);
+		} else
+			ehci_dbg(ehci, "BIOS handoff succeeded\n");
 	}
 	return 0;
 }
@@ -492,8 +493,6 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
-	struct usb_device	*udev;
-	struct usb_bus		*bus;
 	int			retval;
 	u32			hcc_params;
 	u8                      sbrn = 0;
@@ -588,8 +587,8 @@
 		writel (0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
-		if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))
-			ehci_info (ehci, "enabled 64bit PCI DMA\n");
+		if (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK))
+			ehci_info (ehci, "enabled 64bit DMA\n");
 #endif
 	}
 
@@ -631,17 +630,6 @@
 
 	/* set async sleep time = 10 us ... ? */
 
-	/* wire up the root hub */
-	bus = hcd_to_bus (hcd);
-	udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
-	if (!udev) {
-done2:
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-	udev->speed = USB_SPEED_HIGH;
-	udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
-
 	/*
 	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
 	 * are explicitly handed to companion controller(s), so no TT is
@@ -664,24 +652,6 @@
 		first ? "initialized" : "restarted",
 		temp >> 8, temp & 0xff, DRIVER_VERSION);
 
-	/*
-	 * From here on, khubd concurrently accesses the root
-	 * hub; drivers will be talking to enumerated devices.
-	 * (On restart paths, khubd already knows about the root
-	 * hub and could find work as soon as we wrote FLAG_CF.)
-	 *
-	 * Before this point the HC was idle/ready.  After, khubd
-	 * and device drivers may start it running.
-	 */
-	if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
-		if (hcd->state == HC_STATE_RUNNING)
-			ehci_quiesce (ehci);
-		ehci_reset (ehci);
-		usb_put_dev (udev); 
-		retval = -ENODEV;
-		goto done2;
-	}
-
 	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
 
 	if (first)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d7b4f79..36cc1f2 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 by David Brownell
  * 
  * 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
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 7df9b9a..45d89a7 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 by David Brownell
  * 
  * 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
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 2fa1ffe..c2104ca 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -637,9 +637,8 @@
 {
 	struct ehci_iso_stream *stream;
 
-	stream = kmalloc(sizeof *stream, mem_flags);
+	stream = kcalloc(1, sizeof *stream, mem_flags);
 	if (likely (stream != NULL)) {
-		memset (stream, 0, sizeof(*stream));
 		INIT_LIST_HEAD(&stream->td_list);
 		INIT_LIST_HEAD(&stream->free_list);
 		stream->next_uframe = -1;
@@ -894,7 +893,7 @@
 		trans |= length << 16;
 		uframe->transaction = cpu_to_le32 (trans);
 
-		/* might need to cross a buffer page within a td */
+		/* might need to cross a buffer page within a uframe */
 		uframe->bufp = (buf & ~(u64)0x0fff);
 		buf += length;
 		if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
@@ -1194,6 +1193,7 @@
 {
 	int i;
 
+	/* it's been recently zeroed */
 	itd->hw_next = EHCI_LIST_END;
 	itd->hw_bufp [0] = stream->buf0;
 	itd->hw_bufp [1] = stream->buf1;
@@ -1210,8 +1210,7 @@
 	struct ehci_itd		*itd,
 	struct ehci_iso_sched	*iso_sched,
 	unsigned		index,
-	u16			uframe,
-	int			first
+	u16			uframe
 )
 {
 	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
@@ -1228,7 +1227,7 @@
 	itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
 
 	/* iso_frame_desc[].offset must be strictly increasing */
-	if (unlikely (!first && uf->cross)) {
+	if (unlikely (uf->cross)) {
 		u64	bufp = uf->bufp + 4096;
 		itd->pg = ++pg;
 		itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
@@ -1257,7 +1256,7 @@
 	struct ehci_iso_stream	*stream
 )
 {
-	int			packet, first = 1;
+	int			packet;
 	unsigned		next_uframe, uframe, frame;
 	struct ehci_iso_sched	*iso_sched = urb->hcpriv;
 	struct ehci_itd		*itd;
@@ -1290,7 +1289,6 @@
 			list_move_tail (&itd->itd_list, &stream->td_list);
 			itd->stream = iso_stream_get (stream);
 			itd->urb = usb_get_urb (urb);
-			first = 1;
 			itd_init (stream, itd);
 		}
 
@@ -1298,8 +1296,7 @@
 		frame = next_uframe >> 3;
 
 		itd->usecs [uframe] = stream->usecs;
-		itd_patch (itd, iso_sched, packet, uframe, first);
-		first = 0;
+		itd_patch (itd, iso_sched, packet, uframe);
 
 		next_uframe += stream->interval;
 		stream->depth += stream->interval;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
new file mode 100644
index 0000000..ff0a168
--- /dev/null
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -0,0 +1,1875 @@
+/*
+ * ISP116x HCD (Host Controller Driver) for USB.
+ *
+ * Derived from the SL811 HCD, rewritten for ISP116x.
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ *
+ * Portions:
+ * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Copyright (C) 2004 David Brownell
+ *
+ * Periodic scheduling is based on Roman's OHCI code
+ * Copyright (C) 1999 Roman Weissgaerber
+ *
+ */
+
+/*
+ * The driver basically works. A number of people have used it with a range
+ * of devices.
+ *
+ *The driver passes all usbtests 1-14.
+ *
+ * Suspending/resuming of root hub via sysfs works. Remote wakeup works too.
+ * And suspending/resuming of platform device works too. Suspend/resume
+ * via HCD operations vector is not implemented.
+ *
+ * Iso transfer support is not implemented. Adding this would include
+ * implementing recovery from the failure to service the processed ITL
+ * fifo ram in time, which will involve chip reset.
+ *
+ * TODO:
+ + More testing of suspend/resume.
+*/
+
+/*
+  ISP116x chips require certain delays between accesses to its
+  registers. The following timing options exist.
+
+  1. Configure your memory controller (the best)
+  2. Implement platform-specific delay function possibly
+  combined with configuring the memory controller; see
+  include/linux/usb-isp116x.h for more info. Some broken
+  memory controllers line LH7A400 SMC need this. Also,
+  uncomment for that to work the following
+  USE_PLATFORM_DELAY macro.
+  3. Use ndelay (easiest, poorest). For that, uncomment
+  the following USE_NDELAY macro.
+*/
+#define USE_PLATFORM_DELAY
+//#define USE_NDELAY
+
+//#define DEBUG
+//#define VERBOSE
+/* Transfer descriptors. See dump_ptd() for printout format  */
+//#define PTD_TRACE
+/* enqueuing/finishing log of urbs */
+//#define URB_TRACE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb_isp116x.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#ifndef DEBUG
+#	define	STUB_DEBUG_FILE
+#endif
+
+#include "../core/hcd.h"
+#include "isp116x.h"
+
+#define DRIVER_VERSION	"08 Apr 2005"
+#define DRIVER_DESC	"ISP116x USB Host Controller Driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static const char hcd_name[] = "isp116x-hcd";
+
+/*-----------------------------------------------------------------*/
+
+/*
+  Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+	u8 *dp = (u8 *) buf;
+	u16 *dp2 = (u16 *) buf;
+	u16 w;
+	int quot = len % 4;
+
+	if ((unsigned long)dp2 & 1) {
+		/* not aligned */
+		for (; len > 1; len -= 2) {
+			w = *dp++;
+			w |= *dp++ << 8;
+			isp116x_raw_write_data16(isp116x, w);
+		}
+		if (len)
+			isp116x_write_data16(isp116x, (u16) * dp);
+	} else {
+		/* aligned */
+		for (; len > 1; len -= 2)
+			isp116x_raw_write_data16(isp116x, *dp2++);
+		if (len)
+			isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+	}
+	if (quot == 1 || quot == 2)
+		isp116x_raw_write_data16(isp116x, 0);
+}
+
+/*
+  Read len bytes from fifo and then read till 32-bit boundary.
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+	u8 *dp = (u8 *) buf;
+	u16 *dp2 = (u16 *) buf;
+	u16 w;
+	int quot = len % 4;
+
+	if ((unsigned long)dp2 & 1) {
+		/* not aligned */
+		for (; len > 1; len -= 2) {
+			w = isp116x_raw_read_data16(isp116x);
+			*dp++ = w & 0xff;
+			*dp++ = (w >> 8) & 0xff;
+		}
+		if (len)
+			*dp = 0xff & isp116x_read_data16(isp116x);
+	} else {
+		/* aligned */
+		for (; len > 1; len -= 2)
+			*dp2++ = isp116x_raw_read_data16(isp116x);
+		if (len)
+			*(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+	}
+	if (quot == 1 || quot == 2)
+		isp116x_raw_read_data16(isp116x);
+}
+
+/*
+  Write ptd's and data for scheduled transfers into
+  the fifo ram. Fifo must be empty and ready.
+*/
+static void pack_fifo(struct isp116x *isp116x)
+{
+	struct isp116x_ep *ep;
+	struct ptd *ptd;
+	int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+	    ? isp116x->atl_bufshrt : isp116x->atl_buflen;
+	int ptd_count = 0;
+
+	isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+	isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+	isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		++ptd_count;
+		ptd = &ep->ptd;
+		dump_ptd(ptd);
+		dump_ptd_out_data(ptd, ep->data);
+		isp116x_write_data16(isp116x, ptd->count);
+		isp116x_write_data16(isp116x, ptd->mps);
+		isp116x_write_data16(isp116x, ptd->len);
+		isp116x_write_data16(isp116x, ptd->faddr);
+		buflen -= sizeof(struct ptd);
+		/* Skip writing data for last IN PTD */
+		if (ep->active || (isp116x->atl_last_dir != PTD_DIR_IN)) {
+			write_ptddata_to_fifo(isp116x, ep->data, ep->length);
+			buflen -= ALIGN(ep->length, 4);
+		}
+	}
+	BUG_ON(buflen);
+}
+
+/*
+  Read the processed ptd's and data from fifo ram back to
+  URBs' buffers. Fifo must be full and done
+*/
+static void unpack_fifo(struct isp116x *isp116x)
+{
+	struct isp116x_ep *ep;
+	struct ptd *ptd;
+	int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+	    ? isp116x->atl_buflen : isp116x->atl_bufshrt;
+
+	isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+	isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+	isp116x_write_addr(isp116x, HCATLPORT);
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		ptd = &ep->ptd;
+		ptd->count = isp116x_read_data16(isp116x);
+		ptd->mps = isp116x_read_data16(isp116x);
+		ptd->len = isp116x_read_data16(isp116x);
+		ptd->faddr = isp116x_read_data16(isp116x);
+		buflen -= sizeof(struct ptd);
+		/* Skip reading data for last Setup or Out PTD */
+		if (ep->active || (isp116x->atl_last_dir == PTD_DIR_IN)) {
+			read_ptddata_from_fifo(isp116x, ep->data, ep->length);
+			buflen -= ALIGN(ep->length, 4);
+		}
+		dump_ptd(ptd);
+		dump_ptd_in_data(ptd, ep->data);
+	}
+	BUG_ON(buflen);
+}
+
+/*---------------------------------------------------------------*/
+
+/*
+  Set up PTD's.
+*/
+static void preproc_atl_queue(struct isp116x *isp116x)
+{
+	struct isp116x_ep *ep;
+	struct urb *urb;
+	struct ptd *ptd;
+	u16 toggle, dir, len;
+
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		BUG_ON(list_empty(&ep->hep->urb_list));
+		urb = container_of(ep->hep->urb_list.next,
+				   struct urb, urb_list);
+		ptd = &ep->ptd;
+		len = ep->length;
+		spin_lock(&urb->lock);
+		ep->data = (unsigned char *)urb->transfer_buffer
+		    + urb->actual_length;
+
+		switch (ep->nextpid) {
+		case USB_PID_IN:
+			toggle = usb_gettoggle(urb->dev, ep->epnum, 0);
+			dir = PTD_DIR_IN;
+			break;
+		case USB_PID_OUT:
+			toggle = usb_gettoggle(urb->dev, ep->epnum, 1);
+			dir = PTD_DIR_OUT;
+			break;
+		case USB_PID_SETUP:
+			toggle = 0;
+			dir = PTD_DIR_SETUP;
+			len = sizeof(struct usb_ctrlrequest);
+			ep->data = urb->setup_packet;
+			break;
+		case USB_PID_ACK:
+			toggle = 1;
+			len = 0;
+			dir = (urb->transfer_buffer_length
+			       && usb_pipein(urb->pipe))
+			    ? PTD_DIR_OUT : PTD_DIR_IN;
+			break;
+		default:
+			/* To please gcc */
+			toggle = dir = 0;
+			ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__,
+			    ep->nextpid);
+			BUG_ON(1);
+		}
+
+		ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle);
+		ptd->mps = PTD_MPS(ep->maxpacket)
+		    | PTD_SPD(urb->dev->speed == USB_SPEED_LOW)
+		    | PTD_EP(ep->epnum);
+		ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+		ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
+		spin_unlock(&urb->lock);
+		if (!ep->active) {
+			ptd->mps |= PTD_LAST_MSK;
+			isp116x->atl_last_dir = dir;
+		}
+		isp116x->atl_bufshrt = sizeof(struct ptd) + isp116x->atl_buflen;
+		isp116x->atl_buflen = isp116x->atl_bufshrt + ALIGN(len, 4);
+	}
+}
+
+/*
+  Analyze transfer results, handle partial transfers and errors
+*/
+static void postproc_atl_queue(struct isp116x *isp116x)
+{
+	struct isp116x_ep *ep;
+	struct urb *urb;
+	struct usb_device *udev;
+	struct ptd *ptd;
+	int short_not_ok;
+	u8 cc;
+
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		BUG_ON(list_empty(&ep->hep->urb_list));
+		urb =
+		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
+		udev = urb->dev;
+		ptd = &ep->ptd;
+		cc = PTD_GET_CC(ptd);
+
+		spin_lock(&urb->lock);
+		short_not_ok = 1;
+
+		/* Data underrun is special. For allowed underrun
+		   we clear the error and continue as normal. For
+		   forbidden underrun we finish the DATA stage
+		   immediately while for control transfer,
+		   we do a STATUS stage. */
+		if (cc == TD_DATAUNDERRUN) {
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
+				DBG("Allowed data underrun\n");
+				cc = TD_CC_NOERROR;
+				short_not_ok = 0;
+			} else {
+				ep->error_count = 1;
+				if (usb_pipecontrol(urb->pipe))
+					ep->nextpid = USB_PID_ACK;
+				else
+					usb_settoggle(udev, ep->epnum,
+						      ep->nextpid ==
+						      USB_PID_OUT,
+						      PTD_GET_TOGGLE(ptd) ^ 1);
+				urb->status = cc_to_error[TD_DATAUNDERRUN];
+				spin_unlock(&urb->lock);
+				continue;
+			}
+		}
+		/* Keep underrun error through the STATUS stage */
+		if (urb->status == cc_to_error[TD_DATAUNDERRUN])
+			cc = TD_DATAUNDERRUN;
+
+		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
+		    && (++ep->error_count >= 3 || cc == TD_CC_STALL
+			|| cc == TD_DATAOVERRUN)) {
+			if (urb->status == -EINPROGRESS)
+				urb->status = cc_to_error[cc];
+			if (ep->nextpid == USB_PID_ACK)
+				ep->nextpid = 0;
+			spin_unlock(&urb->lock);
+			continue;
+		}
+		/* According to usb spec, zero-length Int transfer signals
+		   finishing of the urb. Hey, does this apply only
+		   for IN endpoints? */
+		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+			spin_unlock(&urb->lock);
+			continue;
+		}
+
+		/* Relax after previously failed, but later succeeded
+		   or correctly NAK'ed retransmission attempt */
+		if (ep->error_count
+		    && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))
+			ep->error_count = 0;
+
+		/* Take into account idiosyncracies of the isp116x chip
+		   regarding toggle bit for failed transfers */
+		if (ep->nextpid == USB_PID_OUT)
+			usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)
+				      ^ (ep->error_count > 0));
+		else if (ep->nextpid == USB_PID_IN)
+			usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)
+				      ^ (ep->error_count > 0));
+
+		switch (ep->nextpid) {
+		case USB_PID_IN:
+		case USB_PID_OUT:
+			urb->actual_length += PTD_GET_COUNT(ptd);
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if (urb->transfer_buffer_length != urb->actual_length) {
+				if (short_not_ok)
+					break;
+			} else {
+				if (urb->transfer_flags & URB_ZERO_PACKET
+				    && ep->nextpid == USB_PID_OUT
+				    && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {
+					DBG("Zero packet requested\n");
+					break;
+				}
+			}
+			/* All data for this URB is transferred, let's finish */
+			if (usb_pipecontrol(urb->pipe))
+				ep->nextpid = USB_PID_ACK;
+			else if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+			break;
+		case USB_PID_SETUP:
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if (urb->transfer_buffer_length == urb->actual_length)
+				ep->nextpid = USB_PID_ACK;
+			else if (usb_pipeout(urb->pipe)) {
+				usb_settoggle(udev, 0, 1, 1);
+				ep->nextpid = USB_PID_OUT;
+			} else {
+				usb_settoggle(udev, 0, 0, 1);
+				ep->nextpid = USB_PID_IN;
+			}
+			break;
+		case USB_PID_ACK:
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+			ep->nextpid = 0;
+			break;
+		default:
+			BUG_ON(1);
+		}
+		spin_unlock(&urb->lock);
+	}
+}
+
+/*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+			   struct urb *urb, struct pt_regs *regs)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+	unsigned i;
+
+	urb->hcpriv = NULL;
+	ep->error_count = 0;
+
+	if (usb_pipecontrol(urb->pipe))
+		ep->nextpid = USB_PID_SETUP;
+
+	urb_dbg(urb, "Finish");
+
+	spin_unlock(&isp116x->lock);
+	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs);
+	spin_lock(&isp116x->lock);
+
+	/* take idle endpoints out of the schedule */
+	if (!list_empty(&ep->hep->urb_list))
+		return;
+
+	/* async deschedule */
+	if (!list_empty(&ep->schedule)) {
+		list_del_init(&ep->schedule);
+		return;
+	}
+
+	/* periodic deschedule */
+	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+		struct isp116x_ep *temp;
+		struct isp116x_ep **prev = &isp116x->periodic[i];
+
+		while (*prev && ((temp = *prev) != ep))
+			prev = &temp->next;
+		if (*prev)
+			*prev = ep->next;
+		isp116x->load[i] -= ep->load;
+	}
+	ep->branch = PERIODIC_SIZE;
+	isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+	    ep->load / ep->period;
+
+	/* switch irq type? */
+	if (!--isp116x->periodic_count) {
+		isp116x->irqenb &= ~HCuPINT_SOF;
+		isp116x->irqenb |= HCuPINT_ATL;
+	}
+}
+
+/*
+  Scan transfer lists, schedule transfers, send data off
+  to chip.
+ */
+static void start_atl_transfers(struct isp116x *isp116x)
+{
+	struct isp116x_ep *last_ep = NULL, *ep;
+	struct urb *urb;
+	u16 load = 0;
+	int len, index, speed, byte_time;
+
+	if (atomic_read(&isp116x->atl_finishing))
+		return;
+
+	if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state))
+		return;
+
+	/* FIFO not empty? */
+	if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL)
+		return;
+
+	isp116x->atl_active = NULL;
+	isp116x->atl_buflen = isp116x->atl_bufshrt = 0;
+
+	/* Schedule int transfers */
+	if (isp116x->periodic_count) {
+		isp116x->fmindex = index =
+		    (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1);
+		if ((load = isp116x->load[index])) {
+			/* Bring all int transfers for this frame
+			   into the active queue */
+			isp116x->atl_active = last_ep =
+			    isp116x->periodic[index];
+			while (last_ep->next)
+				last_ep = (last_ep->active = last_ep->next);
+			last_ep->active = NULL;
+		}
+	}
+
+	/* Schedule control/bulk transfers */
+	list_for_each_entry(ep, &isp116x->async, schedule) {
+		urb = container_of(ep->hep->urb_list.next,
+				   struct urb, urb_list);
+		speed = urb->dev->speed;
+		byte_time = speed == USB_SPEED_LOW
+		    ? BYTE_TIME_LOWSPEED : BYTE_TIME_FULLSPEED;
+
+		if (ep->nextpid == USB_PID_SETUP) {
+			len = sizeof(struct usb_ctrlrequest);
+		} else if (ep->nextpid == USB_PID_ACK) {
+			len = 0;
+		} else {
+			/* Find current free length ... */
+			len = (MAX_LOAD_LIMIT - load) / byte_time;
+
+			/* ... then limit it to configured max size ... */
+			len = min(len, speed == USB_SPEED_LOW ?
+				  MAX_TRANSFER_SIZE_LOWSPEED :
+				  MAX_TRANSFER_SIZE_FULLSPEED);
+
+			/* ... and finally cut to the multiple of MaxPacketSize,
+			   or to the real length if there's enough room. */
+			if (len <
+			    (urb->transfer_buffer_length -
+			     urb->actual_length)) {
+				len -= len % ep->maxpacket;
+				if (!len)
+					continue;
+			} else
+				len = urb->transfer_buffer_length -
+				    urb->actual_length;
+			BUG_ON(len < 0);
+		}
+
+		load += len * byte_time;
+		if (load > MAX_LOAD_LIMIT)
+			break;
+
+		ep->active = NULL;
+		ep->length = len;
+		if (last_ep)
+			last_ep->active = ep;
+		else
+			isp116x->atl_active = ep;
+		last_ep = ep;
+	}
+
+	/* Avoid starving of endpoints */
+	if ((&isp116x->async)->next != (&isp116x->async)->prev)
+		list_move(&isp116x->async, (&isp116x->async)->next);
+
+	if (isp116x->atl_active) {
+		preproc_atl_queue(isp116x);
+		pack_fifo(isp116x);
+	}
+}
+
+/*
+  Finish the processed transfers
+*/
+static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
+{
+	struct isp116x_ep *ep;
+	struct urb *urb;
+
+	if (!isp116x->atl_active)
+		return;
+	/* Fifo not ready? */
+	if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE))
+		return;
+
+	atomic_inc(&isp116x->atl_finishing);
+	unpack_fifo(isp116x);
+	postproc_atl_queue(isp116x);
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		urb =
+		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
+		/* USB_PID_ACK check here avoids finishing of
+		   control transfers, for which TD_DATAUNDERRUN
+		   occured, while URB_SHORT_NOT_OK was set */
+		if (urb && urb->status != -EINPROGRESS
+		    && ep->nextpid != USB_PID_ACK)
+			finish_request(isp116x, ep, urb, regs);
+	}
+	atomic_dec(&isp116x->atl_finishing);
+}
+
+static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	u16 irqstat;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock(&isp116x->lock);
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+	irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+	isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+
+	if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+		ret = IRQ_HANDLED;
+		finish_atl_transfers(isp116x, regs);
+	}
+
+	if (irqstat & HCuPINT_OPR) {
+		u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+		isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+		if (intstat & HCINT_UE) {
+			ERR("Unrecoverable error\n");
+			/* What should we do here? Reset?  */
+		}
+		if (intstat & HCINT_RHSC) {
+			isp116x->rhstatus =
+			    isp116x_read_reg32(isp116x, HCRHSTATUS);
+			isp116x->rhport[0] =
+			    isp116x_read_reg32(isp116x, HCRHPORT1);
+			isp116x->rhport[1] =
+			    isp116x_read_reg32(isp116x, HCRHPORT2);
+		}
+		if (intstat & HCINT_RD) {
+			DBG("---- remote wakeup\n");
+			schedule_work(&isp116x->rh_resume);
+			ret = IRQ_HANDLED;
+		}
+		irqstat &= ~HCuPINT_OPR;
+		ret = IRQ_HANDLED;
+	}
+
+	if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+		start_atl_transfers(isp116x);
+	}
+
+	isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+	spin_unlock(&isp116x->lock);
+	return ret;
+}
+
+/*-----------------------------------------------------------------*/
+
+/* usb 1.1 says max 90% of a frame is available for periodic transfers.
+ * this driver doesn't promise that much since it's got to handle an
+ * IRQ per packet; irq handling latencies also use up that time.
+ */
+
+/* out of 1000 us */
+#define	MAX_PERIODIC_LOAD	600
+static int balance(struct isp116x *isp116x, u16 period, u16 load)
+{
+	int i, branch = -ENOSPC;
+
+	/* search for the least loaded schedule branch of that period
+	   which has enough bandwidth left unreserved. */
+	for (i = 0; i < period; i++) {
+		if (branch < 0 || isp116x->load[branch] > isp116x->load[i]) {
+			int j;
+
+			for (j = i; j < PERIODIC_SIZE; j += period) {
+				if ((isp116x->load[j] + load)
+				    > MAX_PERIODIC_LOAD)
+					break;
+			}
+			if (j < PERIODIC_SIZE)
+				continue;
+			branch = i;
+		}
+	}
+	return branch;
+}
+
+/* NB! ALL the code above this point runs with isp116x->lock
+   held, irqs off
+*/
+
+/*-----------------------------------------------------------------*/
+
+static int isp116x_urb_enqueue(struct usb_hcd *hcd,
+			       struct usb_host_endpoint *hep, struct urb *urb,
+			       int mem_flags)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	struct usb_device *udev = urb->dev;
+	unsigned int pipe = urb->pipe;
+	int is_out = !usb_pipein(pipe);
+	int type = usb_pipetype(pipe);
+	int epnum = usb_pipeendpoint(pipe);
+	struct isp116x_ep *ep = NULL;
+	unsigned long flags;
+	int i;
+	int ret = 0;
+
+	urb_dbg(urb, "Enqueue");
+
+	if (type == PIPE_ISOCHRONOUS) {
+		ERR("Isochronous transfers not supported\n");
+		urb_dbg(urb, "Refused to enqueue");
+		return -ENXIO;
+	}
+	/* avoid all allocations within spinlocks: request or endpoint */
+	if (!hep->hcpriv) {
+		ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags);
+		if (!ep)
+			return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+	if (!HC_IS_RUNNING(hcd->state)) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	if (hep->hcpriv)
+		ep = hep->hcpriv;
+	else {
+		INIT_LIST_HEAD(&ep->schedule);
+		ep->udev = usb_get_dev(udev);
+		ep->epnum = epnum;
+		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
+		usb_settoggle(udev, epnum, is_out, 0);
+
+		if (type == PIPE_CONTROL) {
+			ep->nextpid = USB_PID_SETUP;
+		} else if (is_out) {
+			ep->nextpid = USB_PID_OUT;
+		} else {
+			ep->nextpid = USB_PID_IN;
+		}
+
+		if (urb->interval) {
+			/*
+			   With INT URBs submitted, the driver works with SOF
+			   interrupt enabled and ATL interrupt disabled. After
+			   the PTDs are written to fifo ram, the chip starts
+			   fifo processing and usb transfers after the next
+			   SOF and continues until the transfers are finished
+			   (succeeded or failed) or the frame ends. Therefore,
+			   the transfers occur only in every second frame,
+			   while fifo reading/writing and data processing
+			   occur in every other second frame. */
+			if (urb->interval < 2)
+				urb->interval = 2;
+			if (urb->interval > 2 * PERIODIC_SIZE)
+				urb->interval = 2 * PERIODIC_SIZE;
+			ep->period = urb->interval >> 1;
+			ep->branch = PERIODIC_SIZE;
+			ep->load = usb_calc_bus_time(udev->speed,
+						     !is_out,
+						     (type == PIPE_ISOCHRONOUS),
+						     usb_maxpacket(udev, pipe,
+								   is_out)) /
+			    1000;
+		}
+		hep->hcpriv = ep;
+		ep->hep = hep;
+	}
+
+	/* maybe put endpoint into schedule */
+	switch (type) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (list_empty(&ep->schedule))
+			list_add_tail(&ep->schedule, &isp116x->async);
+		break;
+	case PIPE_INTERRUPT:
+		urb->interval = ep->period;
+		ep->length = min((int)ep->maxpacket,
+				 urb->transfer_buffer_length);
+
+		/* urb submitted for already existing endpoint */
+		if (ep->branch < PERIODIC_SIZE)
+			break;
+
+		ret = ep->branch = balance(isp116x, ep->period, ep->load);
+		if (ret < 0)
+			goto fail;
+		ret = 0;
+
+		urb->start_frame = (isp116x->fmindex & (PERIODIC_SIZE - 1))
+		    + ep->branch;
+
+		/* sort each schedule branch by period (slow before fast)
+		   to share the faster parts of the tree without needing
+		   dummy/placeholder nodes */
+		DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+		for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+			struct isp116x_ep **prev = &isp116x->periodic[i];
+			struct isp116x_ep *here = *prev;
+
+			while (here && ep != here) {
+				if (ep->period > here->period)
+					break;
+				prev = &here->next;
+				here = *prev;
+			}
+			if (ep != here) {
+				ep->next = here;
+				*prev = ep;
+			}
+			isp116x->load[i] += ep->load;
+		}
+		hcd->self.bandwidth_allocated += ep->load / ep->period;
+
+		/* switch over to SOFint */
+		if (!isp116x->periodic_count++) {
+			isp116x->irqenb &= ~HCuPINT_ATL;
+			isp116x->irqenb |= HCuPINT_SOF;
+			isp116x_write_reg16(isp116x, HCuPINTENB,
+					    isp116x->irqenb);
+		}
+	}
+
+	/* in case of unlink-during-submit */
+	spin_lock(&urb->lock);
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock(&urb->lock);
+		finish_request(isp116x, ep, urb, NULL);
+		ret = 0;
+		goto fail;
+	}
+	urb->hcpriv = hep;
+	spin_unlock(&urb->lock);
+	start_atl_transfers(isp116x);
+
+      fail:
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return ret;
+}
+
+/*
+   Dequeue URBs.
+*/
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	struct usb_host_endpoint *hep;
+	struct isp116x_ep *ep, *ep_act;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+	hep = urb->hcpriv;
+	/* URB already unlinked (or never linked)? */
+	if (!hep) {
+		spin_unlock_irqrestore(&isp116x->lock, flags);
+		return 0;
+	}
+	ep = hep->hcpriv;
+	WARN_ON(hep != ep->hep);
+
+	/* In front of queue? */
+	if (ep->hep->urb_list.next == &urb->urb_list)
+		/* active? */
+		for (ep_act = isp116x->atl_active; ep_act;
+		     ep_act = ep_act->active)
+			if (ep_act == ep) {
+				VDBG("dequeue, urb %p active; wait for irq\n",
+				     urb);
+				urb = NULL;
+				break;
+			}
+
+	if (urb)
+		finish_request(isp116x, ep, urb, NULL);
+
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return 0;
+}
+
+static void isp116x_endpoint_disable(struct usb_hcd *hcd,
+				     struct usb_host_endpoint *hep)
+{
+	int i;
+	struct isp116x_ep *ep = hep->hcpriv;;
+
+	if (!ep)
+		return;
+
+	/* assume we'd just wait for the irq */
+	for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++)
+		msleep(3);
+	if (!list_empty(&hep->urb_list))
+		WARN("ep %p not empty?\n", ep);
+
+	usb_put_dev(ep->udev);
+	kfree(ep);
+	hep->hcpriv = NULL;
+}
+
+static int isp116x_get_frame(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	u32 fmnum;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+	fmnum = isp116x_read_reg32(isp116x, HCFMNUM);
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return (int)fmnum;
+}
+
+/*----------------------------------------------------------------*/
+
+/*
+  Adapted from ohci-hub.c. Currently we don't support autosuspend.
+*/
+static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	int ports, i, changed = 0;
+
+	if (!HC_IS_RUNNING(hcd->state))
+		return -ESHUTDOWN;
+
+	ports = isp116x->rhdesca & RH_A_NDP;
+
+	/* init status */
+	if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
+		buf[0] = changed = 1;
+	else
+		buf[0] = 0;
+
+	for (i = 0; i < ports; i++) {
+		u32 status = isp116x->rhport[i];
+
+		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+			      | RH_PS_OCIC | RH_PS_PRSC)) {
+			changed = 1;
+			buf[0] |= 1 << (i + 1);
+			continue;
+		}
+	}
+	return changed;
+}
+
+static void isp116x_hub_descriptor(struct isp116x *isp116x,
+				   struct usb_hub_descriptor *desc)
+{
+	u32 reg = isp116x->rhdesca;
+
+	desc->bDescriptorType = 0x29;
+	desc->bDescLength = 9;
+	desc->bHubContrCurrent = 0;
+	desc->bNbrPorts = (u8) (reg & 0x3);
+	/* Power switching, device type, overcurrent. */
+	desc->wHubCharacteristics =
+	    (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f));
+	desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
+	/* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */
+	desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
+	desc->bitmap[1] = ~0;
+}
+
+/* Perform reset of a given port.
+   It would be great to just start the reset and let the
+   USB core to clear the reset in due time. However,
+   root hub ports should be reset for at least 50 ms, while
+   our chip stays in reset for about 10 ms. I.e., we must
+   repeatedly reset it ourself here.
+*/
+static inline void root_port_reset(struct isp116x *isp116x, unsigned port)
+{
+	u32 tmp;
+	unsigned long flags, t;
+
+	/* Root hub reset should be 50 ms, but some devices
+	   want it even longer. */
+	t = jiffies + msecs_to_jiffies(100);
+
+	while (time_before(jiffies, t)) {
+		spin_lock_irqsave(&isp116x->lock, flags);
+		/* spin until any current reset finishes */
+		for (;;) {
+			tmp = isp116x_read_reg32(isp116x, port ?
+						 HCRHPORT2 : HCRHPORT1);
+			if (!(tmp & RH_PS_PRS))
+				break;
+			udelay(500);
+		}
+		/* Don't reset a disconnected port */
+		if (!(tmp & RH_PS_CCS)) {
+			spin_unlock_irqrestore(&isp116x->lock, flags);
+			break;
+		}
+		/* Reset lasts 10ms (claims datasheet) */
+		isp116x_write_reg32(isp116x, port ? HCRHPORT2 :
+				    HCRHPORT1, (RH_PS_PRS));
+		spin_unlock_irqrestore(&isp116x->lock, flags);
+		msleep(10);
+	}
+}
+
+/* Adapted from ohci-hub.c */
+static int isp116x_hub_control(struct usb_hcd *hcd,
+			       u16 typeReq,
+			       u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	int ret = 0;
+	unsigned long flags;
+	int ports = isp116x->rhdesca & RH_A_NDP;
+	u32 tmp = 0;
+
+	switch (typeReq) {
+	case ClearHubFeature:
+		DBG("ClearHubFeature: ");
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			DBG("C_HUB_OVER_CURRENT\n");
+			spin_lock_irqsave(&isp116x->lock, flags);
+			isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+			spin_unlock_irqrestore(&isp116x->lock, flags);
+		case C_HUB_LOCAL_POWER:
+			DBG("C_HUB_LOCAL_POWER\n");
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetHubFeature:
+		DBG("SetHubFeature: ");
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+		case C_HUB_LOCAL_POWER:
+			DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case GetHubDescriptor:
+		DBG("GetHubDescriptor\n");
+		isp116x_hub_descriptor(isp116x,
+				       (struct usb_hub_descriptor *)buf);
+		break;
+	case GetHubStatus:
+		DBG("GetHubStatus\n");
+		*(__le32 *) buf = cpu_to_le32(0);
+		break;
+	case GetPortStatus:
+		DBG("GetPortStatus\n");
+		if (!wIndex || wIndex > ports)
+			goto error;
+		tmp = isp116x->rhport[--wIndex];
+		*(__le32 *) buf = cpu_to_le32(tmp);
+		DBG("GetPortStatus: port[%d]  %08x\n", wIndex + 1, tmp);
+		break;
+	case ClearPortFeature:
+		DBG("ClearPortFeature: ");
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			DBG("USB_PORT_FEAT_ENABLE\n");
+			tmp = RH_PS_CCS;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			DBG("USB_PORT_FEAT_C_ENABLE\n");
+			tmp = RH_PS_PESC;
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			DBG("USB_PORT_FEAT_SUSPEND\n");
+			tmp = RH_PS_POCI;
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			DBG("USB_PORT_FEAT_C_SUSPEND\n");
+			tmp = RH_PS_PSSC;
+			break;
+		case USB_PORT_FEAT_POWER:
+			DBG("USB_PORT_FEAT_POWER\n");
+			tmp = RH_PS_LSDA;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			DBG("USB_PORT_FEAT_C_CONNECTION\n");
+			tmp = RH_PS_CSC;
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			DBG("USB_PORT_FEAT_C_OVER_CURRENT\n");
+			tmp = RH_PS_OCIC;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			DBG("USB_PORT_FEAT_C_RESET\n");
+			tmp = RH_PS_PRSC;
+			break;
+		default:
+			goto error;
+		}
+		spin_lock_irqsave(&isp116x->lock, flags);
+		isp116x_write_reg32(isp116x, wIndex
+				    ? HCRHPORT2 : HCRHPORT1, tmp);
+		isp116x->rhport[wIndex] =
+		    isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+		spin_unlock_irqrestore(&isp116x->lock, flags);
+		break;
+	case SetPortFeature:
+		DBG("SetPortFeature: ");
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			DBG("USB_PORT_FEAT_SUSPEND\n");
+			spin_lock_irqsave(&isp116x->lock, flags);
+			isp116x_write_reg32(isp116x, wIndex
+					    ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS);
+			break;
+		case USB_PORT_FEAT_POWER:
+			DBG("USB_PORT_FEAT_POWER\n");
+			spin_lock_irqsave(&isp116x->lock, flags);
+			isp116x_write_reg32(isp116x, wIndex
+					    ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS);
+			break;
+		case USB_PORT_FEAT_RESET:
+			DBG("USB_PORT_FEAT_RESET\n");
+			root_port_reset(isp116x, wIndex);
+			spin_lock_irqsave(&isp116x->lock, flags);
+			break;
+		default:
+			goto error;
+		}
+		isp116x->rhport[wIndex] =
+		    isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+		spin_unlock_irqrestore(&isp116x->lock, flags);
+		break;
+
+	default:
+	      error:
+		/* "protocol stall" on error */
+		DBG("PROTOCOL STALL\n");
+		ret = -EPIPE;
+	}
+	return ret;
+}
+
+#ifdef	CONFIG_PM
+
+static int isp116x_hub_suspend(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	unsigned long flags;
+	u32 val;
+	int ret = 0;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+
+	val = isp116x_read_reg32(isp116x, HCCONTROL);
+	switch (val & HCCONTROL_HCFS) {
+	case HCCONTROL_USB_OPER:
+		hcd->state = HC_STATE_QUIESCING;
+		val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
+		val |= HCCONTROL_USB_SUSPEND;
+		if (hcd->remote_wakeup)
+			val |= HCCONTROL_RWE;
+		/* Wait for usb transfers to finish */
+		mdelay(2);
+		isp116x_write_reg32(isp116x, HCCONTROL, val);
+		hcd->state = HC_STATE_SUSPENDED;
+		/* Wait for devices to suspend */
+		mdelay(5);
+	case HCCONTROL_USB_SUSPEND:
+		break;
+	case HCCONTROL_USB_RESUME:
+		isp116x_write_reg32(isp116x, HCCONTROL,
+				    (val & ~HCCONTROL_HCFS) |
+				    HCCONTROL_USB_RESET);
+	case HCCONTROL_USB_RESET:
+		ret = -EBUSY;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return ret;
+}
+
+static int isp116x_hub_resume(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	u32 val;
+	int ret = -EINPROGRESS;
+
+	msleep(5);
+	spin_lock_irq(&isp116x->lock);
+
+	val = isp116x_read_reg32(isp116x, HCCONTROL);
+	switch (val & HCCONTROL_HCFS) {
+	case HCCONTROL_USB_SUSPEND:
+		val &= ~HCCONTROL_HCFS;
+		val |= HCCONTROL_USB_RESUME;
+		isp116x_write_reg32(isp116x, HCCONTROL, val);
+	case HCCONTROL_USB_RESUME:
+		break;
+	case HCCONTROL_USB_OPER:
+		/* Without setting power_state here the
+		   SUSPENDED state won't be removed from
+		   sysfs/usbN/power.state as a response to remote
+		   wakeup. Maybe in the future. */
+		hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+		ret = 0;
+		break;
+	default:
+		ret = -EBUSY;
+	}
+
+	if (ret != -EINPROGRESS) {
+		spin_unlock_irq(&isp116x->lock);
+		return ret;
+	}
+
+	val = isp116x->rhdesca & RH_A_NDP;
+	while (val--) {
+		u32 stat =
+		    isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);
+		/* force global, not selective, resume */
+		if (!(stat & RH_PS_PSS))
+			continue;
+		DBG("%s: Resuming port %d\n", __func__, val);
+		isp116x_write_reg32(isp116x, RH_PS_POCI, val
+				    ? HCRHPORT2 : HCRHPORT1);
+	}
+	spin_unlock_irq(&isp116x->lock);
+
+	hcd->state = HC_STATE_RESUMING;
+	mdelay(20);
+
+	/* Go operational */
+	spin_lock_irq(&isp116x->lock);
+	val = isp116x_read_reg32(isp116x, HCCONTROL);
+	isp116x_write_reg32(isp116x, HCCONTROL,
+			    (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
+	spin_unlock_irq(&isp116x->lock);
+	/* see analogous comment above */
+	hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+	hcd->state = HC_STATE_RUNNING;
+
+	return 0;
+}
+
+static void isp116x_rh_resume(void *_hcd)
+{
+	struct usb_hcd *hcd = _hcd;
+
+	usb_resume_device(hcd->self.root_hub);
+}
+
+#else
+
+#define	isp116x_hub_suspend	NULL
+#define	isp116x_hub_resume	NULL
+
+static void isp116x_rh_resume(void *_hcd)
+{
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILE
+
+static inline void create_debug_file(struct isp116x *isp116x)
+{
+}
+
+static inline void remove_debug_file(struct isp116x *isp116x)
+{
+}
+
+#else
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_irq(struct seq_file *s, char *label, u16 mask)
+{
+	seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask,
+		   mask & HCuPINT_CLKRDY ? " clkrdy" : "",
+		   mask & HCuPINT_SUSP ? " susp" : "",
+		   mask & HCuPINT_OPR ? " opr" : "",
+		   mask & HCuPINT_AIIEOT ? " eot" : "",
+		   mask & HCuPINT_ATL ? " atl" : "",
+		   mask & HCuPINT_SOF ? " sof" : "");
+}
+
+static void dump_int(struct seq_file *s, char *label, u32 mask)
+{
+	seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask,
+		   mask & HCINT_MIE ? " MIE" : "",
+		   mask & HCINT_RHSC ? " rhsc" : "",
+		   mask & HCINT_FNO ? " fno" : "",
+		   mask & HCINT_UE ? " ue" : "",
+		   mask & HCINT_RD ? " rd" : "",
+		   mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");
+}
+
+static int proc_isp116x_show(struct seq_file *s, void *unused)
+{
+	struct isp116x *isp116x = s->private;
+	struct isp116x_ep *ep;
+	struct urb *urb;
+	unsigned i;
+	char *str;
+
+	seq_printf(s, "%s\n%s version %s\n",
+		   isp116x_to_hcd(isp116x)->product_desc, hcd_name,
+		   DRIVER_VERSION);
+
+	if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) {
+		seq_printf(s, "HCD is suspended\n");
+		return 0;
+	}
+	if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) {
+		seq_printf(s, "HCD not running\n");
+		return 0;
+	}
+
+	spin_lock_irq(&isp116x->lock);
+
+	dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB));
+	dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT));
+	dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB));
+	dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT));
+
+	list_for_each_entry(ep, &isp116x->async, schedule) {
+
+		switch (ep->nextpid) {
+		case USB_PID_IN:
+			str = "in";
+			break;
+		case USB_PID_OUT:
+			str = "out";
+			break;
+		case USB_PID_SETUP:
+			str = "setup";
+			break;
+		case USB_PID_ACK:
+			str = "status";
+			break;
+		default:
+			str = "?";
+			break;
+		};
+		seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep,
+			   ep->epnum, str, ep->maxpacket);
+		list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {
+			seq_printf(s, "  urb%p, %d/%d\n", urb,
+				   urb->actual_length,
+				   urb->transfer_buffer_length);
+		}
+	}
+	if (!list_empty(&isp116x->async))
+		seq_printf(s, "\n");
+
+	seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
+
+	for (i = 0; i < PERIODIC_SIZE; i++) {
+		ep = isp116x->periodic[i];
+		if (!ep)
+			continue;
+		seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]);
+
+		/* DUMB: prints shared entries multiple times */
+		do {
+			seq_printf(s, "   %d/%p (%sdev%d ep%d%s max %d)\n",
+				   ep->period, ep,
+				   (ep->udev->speed ==
+				    USB_SPEED_FULL) ? "" : "ls ",
+				   ep->udev->devnum, ep->epnum,
+				   (ep->epnum ==
+				    0) ? "" : ((ep->nextpid ==
+						USB_PID_IN) ? "in" : "out"),
+				   ep->maxpacket);
+			ep = ep->next;
+		} while (ep);
+	}
+	spin_unlock_irq(&isp116x->lock);
+	seq_printf(s, "\n");
+
+	return 0;
+}
+
+static int proc_isp116x_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_isp116x_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+	.open = proc_isp116x_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* expect just one isp116x per system */
+static const char proc_filename[] = "driver/isp116x";
+
+static void create_debug_file(struct isp116x *isp116x)
+{
+	struct proc_dir_entry *pde;
+
+	pde = create_proc_entry(proc_filename, 0, NULL);
+	if (pde == NULL)
+		return;
+
+	pde->proc_fops = &proc_ops;
+	pde->data = isp116x;
+	isp116x->pde = pde;
+}
+
+static void remove_debug_file(struct isp116x *isp116x)
+{
+	if (isp116x->pde)
+		remove_proc_entry(proc_filename, NULL);
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+/*
+  Software reset - can be called from any contect.
+*/
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+	int retries = 15;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+	isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+	isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+	while (--retries) {
+		/* It usually resets within 1 ms */
+		mdelay(1);
+		if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+			break;
+	}
+	if (!retries) {
+		ERR("Software reset timeout\n");
+		ret = -ETIME;
+	}
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return ret;
+}
+
+/*
+  Reset. Tries to perform platform-specific hardware
+  reset first; falls back to software reset.
+*/
+static int isp116x_reset(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	unsigned long t;
+	u16 clkrdy = 0;
+	int ret = 0, timeout = 15 /* ms */ ;
+
+	if (isp116x->board && isp116x->board->reset) {
+		/* Hardware reset */
+		isp116x->board->reset(hcd->self.controller, 1);
+		msleep(10);
+		if (isp116x->board->clock)
+			isp116x->board->clock(hcd->self.controller, 1);
+		msleep(1);
+		isp116x->board->reset(hcd->self.controller, 0);
+	} else
+		ret = isp116x_sw_reset(isp116x);
+
+	if (ret)
+		return ret;
+
+	t = jiffies + msecs_to_jiffies(timeout);
+	while (time_before_eq(jiffies, t)) {
+		msleep(4);
+		spin_lock_irq(&isp116x->lock);
+		clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+		spin_unlock_irq(&isp116x->lock);
+		if (clkrdy)
+			break;
+	}
+	if (!clkrdy) {
+		ERR("Clock not ready after 20ms\n");
+		/* After sw_reset the clock won't report to be ready, if
+		   H_WAKEUP pin is high. */
+		if (!isp116x->board || !isp116x->board->reset)
+			ERR("The driver does not support hardware wakeup.\n");
+			ERR("Please make sure that the H_WAKEUP pin "
+				"is pulled low!\n");
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+static void isp116x_stop(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+	/* Switch off ports' power, some devices don't come up
+	   after next 'insmod' without this */
+	val = isp116x_read_reg32(isp116x, HCRHDESCA);
+	val &= ~(RH_A_NPS | RH_A_PSM);
+	isp116x_write_reg32(isp116x, HCRHDESCA, val);
+	isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+
+	/* Put the chip into reset state */
+	if (isp116x->board && isp116x->board->reset)
+		isp116x->board->reset(hcd->self.controller, 0);
+	else
+		isp116x_sw_reset(isp116x);
+
+	/* Stop the clock */
+	if (isp116x->board && isp116x->board->clock)
+		isp116x->board->clock(hcd->self.controller, 0);
+}
+
+/*
+  Configure the chip. The chip must be successfully reset by now.
+*/
+static int isp116x_start(struct usb_hcd *hcd)
+{
+	struct isp116x *isp116x = hcd_to_isp116x(hcd);
+	struct isp116x_platform_data *board = isp116x->board;
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isp116x->lock, flags);
+
+	/* clear interrupt status and disable all interrupt sources */
+	isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+	val = isp116x_read_reg16(isp116x, HCCHIPID);
+	if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+		ERR("Invalid chip ID %04x\n", val);
+		spin_unlock_irqrestore(&isp116x->lock, flags);
+		return -ENODEV;
+	}
+
+	isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+	isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+	/* ----- HW conf */
+	val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1);
+	if (board->sel15Kres)
+		val |= HCHWCFG_15KRSEL;
+	/* Remote wakeup won't work without working clock */
+	if (board->clknotstop || board->remote_wakeup_enable)
+		val |= HCHWCFG_CLKNOTSTOP;
+	if (board->oc_enable)
+		val |= HCHWCFG_ANALOG_OC;
+	if (board->int_act_high)
+		val |= HCHWCFG_INT_POL;
+	if (board->int_edge_triggered)
+		val |= HCHWCFG_INT_TRIGGER;
+	isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+	/* ----- Root hub conf */
+	val = 0;
+	/* AN10003_1.pdf recommends NPS to be always 1 */
+	if (board->no_power_switching)
+		val |= RH_A_NPS;
+	if (board->power_switching_mode)
+		val |= RH_A_PSM;
+	if (board->potpg)
+		val |= (board->potpg << 24) & RH_A_POTPGT;
+	else
+		val |= (25 << 24) & RH_A_POTPGT;
+	isp116x_write_reg32(isp116x, HCRHDESCA, val);
+	isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+	val = RH_B_PPCM;
+	isp116x_write_reg32(isp116x, HCRHDESCB, val);
+	isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+	val = 0;
+	if (board->remote_wakeup_enable) {
+		hcd->can_wakeup = 1;
+		val |= RH_HS_DRWE;
+	}
+	isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+	isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+	isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+	hcd->state = HC_STATE_RUNNING;
+
+	/* Set up interrupts */
+	isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE;
+	if (board->remote_wakeup_enable)
+		isp116x->intenb |= HCINT_RD;
+	isp116x->irqenb = HCuPINT_ATL | HCuPINT_OPR;	/* | HCuPINT_SUSP; */
+	isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb);
+	isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+
+	/* Go operational */
+	val = HCCONTROL_USB_OPER;
+	/* Remote wakeup connected - NOT SUPPORTED */
+	/*  if (board->remote_wakeup_connected)
+	   val |= HCCONTROL_RWC;  */
+	if (board->remote_wakeup_enable)
+		val |= HCCONTROL_RWE;
+	isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+	/* Disable ports to avoid race in device enumeration */
+	isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+	isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+	isp116x_show_regs(isp116x);
+	spin_unlock_irqrestore(&isp116x->lock, flags);
+	return 0;
+}
+
+/*-----------------------------------------------------------------*/
+
+static struct hc_driver isp116x_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "ISP116x Host Controller",
+	.hcd_priv_size = sizeof(struct isp116x),
+
+	.irq = isp116x_irq,
+	.flags = HCD_USB11,
+
+	.reset = isp116x_reset,
+	.start = isp116x_start,
+	.stop = isp116x_stop,
+
+	.urb_enqueue = isp116x_urb_enqueue,
+	.urb_dequeue = isp116x_urb_dequeue,
+	.endpoint_disable = isp116x_endpoint_disable,
+
+	.get_frame_number = isp116x_get_frame,
+
+	.hub_status_data = isp116x_hub_status_data,
+	.hub_control = isp116x_hub_control,
+	.hub_suspend = isp116x_hub_suspend,
+	.hub_resume = isp116x_hub_resume,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init_or_module isp116x_remove(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct isp116x *isp116x;
+	struct platform_device *pdev;
+	struct resource *res;
+
+	if(!hcd)
+		return 0;
+	isp116x = hcd_to_isp116x(hcd);
+	pdev = container_of(dev, struct platform_device, dev);
+	remove_debug_file(isp116x);
+	usb_remove_hcd(hcd);
+
+	iounmap(isp116x->data_reg);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	release_mem_region(res->start, 2);
+	iounmap(isp116x->addr_reg);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, 2);
+
+	usb_put_hcd(hcd);
+	return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init isp116x_probe(struct device *dev)
+{
+	struct usb_hcd *hcd;
+	struct isp116x *isp116x;
+	struct platform_device *pdev;
+	struct resource *addr, *data;
+	void __iomem *addr_reg;
+	void __iomem *data_reg;
+	int irq;
+	int ret = 0;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	if (pdev->num_resources < 3) {
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	irq = platform_get_irq(pdev, 0);
+	if (!addr || !data || irq < 0) {
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	if (dev->dma_mask) {
+		DBG("DMA not supported\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	if (!request_mem_region(addr->start, 2, hcd_name)) {
+		ret = -EBUSY;
+		goto err1;
+	}
+	addr_reg = ioremap(addr->start, resource_len(addr));
+	if (addr_reg == NULL) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+	if (!request_mem_region(data->start, 2, hcd_name)) {
+		ret = -EBUSY;
+		goto err3;
+	}
+	data_reg = ioremap(data->start, resource_len(data));
+	if (data_reg == NULL) {
+		ret = -ENOMEM;
+		goto err4;
+	}
+
+	/* allocate and initialize hcd */
+	hcd = usb_create_hcd(&isp116x_hc_driver, dev, dev->bus_id);
+	if (!hcd) {
+		ret = -ENOMEM;
+		goto err5;
+	}
+	/* this rsrc_start is bogus */
+	hcd->rsrc_start = addr->start;
+	isp116x = hcd_to_isp116x(hcd);
+	isp116x->data_reg = data_reg;
+	isp116x->addr_reg = addr_reg;
+	spin_lock_init(&isp116x->lock);
+	INIT_LIST_HEAD(&isp116x->async);
+	INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
+	isp116x->board = dev->platform_data;
+
+	if (!isp116x->board) {
+		ERR("Platform data structure not initialized\n");
+		ret = -ENODEV;
+		goto err6;
+	}
+	if (isp116x_check_platform_delay(isp116x)) {
+		ERR("USE_PLATFORM_DELAY defined, but delay function not "
+		    "implemented.\n");
+		ERR("See comments in drivers/usb/host/isp116x-hcd.c\n");
+		ret = -ENODEV;
+		goto err6;
+	}
+
+	ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+	if (ret != 0)
+		goto err6;
+
+	create_debug_file(isp116x);
+	return 0;
+
+      err6:
+	usb_put_hcd(hcd);
+      err5:
+	iounmap(data_reg);
+      err4:
+	release_mem_region(data->start, 2);
+      err3:
+	iounmap(addr_reg);
+      err2:
+	release_mem_region(addr->start, 2);
+      err1:
+	ERR("init error, %d\n", ret);
+	return ret;
+}
+
+#ifdef	CONFIG_PM
+/*
+  Suspend of platform device
+*/
+static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase)
+{
+	int ret = 0;
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	VDBG("%s: state %x, phase %x\n", __func__, state, phase);
+
+	if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN)
+		return 0;
+
+	ret = usb_suspend_device(hcd->self.root_hub, state);
+	if (!ret) {
+		dev->power.power_state = state;
+		INFO("%s suspended\n", (char *)hcd_name);
+	} else
+		ERR("%s suspend failed\n", (char *)hcd_name);
+
+	return ret;
+}
+
+/*
+  Resume platform device
+*/
+static int isp116x_resume(struct device *dev, u32 phase)
+{
+	int ret = 0;
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	VDBG("%s:  state %x, phase %x\n", __func__, dev->power.power_state,
+	     phase);
+	if (phase != RESUME_POWER_ON)
+		return 0;
+
+	ret = usb_resume_device(hcd->self.root_hub);
+	if (!ret) {
+		dev->power.power_state = PMSG_ON;
+		VDBG("%s resumed\n", (char *)hcd_name);
+	}
+	return ret;
+}
+
+#else
+
+#define	isp116x_suspend    NULL
+#define	isp116x_resume     NULL
+
+#endif
+
+static struct device_driver isp116x_driver = {
+	.name = (char *)hcd_name,
+	.bus = &platform_bus_type,
+	.probe = isp116x_probe,
+	.remove = isp116x_remove,
+	.suspend = isp116x_suspend,
+	.resume = isp116x_resume,
+};
+
+/*-----------------------------------------------------------------*/
+
+static int __init isp116x_init(void)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
+	return driver_register(&isp116x_driver);
+}
+
+module_init(isp116x_init);
+
+static void __exit isp116x_cleanup(void)
+{
+	driver_unregister(&isp116x_driver);
+}
+
+module_exit(isp116x_cleanup);
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
new file mode 100644
index 0000000..5887347
--- /dev/null
+++ b/drivers/usb/host/isp116x.h
@@ -0,0 +1,583 @@
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ */
+
+/* us of 1ms frame */
+#define  MAX_LOAD_LIMIT		850
+
+/* Full speed: max # of bytes to transfer for a single urb
+   at a time must be < 1024 && must be multiple of 64.
+   832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED	832
+
+/* Low speed: there is no reason to schedule in very big
+   chunks; often the requested long transfers are for
+   string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED	64
+
+/* Bytetime (us), a rough indication of how much time it
+   would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED	1
+#define BYTE_TIME_LOWSPEED	20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE	4096
+#define ISP116x_ITL_BUFSIZE	0
+#define ISP116x_ATL_BUFSIZE	((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET	0x80
+
+/*------------ ISP116x registers/bits ------------*/
+#define	HCREVISION	0x00
+#define	HCCONTROL	0x01
+#define		HCCONTROL_HCFS	(3 << 6)	/* host controller
+						   functional state */
+#define		HCCONTROL_USB_RESET	(0 << 6)
+#define		HCCONTROL_USB_RESUME	(1 << 6)
+#define		HCCONTROL_USB_OPER	(2 << 6)
+#define		HCCONTROL_USB_SUSPEND	(3 << 6)
+#define		HCCONTROL_RWC	(1 << 9)	/* remote wakeup connected */
+#define		HCCONTROL_RWE	(1 << 10)	/* remote wakeup enable */
+#define	HCCMDSTAT	0x02
+#define		HCCMDSTAT_HCR	(1 << 0)	/* host controller reset */
+#define		HCCMDSTAT_SOC	(3 << 16)	/* scheduling overrun count */
+#define	HCINTSTAT	0x03
+#define		HCINT_SO	(1 << 0)	/* scheduling overrun */
+#define		HCINT_WDH	(1 << 1)	/* writeback of done_head */
+#define		HCINT_SF	(1 << 2)	/* start frame */
+#define		HCINT_RD	(1 << 3)	/* resume detect */
+#define		HCINT_UE	(1 << 4)	/* unrecoverable error */
+#define		HCINT_FNO	(1 << 5)	/* frame number overflow */
+#define		HCINT_RHSC	(1 << 6)	/* root hub status change */
+#define		HCINT_OC	(1 << 30)	/* ownership change */
+#define		HCINT_MIE	(1 << 31)	/* master interrupt enable */
+#define	HCINTENB	0x04
+#define	HCINTDIS	0x05
+#define	HCFMINTVL	0x0d
+#define	HCFMREM		0x0e
+#define	HCFMNUM		0x0f
+#define	HCLSTHRESH	0x11
+#define	HCRHDESCA	0x12
+#define		RH_A_NDP	(0x3 << 0)	/* # downstream ports */
+#define		RH_A_PSM	(1 << 8)	/* power switching mode */
+#define		RH_A_NPS	(1 << 9)	/* no power switching */
+#define		RH_A_DT		(1 << 10)	/* device type (mbz) */
+#define		RH_A_OCPM	(1 << 11)	/* overcurrent protection
+						   mode */
+#define		RH_A_NOCP	(1 << 12)	/* no overcurrent protection */
+#define		RH_A_POTPGT	(0xff << 24)	/* power on -> power good
+						   time */
+#define	HCRHDESCB	0x13
+#define		RH_B_DR		(0xffff << 0)	/* device removable flags */
+#define		RH_B_PPCM	(0xffff << 16)	/* port power control mask */
+#define	HCRHSTATUS	0x14
+#define		RH_HS_LPS	(1 << 0)	/* local power status */
+#define		RH_HS_OCI	(1 << 1)	/* over current indicator */
+#define		RH_HS_DRWE	(1 << 15)	/* device remote wakeup
+						   enable */
+#define		RH_HS_LPSC	(1 << 16)	/* local power status change */
+#define		RH_HS_OCIC	(1 << 17)	/* over current indicator
+						   change */
+#define		RH_HS_CRWE	(1 << 31)	/* clear remote wakeup
+						   enable */
+#define	HCRHPORT1	0x15
+#define		RH_PS_CCS	(1 << 0)	/* current connect status */
+#define		RH_PS_PES	(1 << 1)	/* port enable status */
+#define		RH_PS_PSS	(1 << 2)	/* port suspend status */
+#define		RH_PS_POCI	(1 << 3)	/* port over current
+						   indicator */
+#define		RH_PS_PRS	(1 << 4)	/* port reset status */
+#define		RH_PS_PPS	(1 << 8)	/* port power status */
+#define		RH_PS_LSDA	(1 << 9)	/* low speed device attached */
+#define		RH_PS_CSC	(1 << 16)	/* connect status change */
+#define		RH_PS_PESC	(1 << 17)	/* port enable status change */
+#define		RH_PS_PSSC	(1 << 18)	/* port suspend status
+						   change */
+#define		RH_PS_OCIC	(1 << 19)	/* over current indicator
+						   change */
+#define		RH_PS_PRSC	(1 << 20)	/* port reset status change */
+#define		HCRHPORT_CLRMASK	(0x1f << 16)
+#define	HCRHPORT2	0x16
+#define	HCHWCFG		0x20
+#define		HCHWCFG_15KRSEL		(1 << 12)
+#define		HCHWCFG_CLKNOTSTOP	(1 << 11)
+#define		HCHWCFG_ANALOG_OC	(1 << 10)
+#define		HCHWCFG_DACK_MODE	(1 << 8)
+#define		HCHWCFG_EOT_POL		(1 << 7)
+#define		HCHWCFG_DACK_POL	(1 << 6)
+#define		HCHWCFG_DREQ_POL	(1 << 5)
+#define		HCHWCFG_DBWIDTH_MASK	(0x03 << 3)
+#define		HCHWCFG_DBWIDTH(n)	(((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define		HCHWCFG_INT_POL		(1 << 2)
+#define		HCHWCFG_INT_TRIGGER	(1 << 1)
+#define		HCHWCFG_INT_ENABLE	(1 << 0)
+#define	HCDMACFG	0x21
+#define		HCDMACFG_BURST_LEN_MASK	(0x03 << 5)
+#define		HCDMACFG_BURST_LEN(n)	(((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define		HCDMACFG_BURST_LEN_1	HCDMACFG_BURST_LEN(0)
+#define		HCDMACFG_BURST_LEN_4	HCDMACFG_BURST_LEN(1)
+#define		HCDMACFG_BURST_LEN_8	HCDMACFG_BURST_LEN(2)
+#define		HCDMACFG_DMA_ENABLE	(1 << 4)
+#define		HCDMACFG_BUF_TYPE_MASK	(0x07 << 1)
+#define		HCDMACFG_CTR_SEL	(1 << 2)
+#define		HCDMACFG_ITLATL_SEL	(1 << 1)
+#define		HCDMACFG_DMA_RW_SELECT	(1 << 0)
+#define	HCXFERCTR	0x22
+#define	HCuPINT		0x24
+#define		HCuPINT_SOF		(1 << 0)
+#define		HCuPINT_ATL		(1 << 1)
+#define		HCuPINT_AIIEOT		(1 << 2)
+#define		HCuPINT_OPR		(1 << 4)
+#define		HCuPINT_SUSP		(1 << 5)
+#define		HCuPINT_CLKRDY		(1 << 6)
+#define	HCuPINTENB	0x25
+#define	HCCHIPID	0x27
+#define		HCCHIPID_MASK		0xff00
+#define		HCCHIPID_MAGIC		0x6100
+#define	HCSCRATCH	0x28
+#define	HCSWRES		0x29
+#define		HCSWRES_MAGIC		0x00f6
+#define	HCITLBUFLEN	0x2a
+#define	HCATLBUFLEN	0x2b
+#define	HCBUFSTAT	0x2c
+#define		HCBUFSTAT_ITL0_FULL	(1 << 0)
+#define		HCBUFSTAT_ITL1_FULL	(1 << 1)
+#define		HCBUFSTAT_ATL_FULL	(1 << 2)
+#define		HCBUFSTAT_ITL0_DONE	(1 << 3)
+#define		HCBUFSTAT_ITL1_DONE	(1 << 4)
+#define		HCBUFSTAT_ATL_DONE	(1 << 5)
+#define	HCRDITL0LEN	0x2d
+#define	HCRDITL1LEN	0x2e
+#define	HCITLPORT	0x40
+#define	HCATLPORT	0x41
+
+/* Philips transfer descriptor */
+struct ptd {
+	u16 count;
+#define	PTD_COUNT_MSK	(0x3ff << 0)
+#define	PTD_TOGGLE_MSK	(1 << 10)
+#define	PTD_ACTIVE_MSK	(1 << 11)
+#define	PTD_CC_MSK	(0xf << 12)
+	u16 mps;
+#define	PTD_MPS_MSK	(0x3ff << 0)
+#define	PTD_SPD_MSK	(1 << 10)
+#define	PTD_LAST_MSK	(1 << 11)
+#define	PTD_EP_MSK	(0xf << 12)
+	u16 len;
+#define	PTD_LEN_MSK	(0x3ff << 0)
+#define	PTD_DIR_MSK	(3 << 10)
+#define	PTD_DIR_SETUP	(0)
+#define	PTD_DIR_OUT	(1)
+#define	PTD_DIR_IN	(2)
+#define	PTD_B5_5_MSK	(1 << 13)
+	u16 faddr;
+#define	PTD_FA_MSK	(0x7f << 0)
+#define	PTD_FMT_MSK	(1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p)	(((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v)		(((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p)	(((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v)		(((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p)	(((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v)		(((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p)		(((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v)		(((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p)		(((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v)		(((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p)		(((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v)		(((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p)		(((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v)		(((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p)		(((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v)		(((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p)		(((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v)		(((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p)		(((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v)		(((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p)		(((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v)		(((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p)		(((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v)		(((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p)		(((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v)		(((v) << 7) & PTD_FMT_MSK)
+
+/*  Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+/* map PTD status codes (CC) to errno values */
+static const int cc_to_error[16] = {
+	/* No  Error  */ 0,
+	/* CRC Error  */ -EILSEQ,
+	/* Bit Stuff  */ -EPROTO,
+	/* Data Togg  */ -EILSEQ,
+	/* Stall      */ -EPIPE,
+	/* DevNotResp */ -ETIMEDOUT,
+	/* PIDCheck   */ -EPROTO,
+	/* UnExpPID   */ -EPROTO,
+	/* DataOver   */ -EOVERFLOW,
+	/* DataUnder  */ -EREMOTEIO,
+	/* (for hw)   */ -EIO,
+	/* (for hw)   */ -EIO,
+	/* BufferOver */ -ECOMM,
+	/* BuffUnder  */ -ENOSR,
+	/* (for HCD)  */ -EALREADY,
+	/* (for HCD)  */ -EALREADY
+};
+
+/*--------------------------------------------------------------*/
+
+#define	LOG2_PERIODIC_SIZE	5	/* arbitrary; this matches OHCI */
+#define	PERIODIC_SIZE		(1 << LOG2_PERIODIC_SIZE)
+
+struct isp116x {
+	spinlock_t lock;
+	struct work_struct rh_resume;
+
+	void __iomem *addr_reg;
+	void __iomem *data_reg;
+
+	struct isp116x_platform_data *board;
+
+	struct proc_dir_entry *pde;
+	unsigned long stat1, stat2, stat4, stat8, stat16;
+
+	/* HC registers */
+	u32 intenb;		/* "OHCI" interrupts */
+	u16 irqenb;		/* uP interrupts */
+
+	/* Root hub registers */
+	u32 rhdesca;
+	u32 rhdescb;
+	u32 rhstatus;
+	u32 rhport[2];
+
+	/* async schedule: control, bulk */
+	struct list_head async;
+
+	/* periodic schedule: int */
+	u16 load[PERIODIC_SIZE];
+	struct isp116x_ep *periodic[PERIODIC_SIZE];
+	unsigned periodic_count;
+	u16 fmindex;
+
+	/* Schedule for the current frame */
+	struct isp116x_ep *atl_active;
+	int atl_buflen;
+	int atl_bufshrt;
+	int atl_last_dir;
+	atomic_t atl_finishing;
+};
+
+static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd)
+{
+	return (struct isp116x *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x)
+{
+	return container_of((void *)isp116x, struct usb_hcd, hcd_priv);
+}
+
+struct isp116x_ep {
+	struct usb_host_endpoint *hep;
+	struct usb_device *udev;
+	struct ptd ptd;
+
+	u8 maxpacket;
+	u8 epnum;
+	u8 nextpid;
+	u16 error_count;
+	u16 length;		/* of current packet */
+	unsigned char *data;	/* to databuf */
+	/* queue of active EP's (the ones scheduled for the
+	   current frame) */
+	struct isp116x_ep *active;
+
+	/* periodic schedule */
+	u16 period;
+	u16 branch;
+	u16 load;
+	struct isp116x_ep *next;
+
+	/* async schedule */
+	struct list_head schedule;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)		printk(KERN_DEBUG "116x: " stuff)
+#else
+#define DBG(stuff...)		do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "116x: " stuff)
+#define WARN(stuff...)		printk(KERN_WARNING "116x: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "116x: " stuff)
+
+/* ------------------------------------------------- */
+
+#if defined(USE_PLATFORM_DELAY)
+#if defined(USE_NDELAY)
+#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined.
+#endif
+#define	isp116x_delay(h,d)	(h)->board->delay(	\
+				isp116x_to_hcd(h)->self.controller,d)
+#define isp116x_check_platform_delay(h)	((h)->board->delay == NULL)
+#elif defined(USE_NDELAY)
+#define	isp116x_delay(h,d)	ndelay(d)
+#define isp116x_check_platform_delay(h)	0
+#else
+#define	isp116x_delay(h,d)	do{}while(0)
+#define isp116x_check_platform_delay(h)	0
+#endif
+
+#if defined(DEBUG)
+#define	IRQ_TEST()	BUG_ON(!irqs_disabled())
+#else
+#define	IRQ_TEST()	do{}while(0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+	IRQ_TEST();
+	writew(reg & 0xff, isp116x->addr_reg);
+	isp116x_delay(isp116x, 300);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+	writew(val, isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+	__raw_writew(val, isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+	u16 val;
+
+	val = readw(isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+	return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+	u16 val;
+
+	val = __raw_readw(isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+	return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+	writew(val & 0xffff, isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+	writew(val >> 16, isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+	u32 val;
+
+	val = (u32) readw(isp116x->data_reg);
+	isp116x_delay(isp116x, 150);
+	val |= ((u32) readw(isp116x->data_reg)) << 16;
+	isp116x_delay(isp116x, 150);
+	return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+   we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+	isp116x_write_addr(isp116x, reg);
+	return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+	isp116x_write_addr(isp116x, reg);
+	return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+				unsigned val)
+{
+	isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+	isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+				unsigned val)
+{
+	isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+	isp116x_write_data32(isp116x, (u32) val);
+}
+
+#define isp116x_show_reg(d,r) {					\
+	if ((r) < 0x20) {			                \
+		DBG("%-12s[%02x]: %08x\n", #r,			\
+			r, isp116x_read_reg32(d, r));		\
+	} else {						\
+		DBG("%-12s[%02x]:     %04x\n", #r,		\
+			r, isp116x_read_reg16(d, r));	    	\
+	}							\
+}
+
+static inline void isp116x_show_regs(struct isp116x *isp116x)
+{
+	isp116x_show_reg(isp116x, HCREVISION);
+	isp116x_show_reg(isp116x, HCCONTROL);
+	isp116x_show_reg(isp116x, HCCMDSTAT);
+	isp116x_show_reg(isp116x, HCINTSTAT);
+	isp116x_show_reg(isp116x, HCINTENB);
+	isp116x_show_reg(isp116x, HCFMINTVL);
+	isp116x_show_reg(isp116x, HCFMREM);
+	isp116x_show_reg(isp116x, HCFMNUM);
+	isp116x_show_reg(isp116x, HCLSTHRESH);
+	isp116x_show_reg(isp116x, HCRHDESCA);
+	isp116x_show_reg(isp116x, HCRHDESCB);
+	isp116x_show_reg(isp116x, HCRHSTATUS);
+	isp116x_show_reg(isp116x, HCRHPORT1);
+	isp116x_show_reg(isp116x, HCRHPORT2);
+	isp116x_show_reg(isp116x, HCHWCFG);
+	isp116x_show_reg(isp116x, HCDMACFG);
+	isp116x_show_reg(isp116x, HCXFERCTR);
+	isp116x_show_reg(isp116x, HCuPINT);
+	isp116x_show_reg(isp116x, HCuPINTENB);
+	isp116x_show_reg(isp116x, HCCHIPID);
+	isp116x_show_reg(isp116x, HCSCRATCH);
+	isp116x_show_reg(isp116x, HCITLBUFLEN);
+	isp116x_show_reg(isp116x, HCATLBUFLEN);
+	isp116x_show_reg(isp116x, HCBUFSTAT);
+	isp116x_show_reg(isp116x, HCRDITL0LEN);
+	isp116x_show_reg(isp116x, HCRDITL1LEN);
+}
+
+#if defined(URB_TRACE)
+
+#define PIPETYPE(pipe)  ({ char *__s;			\
+	if (usb_pipecontrol(pipe))	__s = "ctrl";	\
+	else if (usb_pipeint(pipe))	__s = "int";	\
+	else if (usb_pipebulk(pipe))	__s = "bulk";	\
+	else				__s = "iso";	\
+	__s;})
+#define PIPEDIR(pipe)   ({ usb_pipein(pipe) ? "in" : "out"; })
+#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \
+	"short_not_ok" : ""; })
+
+/* print debug info about the URB */
+static void urb_dbg(struct urb *urb, char *msg)
+{
+	unsigned int pipe;
+
+	if (!urb) {
+		DBG("%s: zero urb\n", msg);
+		return;
+	}
+	pipe = urb->pipe;
+	DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg,
+	    usb_pipedevice(pipe), usb_pipeendpoint(pipe),
+	    PIPEDIR(pipe), PIPETYPE(pipe),
+	    urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb));
+}
+
+#else
+
+#define  urb_dbg(urb,msg)   do{}while(0)
+
+#endif				/* ! defined(URB_TRACE) */
+
+#if defined(PTD_TRACE)
+
+#define PTD_DIR_STR(ptd)  ({char __c;		\
+	switch(PTD_GET_DIR(ptd)){		\
+	case 0:  __c = 's'; break;		\
+	case 1:  __c = 'o'; break;		\
+	default: __c = 'i'; break;		\
+	}; __c;})
+
+/*
+  Dump PTD info. The code documents the format
+  perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+	printk("td: %x %d%c%d %d,%d,%d  %x %x%x%x\n",
+	       PTD_GET_CC(ptd), PTD_GET_FA(ptd),
+	       PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+	       PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+	       PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd),
+	       PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+}
+
+static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf)
+{
+	int k;
+
+	if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
+		printk("-> ");
+		for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+			printk("%02x ", ((u8 *) buf)[k]);
+		printk("\n");
+	}
+}
+
+static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf)
+{
+	int k;
+
+	if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
+		printk("<- ");
+		for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+			printk("%02x ", ((u8 *) buf)[k]);
+		printk("\n");
+	}
+	if (PTD_GET_LAST(ptd))
+		printk("-\n");
+}
+
+#else
+
+#define dump_ptd(ptd)               do{}while(0)
+#define dump_ptd_in_data(ptd,buf)   do{}while(0)
+#define dump_ptd_out_data(ptd,buf)  do{}while(0)
+
+#endif				/* ! defined(PTD_TRACE) */
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 1e27f10..13cd217 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -95,12 +95,11 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/list.h>
-#include <linux/interrupt.h>  /* for in_interrupt () */
 #include <linux/usb.h>
 #include <linux/usb_otg.h>
-#include "../core/hcd.h"
 #include <linux/dma-mapping.h> 
-#include <linux/dmapool.h>    /* needed by ohci-mem.c when no PCI */
+#include <linux/dmapool.h>
+#include <linux/reboot.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -108,8 +107,9 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
+#include "../core/hcd.h"
 
-#define DRIVER_VERSION "2004 Nov 08"
+#define DRIVER_VERSION "2005 April 22"
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -141,6 +141,7 @@
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_reboot (struct notifier_block *, unsigned long , void *);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -420,6 +421,23 @@
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
 }
 
+/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+ * other cases where the next software may expect clean state from the
+ * "firmware".  this is bus-neutral, unlike shutdown() methods.
+ */
+static int
+ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+{
+	struct ohci_hcd *ohci;
+
+	ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	ohci_usb_reset (ohci);
+	/* flush the writes */
+	(void) ohci_readl (ohci, &ohci->regs->control);
+	return 0;
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -487,13 +505,10 @@
 /* Start an OHCI controller, set the BUS operational
  * resets USB and controller
  * enable interrupts 
- * connect the virtual root hub
  */
 static int ohci_run (struct ohci_hcd *ohci)
 {
   	u32			mask, temp;
-  	struct usb_device	*udev;
-  	struct usb_bus		*bus;
 	int			first = ohci->fminterval == 0;
 
 	disable (ohci);
@@ -654,37 +669,13 @@
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((temp >> 23) & 0x1fe);
-	bus = &ohci_to_hcd(ohci)->self;
 	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
 
 	ohci_dump (ohci, 1);
 
-	udev = bus->root_hub;
-	if (udev) {
-		return 0;
-	}
- 
-	/* connect the virtual root hub */
-	udev = usb_alloc_dev (NULL, bus, 0);
-	if (!udev) {
-		disable (ohci);
-		ohci->hc_control &= ~OHCI_CTRL_HCFS;
-		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-		return -ENOMEM;
-	}
+	if (ohci_to_hcd(ohci)->self.root_hub == NULL)
+		create_debug_files (ohci);
 
-	udev->speed = USB_SPEED_FULL;
-	if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
-		usb_put_dev (udev);
-		disable (ohci);
-		ohci->hc_control &= ~OHCI_CTRL_HCFS;
-		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-		return -ENODEV;
-	}
-	if (ohci->power_budget)
-		hub_set_power_budget(udev, ohci->power_budget);
-
-	create_debug_files (ohci);
 	return 0;
 }
 
@@ -781,6 +772,7 @@
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
 	
 	remove_debug_files (ohci);
+	unregister_reboot_notifier (&ohci->reboot_notifier);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
 		dma_free_coherent (hcd->self.controller, 
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index e55682b..23735a3 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -29,6 +29,7 @@
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
 	INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
+	ohci->reboot_notifier.notifier_call = ohci_reboot;
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 8aab590..b62d699 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -181,7 +181,7 @@
 	if (config->otg) {
 		ohci_to_hcd(ohci)->self.otg_port = config->otg;
 		/* default/minimum OTG power budget:  8 mA */
-		ohci->power_budget = 8;
+		ohci_to_hcd(ohci)->power_budget = 8;
 	}
 
 	/* boards can use OTG transceivers in non-OTG modes */
@@ -230,7 +230,7 @@
 
 		/* TPS2045 switch for internal transceiver (port 1) */
 		if (machine_is_omap_osk()) {
-			ohci->power_budget = 250;
+			ohci_to_hcd(ohci)->power_budget = 250;
 
 			rh &= ~RH_A_NOCP;
 
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 22e1ac1..71cdd22 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -371,7 +371,6 @@
 	 * other external transceivers should be software-transparent 
 	 */
 	struct otg_transceiver	*transceiver;
-	unsigned		power_budget;
 
 	/*
 	 * memory management for queue data structures
@@ -390,6 +389,7 @@
 	u32			fminterval;		/* saved register */
 
 	struct work_struct	rh_resume;
+	struct notifier_block	reboot_notifier;
 
 	unsigned long		flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 99d43f7..6c3f910 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1563,29 +1563,15 @@
 sl811h_start(struct usb_hcd *hcd)
 {
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
-	struct usb_device	*udev;
 
 	/* chip has been reset, VBUS power is off */
-
-	udev = usb_alloc_dev(NULL, &hcd->self, 0);
-	if (!udev)
-		return -ENOMEM;
-
-	udev->speed = USB_SPEED_FULL;
 	hcd->state = HC_STATE_RUNNING;
 
-	if (sl811->board)
+	if (sl811->board) {
 		hcd->can_wakeup = sl811->board->can_wakeup;
-
-	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
-		usb_put_dev(udev);
-		sl811h_stop(hcd);
-		return -ENODEV;
+		hcd->power_budget = sl811->board->power * 2;
 	}
 
-	if (sl811->board && sl811->board->power)
-		hub_set_power_budget(udev, sl811->board->power * 2);
-
 	/* enable power and interupts */
 	port_power(sl811, 1);
 
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 24c73c5..4538a98 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -237,6 +237,37 @@
 	return out - buf;
 }
 
+static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
+{
+	char *out = buf;
+	char *rh_state;
+
+	/* Try to make sure there's enough memory */
+	if (len < 60)
+		return 0;
+
+	switch (uhci->rh_state) {
+	    case UHCI_RH_RESET:
+		rh_state = "reset";		break;
+	    case UHCI_RH_SUSPENDED:
+		rh_state = "suspended";		break;
+	    case UHCI_RH_AUTO_STOPPED:
+		rh_state = "auto-stopped";	break;
+	    case UHCI_RH_RESUMING:
+		rh_state = "resuming";		break;
+	    case UHCI_RH_SUSPENDING:
+		rh_state = "suspending";	break;
+	    case UHCI_RH_RUNNING:
+		rh_state = "running";		break;
+	    case UHCI_RH_RUNNING_NODEVS:
+		rh_state = "running, no devs";	break;
+	    default:
+		rh_state = "?";			break;
+	}
+	out += sprintf(out, "Root-hub state: %s\n", rh_state);
+	return out - buf;
+}
+
 static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
 {
 	char *out = buf;
@@ -408,6 +439,7 @@
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
+	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
 
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 49bd83e..0d5d254 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -13,18 +13,13 @@
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
  * people who decided that they want to do the same thing in a
  * completely different way.
  *
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- *  - the low-level protocol (fairly simple but lots of small details)
- *  - working around the horridness of the rest
  */
 
 #include <linux/config.h>
@@ -64,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
@@ -89,8 +84,9 @@
 
 static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
 
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
+static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
-static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
 #define IDLE_TIMEOUT	msecs_to_jiffies(50)
@@ -101,77 +97,312 @@
 /* to make sure it doesn't hog all of the bandwidth */
 #define DEPTH_INTERVAL 5
 
+static inline void restart_timer(struct uhci_hcd *uhci)
+{
+	mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
+}
+
 #include "uhci-hub.c"
 #include "uhci-debug.c"
 #include "uhci-q.c"
 
-static int init_stall_timer(struct usb_hcd *hcd);
-
-static void stall_callback(unsigned long ptr)
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void reset_hc(struct uhci_hcd *uhci)
 {
-	struct usb_hcd *hcd = (struct usb_hcd *)ptr;
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	struct urb_priv *up;
+	int port;
+
+	/* Turn off PIRQ enable and SMI enable.  (This also turns off the
+	 * BIOS's USB Legacy Support.)  Turn off all the R/WC bits too.
+	 */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+			USBLEGSUP_RWC);
+
+	/* Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(USBCMD_HCRESET, uhci->io_addr + USBCMD);
+	mb();
+	udelay(5);
+	if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET)
+		dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
+
+	/* Just to be safe, disable interrupt requests and
+	 * make sure the controller is stopped.
+	 */
+	outw(0, uhci->io_addr + USBINTR);
+	outw(0, uhci->io_addr + USBCMD);
+
+	/* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
+	 * bits in the port status and control registers.
+	 * We have to clear them by hand.
+	 */
+	for (port = 0; port < uhci->rh_numports; ++port)
+		outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
+
+	uhci->port_c_suspend = uhci->suspended_ports =
+			uhci->resuming_ports = 0;
+	uhci->rh_state = UHCI_RH_RESET;
+	uhci->is_stopped = UHCI_IS_STOPPED;
+	uhci_to_hcd(uhci)->state = HC_STATE_HALT;
+	uhci_to_hcd(uhci)->poll_rh = 0;
+}
+
+/*
+ * Last rites for a defunct/nonfunctional controller
+ * or one we don't want to use any more.
+ */
+static void hc_died(struct uhci_hcd *uhci)
+{
+	reset_hc(uhci);
+	uhci->hc_inaccessible = 1;
+	del_timer(&uhci->stall_timer);
+}
+
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed.  In either case we can't be sure of its previous state.
+ */
+static void check_and_reset_hc(struct uhci_hcd *uhci)
+{
+	u16 legsup;
+	unsigned int cmd, intr;
+
+	/*
+	 * When restarting a suspended controller, we expect all the
+	 * settings to be the same as we left them:
+	 *
+	 *	PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
+	 *	Controller is stopped and configured with EGSM set;
+	 *	No interrupts enabled except possibly Resume Detect.
+	 *
+	 * If any of these conditions are violated we do a complete reset.
+	 */
+	pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup);
+	if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) {
+		dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n",
+				__FUNCTION__, legsup);
+		goto reset_needed;
+	}
+
+	cmd = inw(uhci->io_addr + USBCMD);
+	if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
+		dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
+				__FUNCTION__, cmd);
+		goto reset_needed;
+	}
+
+	intr = inw(uhci->io_addr + USBINTR);
+	if (intr & (~USBINTR_RESUME)) {
+		dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
+				__FUNCTION__, intr);
+		goto reset_needed;
+	}
+	return;
+
+reset_needed:
+	dev_dbg(uhci_dev(uhci), "Performing full reset\n");
+	reset_hc(uhci);
+}
+
+/*
+ * Store the basic register settings needed by the controller.
+ */
+static void configure_hc(struct uhci_hcd *uhci)
+{
+	/* Set the frame length to the default: 1 ms exactly */
+	outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
+
+	/* Store the frame list base address */
+	outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
+
+	/* Set the current frame number */
+	outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
+
+	/* Mark controller as running before we enable interrupts */
+	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+	mb();
+
+	/* Enable PIRQ */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+			USBLEGSUP_DEFAULT);
+}
+
+
+static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
+{
+	int port;
+
+	switch (to_pci_dev(uhci_dev(uhci))->vendor) {
+	    default:
+		break;
+
+	    case PCI_VENDOR_ID_GENESYS:
+		/* Genesys Logic's GL880S controllers don't generate
+		 * resume-detect interrupts.
+		 */
+		return 1;
+
+	    case PCI_VENDOR_ID_INTEL:
+		/* Some of Intel's USB controllers have a bug that causes
+		 * resume-detect interrupts if any port has an over-current
+		 * condition.  To make matters worse, some motherboards
+		 * hardwire unused USB ports' over-current inputs active!
+		 * To prevent problems, we will not enable resume-detect
+		 * interrupts if any ports are OC.
+		 */
+		for (port = 0; port < uhci->rh_numports; ++port) {
+			if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+					USBPORTSC_OC)
+				return 1;
+		}
+		break;
+	}
+	return 0;
+}
+
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
+__releases(uhci->lock)
+__acquires(uhci->lock)
+{
+	int auto_stop;
+	int int_enable;
+
+	auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
+	dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+			(auto_stop ? " (auto-stop)" : ""));
+
+	/* If we get a suspend request when we're already auto-stopped
+	 * then there's nothing to do.
+	 */
+	if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
+		uhci->rh_state = new_state;
+		return;
+	}
+
+	/* Enable resume-detect interrupts if they work.
+	 * Then enter Global Suspend mode, still configured.
+	 */
+	int_enable = (resume_detect_interrupts_are_broken(uhci) ?
+			0 : USBINTR_RESUME);
+	outw(int_enable, uhci->io_addr + USBINTR);
+	outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
+	mb();
+	udelay(5);
+
+	/* If we're auto-stopping then no devices have been attached
+	 * for a while, so there shouldn't be any active URBs and the
+	 * controller should stop after a few microseconds.  Otherwise
+	 * we will give the controller one frame to stop.
+	 */
+	if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
+		uhci->rh_state = UHCI_RH_SUSPENDING;
+		spin_unlock_irq(&uhci->lock);
+		msleep(1);
+		spin_lock_irq(&uhci->lock);
+		if (uhci->hc_inaccessible)	/* Died */
+			return;
+	}
+	if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
+		dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
+
+	uhci_get_current_frame_number(uhci);
+	smp_wmb();
+
+	uhci->rh_state = new_state;
+	uhci->is_stopped = UHCI_IS_STOPPED;
+	del_timer(&uhci->stall_timer);
+	uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+	uhci_scan_schedule(uhci, NULL);
+}
+
+static void start_rh(struct uhci_hcd *uhci)
+{
+	uhci->is_stopped = 0;
+	smp_wmb();
+
+	/* Mark it configured and running with a 64-byte max packet.
+	 * All interrupts are enabled, even though RESUME won't do anything.
+	 */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+			uhci->io_addr + USBINTR);
+	mb();
+	uhci->rh_state = UHCI_RH_RUNNING;
+	uhci_to_hcd(uhci)->poll_rh = 1;
+	restart_timer(uhci);
+}
+
+static void wakeup_rh(struct uhci_hcd *uhci)
+__releases(uhci->lock)
+__acquires(uhci->lock)
+{
+	dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+			uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
+				" (auto-start)" : "");
+
+	/* If we are auto-stopped then no devices are attached so there's
+	 * no need for wakeup signals.  Otherwise we send Global Resume
+	 * for 20 ms.
+	 */
+	if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+		uhci->rh_state = UHCI_RH_RESUMING;
+		outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
+				uhci->io_addr + USBCMD);
+		spin_unlock_irq(&uhci->lock);
+		msleep(20);
+		spin_lock_irq(&uhci->lock);
+		if (uhci->hc_inaccessible)	/* Died */
+			return;
+
+		/* End Global Resume and wait for EOP to be sent */
+		outw(USBCMD_CF, uhci->io_addr + USBCMD);
+		mb();
+		udelay(4);
+		if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
+			dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
+	}
+
+	start_rh(uhci);
+
+	/* Restart root hub polling */
+	mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
+}
+
+static void stall_callback(unsigned long _uhci)
+{
+	struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
 	unsigned long flags;
 
 	spin_lock_irqsave(&uhci->lock, flags);
 	uhci_scan_schedule(uhci, NULL);
+	check_fsbr(uhci);
 
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		spin_lock(&u->lock);
-
-		/* Check if the FSBR timed out */
-		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-			uhci_fsbr_timeout(uhci, u);
-
-		spin_unlock(&u->lock);
-	}
-
-	/* Really disable FSBR */
-	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
-		uhci->fsbrtimeout = 0;
-		uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	}
-
-	/* Poll for and perform state transitions */
-	hc_state_transitions(uhci);
-	if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
-		uhci_check_ports(uhci);
-
-	init_stall_timer(hcd);
+	if (!uhci->is_stopped)
+		restart_timer(uhci);
 	spin_unlock_irqrestore(&uhci->lock, flags);
 }
 
-static int init_stall_timer(struct usb_hcd *hcd)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
-	init_timer(&uhci->stall_timer);
-	uhci->stall_timer.function = stall_callback;
-	uhci->stall_timer.data = (unsigned long)hcd;
-	uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
-	add_timer(&uhci->stall_timer);
-
-	return 0;
-}
-
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	unsigned long io_addr = uhci->io_addr;
 	unsigned short status;
+	unsigned long flags;
 
 	/*
 	 * Read the interrupt status, and write it back to clear the
 	 * interrupt cause.  Contrary to the UHCI specification, the
 	 * "HC Halted" status bit is persistent: it is RO, not R/WC.
 	 */
-	status = inw(io_addr + USBSTS);
+	status = inw(uhci->io_addr + USBSTS);
 	if (!(status & ~USBSTS_HCH))	/* shared interrupt, not mine */
 		return IRQ_NONE;
-	outw(status, io_addr + USBSTS);		/* Clear it */
+	outw(status, uhci->io_addr + USBSTS);		/* Clear it */
 
 	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
 		if (status & USBSTS_HSE)
@@ -180,179 +411,30 @@
 		if (status & USBSTS_HCPE)
 			dev_err(uhci_dev(uhci), "host controller process "
 					"error, something bad happened!\n");
-		if ((status & USBSTS_HCH) && uhci->state > 0) {
-			dev_err(uhci_dev(uhci), "host controller halted, "
+		if (status & USBSTS_HCH) {
+			spin_lock_irqsave(&uhci->lock, flags);
+			if (uhci->rh_state >= UHCI_RH_RUNNING) {
+				dev_err(uhci_dev(uhci),
+					"host controller halted, "
 					"very bad!\n");
-			/* FIXME: Reset the controller, fix the offending TD */
+				hc_died(uhci);
+				spin_unlock_irqrestore(&uhci->lock, flags);
+				return IRQ_HANDLED;
+			}
+			spin_unlock_irqrestore(&uhci->lock, flags);
 		}
 	}
 
 	if (status & USBSTS_RD)
-		uhci->resume_detect = 1;
+		usb_hcd_poll_rh_status(hcd);
 
-	spin_lock(&uhci->lock);
+	spin_lock_irqsave(&uhci->lock, flags);
 	uhci_scan_schedule(uhci, regs);
-	spin_unlock(&uhci->lock);
+	spin_unlock_irqrestore(&uhci->lock, flags);
 
 	return IRQ_HANDLED;
 }
 
-static void reset_hc(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-
-	/* Turn off PIRQ, SMI, and all interrupts.  This also turns off
-	 * the BIOS's USB Legacy Support.
-	 */
-	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
-	outw(0, uhci->io_addr + USBINTR);
-
-	/* Global reset for 50ms */
-	uhci->state = UHCI_RESET;
-	outw(USBCMD_GRESET, io_addr + USBCMD);
-	msleep(50);
-	outw(0, io_addr + USBCMD);
-
-	/* Another 10ms delay */
-	msleep(10);
-	uhci->resume_detect = 0;
-	uhci->is_stopped = UHCI_IS_STOPPED;
-}
-
-static void suspend_hc(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-
-	dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
-	uhci->state = UHCI_SUSPENDED;
-	uhci->resume_detect = 0;
-	outw(USBCMD_EGSM, io_addr + USBCMD);
-
-	/* FIXME: Wait for the controller to actually stop */
-	uhci_get_current_frame_number(uhci);
-	uhci->is_stopped = UHCI_IS_STOPPED;
-
-	uhci_scan_schedule(uhci, NULL);
-}
-
-static void wakeup_hc(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-
-	switch (uhci->state) {
-		case UHCI_SUSPENDED:		/* Start the resume */
-			dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
-
-			/* Global resume for >= 20ms */
-			outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
-			uhci->state = UHCI_RESUMING_1;
-			uhci->state_end = jiffies + msecs_to_jiffies(20);
-			uhci->is_stopped = 0;
-			break;
-
-		case UHCI_RESUMING_1:		/* End global resume */
-			uhci->state = UHCI_RESUMING_2;
-			outw(0, io_addr + USBCMD);
-			/* Falls through */
-
-		case UHCI_RESUMING_2:		/* Wait for EOP to be sent */
-			if (inw(io_addr + USBCMD) & USBCMD_FGR)
-				break;
-
-			/* Run for at least 1 second, and
-			 * mark it configured with a 64-byte max packet */
-			uhci->state = UHCI_RUNNING_GRACE;
-			uhci->state_end = jiffies + HZ;
-			outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP,
-					io_addr + USBCMD);
-			break;
-
-		case UHCI_RUNNING_GRACE:	/* Now allowed to suspend */
-			uhci->state = UHCI_RUNNING;
-			break;
-
-		default:
-			break;
-	}
-}
-
-static int ports_active(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-	int connection = 0;
-	int i;
-
-	for (i = 0; i < uhci->rh_numports; i++)
-		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS);
-
-	return connection;
-}
-
-static int suspend_allowed(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-	int i;
-
-	if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
-		return 1;
-
-	/* Some of Intel's USB controllers have a bug that causes false
-	 * resume indications if any port has an over current condition.
-	 * To prevent problems, we will not allow a global suspend if
-	 * any ports are OC.
-	 *
-	 * Some motherboards using Intel's chipsets (but not using all
-	 * the USB ports) appear to hardwire the over current inputs active
-	 * to disable the USB ports.
-	 */
-
-	/* check for over current condition on any port */
-	for (i = 0; i < uhci->rh_numports; i++) {
-		if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC)
-			return 0;
-	}
-
-	return 1;
-}
-
-static void hc_state_transitions(struct uhci_hcd *uhci)
-{
-	switch (uhci->state) {
-		case UHCI_RUNNING:
-
-			/* global suspend if nothing connected for 1 second */
-			if (!ports_active(uhci) && suspend_allowed(uhci)) {
-				uhci->state = UHCI_SUSPENDING_GRACE;
-				uhci->state_end = jiffies + HZ;
-			}
-			break;
-
-		case UHCI_SUSPENDING_GRACE:
-			if (ports_active(uhci))
-				uhci->state = UHCI_RUNNING;
-			else if (time_after_eq(jiffies, uhci->state_end))
-				suspend_hc(uhci);
-			break;
-
-		case UHCI_SUSPENDED:
-
-			/* wakeup if requested by a device */
-			if (uhci->resume_detect)
-				wakeup_hc(uhci);
-			break;
-
-		case UHCI_RESUMING_1:
-		case UHCI_RESUMING_2:
-		case UHCI_RUNNING_GRACE:
-			if (time_after_eq(jiffies, uhci->state_end))
-				wakeup_hc(uhci);
-			break;
-
-		default:
-			break;
-	}
-}
-
 /*
  * Store the current frame number in uhci->frame_number if the controller
  * is runnning
@@ -363,48 +445,6 @@
 		uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
 }
 
-static int start_hc(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = uhci->io_addr;
-	int timeout = 10;
-
-	/*
-	 * Reset the HC - this will force us to get a
-	 * new notification of any already connected
-	 * ports due to the virtual disconnect that it
-	 * implies.
-	 */
-	outw(USBCMD_HCRESET, io_addr + USBCMD);
-	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
-		if (--timeout < 0) {
-			dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n");
-			return -ETIMEDOUT;
-		}
-		msleep(1);
-	}
-
-	/* Mark controller as running before we enable interrupts */
-	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
-
-	/* Turn on PIRQ and all interrupts */
-	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-			USBLEGSUP_DEFAULT);
-	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
-		io_addr + USBINTR);
-
-	/* Start at frame 0 */
-	outw(0, io_addr + USBFRNUM);
-	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	uhci->state = UHCI_RUNNING_GRACE;
-	uhci->state_end = jiffies + HZ;
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-	uhci->is_stopped = 0;
-
-	return 0;
-}
-
 /*
  * De-allocate all resources
  */
@@ -448,16 +488,58 @@
 static int uhci_reset(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned io_size = (unsigned) hcd->rsrc_len;
+	int port;
 
 	uhci->io_addr = (unsigned long) hcd->rsrc_start;
 
-	/* Kick BIOS off this hardware and reset, so we won't get
-	 * interrupts from any previous setup.
+	/* The UHCI spec says devices must have 2 ports, and goes on to say
+	 * they may have more but gives no way to determine how many there
+	 * are.  However according to the UHCI spec, Bit 7 of the port
+	 * status and control register is always set to 1.  So we try to
+	 * use this to our advantage.  Another common failure mode when
+	 * a nonexistent register is addressed is to return all ones, so
+	 * we test for that also.
 	 */
-	reset_hc(uhci);
+	for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
+		unsigned int portstatus;
+
+		portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2));
+		if (!(portstatus & 0x0080) || portstatus == 0xffff)
+			break;
+	}
+	if (debug)
+		dev_info(uhci_dev(uhci), "detected %d ports\n", port);
+
+	/* Anything greater than 7 is weird so we'll ignore it. */
+	if (port > UHCI_RH_MAXCHILD) {
+		dev_info(uhci_dev(uhci), "port count misdetected? "
+				"forcing to 2 ports\n");
+		port = 2;
+	}
+	uhci->rh_numports = port;
+
+	/* Kick BIOS off this hardware and reset if the controller
+	 * isn't already safely quiescent.
+	 */
+	check_and_reset_hc(uhci);
 	return 0;
 }
 
+/* Make sure the controller is quiescent and that we're not using it
+ * any more.  This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel.  Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_shutdown(struct pci_dev *pdev)
+{
+	struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
+
+	hc_died(hcd_to_uhci(hcd));
+}
+
 /*
  * Allocate a frame list, and then setup the skeleton
  *
@@ -478,17 +560,20 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	int retval = -EBUSY;
-	int i, port;
-	unsigned io_size;
+	int i;
 	dma_addr_t dma_handle;
-	struct usb_device *udev;
 	struct dentry *dentry;
 
-	io_size = (unsigned) hcd->rsrc_len;
+	hcd->uses_new_polling = 1;
+	if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
+		hcd->can_wakeup = 1;		/* Assume it supports PME# */
 
-	dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
+	dentry = debugfs_create_file(hcd->self.bus_name,
+			S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
+			&uhci_debug_operations);
 	if (!dentry) {
-		dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
+		dev_err(uhci_dev(uhci),
+				"couldn't create uhci debugfs entry\n");
 		retval = -ENOMEM;
 		goto err_create_debug_entry;
 	}
@@ -510,6 +595,10 @@
 
 	init_waitqueue_head(&uhci->waitqh);
 
+	init_timer(&uhci->stall_timer);
+	uhci->stall_timer.function = stall_callback;
+	uhci->stall_timer.data = (unsigned long) uhci;
+
 	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
 			&dma_handle, 0);
 	if (!uhci->fl) {
@@ -536,46 +625,14 @@
 		goto err_create_qh_pool;
 	}
 
-	/* Initialize the root hub */
-
-	/* UHCI specs says devices must have 2 ports, but goes on to say */
-	/*  they may have more but give no way to determine how many they */
-	/*  have. However, according to the UHCI spec, Bit 7 is always set */
-	/*  to 1. So we try to use this to our advantage */
-	for (port = 0; port < (io_size - 0x10) / 2; port++) {
-		unsigned int portstatus;
-
-		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	if (debug)
-		dev_info(uhci_dev(uhci), "detected %d ports\n", port);
-
-	/* This is experimental so anything less than 2 or greater than 8 is */
-	/*  something weird and we'll ignore it */
-	if (port < 2 || port > UHCI_RH_MAXCHILD) {
-		dev_info(uhci_dev(uhci), "port count misdetected? "
-				"forcing to 2 ports\n");
-		port = 2;
-	}
-
-	uhci->rh_numports = port;
-
-	udev = usb_alloc_dev(NULL, &hcd->self, 0);
-	if (!udev) {
-		dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
-		goto err_alloc_root_hub;
-	}
-
-	uhci->term_td = uhci_alloc_td(uhci, udev);
+	uhci->term_td = uhci_alloc_td(uhci);
 	if (!uhci->term_td) {
 		dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");
 		goto err_alloc_term_td;
 	}
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
+		uhci->skelqh[i] = uhci_alloc_qh(uhci);
 		if (!uhci->skelqh[i]) {
 			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
 			goto err_alloc_skelqh;
@@ -641,32 +698,17 @@
 
 	/*
 	 * Some architectures require a full mb() to enforce completion of
-	 * the memory writes above before the I/O transfers in start_hc().
+	 * the memory writes above before the I/O transfers in configure_hc().
 	 */
 	mb();
-	if ((retval = start_hc(uhci)) != 0)
-		goto err_alloc_skelqh;
 
-	init_stall_timer(hcd);
-
-	udev->speed = USB_SPEED_FULL;
-
-	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
-		dev_err(uhci_dev(uhci), "unable to start root hub\n");
-		retval = -ENOMEM;
-		goto err_start_root_hub;
-	}
-
+	configure_hc(uhci);
+	start_rh(uhci);
 	return 0;
 
 /*
  * error exits:
  */
-err_start_root_hub:
-	reset_hc(uhci);
-
-	del_timer_sync(&uhci->stall_timer);
-
 err_alloc_skelqh:
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 		if (uhci->skelqh[i]) {
@@ -678,9 +720,6 @@
 	uhci->term_td = NULL;
 
 err_alloc_term_td:
-	usb_put_dev(udev);
-
-err_alloc_root_hub:
 	dma_pool_destroy(uhci->qh_pool);
 	uhci->qh_pool = NULL;
 
@@ -705,73 +744,114 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	del_timer_sync(&uhci->stall_timer);
-	reset_hc(uhci);
-
 	spin_lock_irq(&uhci->lock);
+	reset_hc(uhci);
 	uhci_scan_schedule(uhci, NULL);
 	spin_unlock_irq(&uhci->lock);
-	
+
+	del_timer_sync(&uhci->stall_timer);
 	release_uhci(uhci);
 }
 
 #ifdef CONFIG_PM
-static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
+static int uhci_rh_suspend(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
 	spin_lock_irq(&uhci->lock);
-
-	/* Don't try to suspend broken motherboards, reset instead */
-	if (suspend_allowed(uhci))
-		suspend_hc(uhci);
-	else {
-		spin_unlock_irq(&uhci->lock);
-		reset_hc(uhci);
-		spin_lock_irq(&uhci->lock);
-		uhci_scan_schedule(uhci, NULL);
-	}
-
+	if (!uhci->hc_inaccessible)		/* Not dead */
+		suspend_rh(uhci, UHCI_RH_SUSPENDED);
 	spin_unlock_irq(&uhci->lock);
 	return 0;
 }
 
+static int uhci_rh_resume(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int rc = 0;
+
+	spin_lock_irq(&uhci->lock);
+	if (uhci->hc_inaccessible) {
+		if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+			dev_warn(uhci_dev(uhci), "HC isn't running!\n");
+			rc = -ENODEV;
+		}
+		/* Otherwise the HC is dead */
+	} else
+		wakeup_rh(uhci);
+	spin_unlock_irq(&uhci->lock);
+	return rc;
+}
+
+static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int rc = 0;
+
+	dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+
+	spin_lock_irq(&uhci->lock);
+	if (uhci->hc_inaccessible)	/* Dead or already suspended */
+		goto done;
+
+#ifndef CONFIG_USB_SUSPEND
+	/* Otherwise this would never happen */
+	suspend_rh(uhci, UHCI_RH_SUSPENDED);
+#endif
+
+	if (uhci->rh_state > UHCI_RH_SUSPENDED) {
+		dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
+		hcd->state = HC_STATE_RUNNING;
+		rc = -EBUSY;
+		goto done;
+	};
+
+	/* All PCI host controllers are required to disable IRQ generation
+	 * at the source, so we must turn off PIRQ.
+	 */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+	uhci->hc_inaccessible = 1;
+
+	/* FIXME: Enable non-PME# remote wakeup? */
+
+done:
+	spin_unlock_irq(&uhci->lock);
+	if (rc == 0)
+		del_timer_sync(&hcd->rh_timer);
+	return rc;
+}
+
 static int uhci_resume(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	int rc;
 
-	pci_set_master(to_pci_dev(uhci_dev(uhci)));
+	dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
+	if (uhci->rh_state == UHCI_RH_RESET)	/* Dead */
+		return 0;
 	spin_lock_irq(&uhci->lock);
 
-	if (uhci->state == UHCI_SUSPENDED) {
+	/* FIXME: Disable non-PME# remote wakeup? */
 
-		/*
-		 * Some systems don't maintain the UHCI register values
-		 * during a PM suspend/resume cycle, so reinitialize
-		 * the Frame Number, Framelist Base Address, Interrupt
-		 * Enable, and Legacy Support registers.
-		 */
-		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-				0);
-		outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
-		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
-		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
-				USBINTR_SP, uhci->io_addr + USBINTR);
-		uhci->resume_detect = 1;
-		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-				USBLEGSUP_DEFAULT);
-	} else {
-		spin_unlock_irq(&uhci->lock);
-		reset_hc(uhci);
-		if ((rc = start_hc(uhci)) != 0)
-			return rc;
-		spin_lock_irq(&uhci->lock);
-	}
-	hcd->state = HC_STATE_RUNNING;
+	uhci->hc_inaccessible = 0;
+
+	/* The BIOS may have changed the controller settings during a
+	 * system wakeup.  Check it and reconfigure to avoid problems.
+	 */
+	check_and_reset_hc(uhci);
+	configure_hc(uhci);
+
+#ifndef CONFIG_USB_SUSPEND
+	/* Otherwise this would never happen */
+	wakeup_rh(uhci);
+#endif
+	if (uhci->rh_state == UHCI_RH_RESET)
+		suspend_rh(uhci, UHCI_RH_SUSPENDED);
 
 	spin_unlock_irq(&uhci->lock);
+
+	if (hcd->poll_rh)
+		usb_hcd_poll_rh_status(hcd);
 	return 0;
 }
 #endif
@@ -788,13 +868,15 @@
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	int frame_number;
 	unsigned long flags;
+	int is_stopped;
+	int frame_number;
 
 	/* Minimize latency by avoiding the spinlock */
 	local_irq_save(flags);
-	rmb();
-	frame_number = (uhci->is_stopped ? uhci->frame_number :
+	is_stopped = uhci->is_stopped;
+	smp_rmb();
+	frame_number = (is_stopped ? uhci->frame_number :
 			inw(uhci->io_addr + USBFRNUM));
 	local_irq_restore(flags);
 	return frame_number;
@@ -817,6 +899,8 @@
 #ifdef CONFIG_PM
 	.suspend =		uhci_suspend,
 	.resume =		uhci_resume,
+	.hub_suspend =		uhci_rh_suspend,
+	.hub_resume =		uhci_rh_resume,
 #endif
 	.stop =			uhci_stop,
 
@@ -845,6 +929,7 @@
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
+	.shutdown =	uhci_shutdown,
 
 #ifdef	CONFIG_PM
 	.suspend =	usb_hcd_pci_suspend,
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 02255d6..bf9c5f9 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -41,6 +41,7 @@
 #define USBFRNUM	6
 #define USBFLBASEADD	8
 #define USBSOF		12
+#define   USBSOF_DEFAULT	64	/* Frame length is exactly 1 ms */
 
 /* USB port status and control registers */
 #define USBPORTSC1	16
@@ -66,6 +67,8 @@
 /* Legacy support register */
 #define USBLEGSUP		0xc0
 #define   USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
+#define   USBLEGSUP_RWC		0x8f00	/* the R/WC bits */
+#define   USBLEGSUP_RO		0x5040	/* R/O and reserved bits */
 
 #define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
 
@@ -111,7 +114,6 @@
 	/* Software fields */
 	dma_addr_t dma_handle;
 
-	struct usb_device *dev;
 	struct urb_priv *urbp;
 
 	struct list_head list;		/* P: uhci->frame_list_lock */
@@ -203,7 +205,6 @@
 	/* Software fields */
 	dma_addr_t dma_handle;
 
-	struct usb_device *dev;
 	struct urb *urb;
 
 	struct list_head list;		/* P: urb->lock */
@@ -314,26 +315,32 @@
 }
 
 /*
- * Device states for the host controller.
+ * States for the root hub.
  *
  * To prevent "bouncing" in the presence of electrical noise,
- * we insist on a 1-second "grace" period, before switching to
- * the RUNNING or SUSPENDED states, during which the state is
- * not allowed to change.
- *
- * The resume process is divided into substates in order to avoid
- * potentially length delays during the timer handler.
- *
- * States in which the host controller is halted must have values <= 0.
+ * when there are no devices attached we delay for 1 second in the
+ * RUNNING_NODEVS state before switching to the AUTO_STOPPED state.
+ * 
+ * (Note that the AUTO_STOPPED state won't be necessary once the hub
+ * driver learns to autosuspend.)
  */
-enum uhci_state {
-	UHCI_RESET,
-	UHCI_RUNNING_GRACE,		/* Before RUNNING */
-	UHCI_RUNNING,			/* The normal state */
-	UHCI_SUSPENDING_GRACE,		/* Before SUSPENDED */
-	UHCI_SUSPENDED = -10,		/* When no devices are attached */
-	UHCI_RESUMING_1,
-	UHCI_RESUMING_2
+enum uhci_rh_state {
+	/* In the following states the HC must be halted.
+	 * These two must come first */
+	UHCI_RH_RESET,
+	UHCI_RH_SUSPENDED,
+
+	UHCI_RH_AUTO_STOPPED,
+	UHCI_RH_RESUMING,
+
+	/* In this state the HC changes from running to halted,
+	 * so it can legally appear either way. */
+	UHCI_RH_SUSPENDING,
+
+	/* In the following states it's an error if the HC is halted.
+	 * These two must come last */
+	UHCI_RH_RUNNING,		/* The normal state */
+	UHCI_RH_RUNNING_NODEVS,		/* Running with no devices attached */
 };
 
 /*
@@ -363,15 +370,16 @@
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
-	enum uhci_state state;			/* FIXME: needs a spinlock */
-	unsigned long state_end;		/* Time of next transition */
+	enum uhci_rh_state rh_state;
+	unsigned long auto_stop_time;		/* When to AUTO_STOP */
+
 	unsigned int frame_number;		/* As of last check */
 	unsigned int is_stopped;
 #define UHCI_IS_STOPPED		9999		/* Larger than a frame # */
 
 	unsigned int scan_in_progress:1;	/* Schedule scan is running */
 	unsigned int need_rescan:1;		/* Redo the schedule scan */
-	unsigned int resume_detect:1;		/* Need a Global Resume */
+	unsigned int hc_inaccessible:1;		/* HC is suspended or dead */
 
 	/* Support for port suspend/resume/reset */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
@@ -451,4 +459,11 @@
  * #2 urb->lock
  */
 
+
+/* Some special IDs */
+
+#define PCI_VENDOR_ID_GENESYS		0x17a0
+#define PCI_DEVICE_ID_GL880S_UHCI	0x8083
+#define PCI_DEVICE_ID_GL880S_EHCI	0x8084
+
 #endif
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 4c45ba8..4eace2b 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -33,9 +33,24 @@
 /* status change bits:  nonzero writes will clear */
 #define RWC_BITS	(USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
 
-static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+/* A port that either is connected or has a changed-bit set will prevent
+ * us from AUTO_STOPPING.
+ */
+static int any_ports_active(struct uhci_hcd *uhci)
 {
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int port;
+
+	for (port = 0; port < uhci->rh_numports; ++port) {
+		if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+				(USBPORTSC_CCS | RWC_BITS)) ||
+				test_bit(port, &uhci->port_c_suspend))
+			return 1;
+	}
+	return 0;
+}
+
+static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
+{
 	int port;
 
 	*buf = 0;
@@ -44,8 +59,6 @@
 				test_bit(port, &uhci->port_c_suspend))
 			*buf |= (1 << (port + 1));
 	}
-	if (*buf && uhci->state == UHCI_SUSPENDED)
-		uhci->resume_detect = 1;
 	return !!*buf;
 }
 
@@ -115,6 +128,11 @@
 				set_bit(port, &uhci->resuming_ports);
 				uhci->ports_timeout = jiffies +
 						msecs_to_jiffies(20);
+
+				/* Make sure we see the port again
+				 * after the resuming period is over. */
+				mod_timer(&uhci_to_hcd(uhci)->rh_timer,
+						uhci->ports_timeout);
 			} else if (time_after_eq(jiffies,
 						uhci->ports_timeout)) {
 				uhci_finish_suspend(uhci, port, port_addr);
@@ -123,6 +141,60 @@
 	}
 }
 
+static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
+	int status;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+	if (uhci->hc_inaccessible) {
+		status = 0;
+		goto done;
+	}
+
+	uhci_check_ports(uhci);
+	status = get_hub_status_data(uhci, buf);
+
+	switch (uhci->rh_state) {
+	    case UHCI_RH_SUSPENDING:
+	    case UHCI_RH_SUSPENDED:
+		/* if port change, ask to be resumed */
+		if (status)
+			usb_hcd_resume_root_hub(hcd);
+		break;
+
+	    case UHCI_RH_AUTO_STOPPED:
+		/* if port change, auto start */
+		if (status)
+			wakeup_rh(uhci);
+		break;
+
+	    case UHCI_RH_RUNNING:
+		/* are any devices attached? */
+		if (!any_ports_active(uhci)) {
+			uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
+			uhci->auto_stop_time = jiffies + HZ;
+		}
+		break;
+
+	    case UHCI_RH_RUNNING_NODEVS:
+		/* auto-stop if nothing connected for 1 second */
+		if (any_ports_active(uhci))
+			uhci->rh_state = UHCI_RH_RUNNING;
+		else if (time_after_eq(jiffies, uhci->auto_stop_time))
+			suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
+		break;
+
+	    default:
+		break;
+	}
+
+done:
+	spin_unlock_irqrestore(&uhci->lock, flags);
+	return status;
+}
+
 /* size of returned buffer is part of USB spec */
 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 			u16 wIndex, char *buf, u16 wLength)
@@ -134,6 +206,9 @@
 	u16 wPortChange, wPortStatus;
 	unsigned long flags;
 
+	if (uhci->hc_inaccessible)
+		return -ETIMEDOUT;
+
 	spin_lock_irqsave(&uhci->lock, flags);
 	switch (typeReq) {
 
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 2a7c195..5f18084 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -32,6 +32,8 @@
  */
 static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
+	if (uhci->is_stopped)
+		mod_timer(&uhci->stall_timer, jiffies);
 	uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
 }
 
@@ -46,7 +48,7 @@
 	list_move_tail(&urbp->urb_list, &uhci->complete_list);
 }
 
-static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
 {
 	dma_addr_t dma_handle;
 	struct uhci_td *td;
@@ -61,14 +63,11 @@
 	td->buffer = 0;
 
 	td->frame = -1;
-	td->dev = dev;
 
 	INIT_LIST_HEAD(&td->list);
 	INIT_LIST_HEAD(&td->remove_list);
 	INIT_LIST_HEAD(&td->fl_list);
 
-	usb_get_dev(dev);
-
 	return td;
 }
 
@@ -168,13 +167,10 @@
 	if (!list_empty(&td->fl_list))
 		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
 
-	if (td->dev)
-		usb_put_dev(td->dev);
-
 	dma_pool_free(uhci->td_pool, td, td->dma_handle);
 }
 
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
 {
 	dma_addr_t dma_handle;
 	struct uhci_qh *qh;
@@ -188,14 +184,11 @@
 	qh->element = UHCI_PTR_TERM;
 	qh->link = UHCI_PTR_TERM;
 
-	qh->dev = dev;
 	qh->urbp = NULL;
 
 	INIT_LIST_HEAD(&qh->list);
 	INIT_LIST_HEAD(&qh->remove_list);
 
-	usb_get_dev(dev);
-
 	return qh;
 }
 
@@ -206,9 +199,6 @@
 	if (!list_empty(&qh->remove_list))
 		dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
 
-	if (qh->dev)
-		usb_put_dev(qh->dev);
-
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
@@ -597,7 +587,7 @@
 	/*
 	 * Build the TD for the control request setup packet
 	 */
-	td = uhci_alloc_td(uhci, urb->dev);
+	td = uhci_alloc_td(uhci);
 	if (!td)
 		return -ENOMEM;
 
@@ -626,7 +616,7 @@
 		if (pktsze > maxsze)
 			pktsze = maxsze;
 
-		td = uhci_alloc_td(uhci, urb->dev);
+		td = uhci_alloc_td(uhci);
 		if (!td)
 			return -ENOMEM;
 
@@ -644,7 +634,7 @@
 	/*
 	 * Build the final TD for control status 
 	 */
-	td = uhci_alloc_td(uhci, urb->dev);
+	td = uhci_alloc_td(uhci);
 	if (!td)
 		return -ENOMEM;
 
@@ -666,7 +656,7 @@
 	uhci_fill_td(td, status | TD_CTRL_IOC,
 		destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
 
-	qh = uhci_alloc_qh(uhci, urb->dev);
+	qh = uhci_alloc_qh(uhci);
 	if (!qh)
 		return -ENOMEM;
 
@@ -865,7 +855,7 @@
 				status &= ~TD_CTRL_SPD;
 		}
 
-		td = uhci_alloc_td(uhci, urb->dev);
+		td = uhci_alloc_td(uhci);
 		if (!td)
 			return -ENOMEM;
 
@@ -891,7 +881,7 @@
 	 */
 	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
 	    !len && urb->transfer_buffer_length) {
-		td = uhci_alloc_td(uhci, urb->dev);
+		td = uhci_alloc_td(uhci);
 		if (!td)
 			return -ENOMEM;
 
@@ -913,7 +903,7 @@
 	 * flag setting. */
 	td->status |= cpu_to_le32(TD_CTRL_IOC);
 
-	qh = uhci_alloc_qh(uhci, urb->dev);
+	qh = uhci_alloc_qh(uhci);
 	if (!qh)
 		return -ENOMEM;
 
@@ -1096,7 +1086,7 @@
 		if (!urb->iso_frame_desc[i].length)
 			continue;
 
-		td = uhci_alloc_td(uhci, urb->dev);
+		td = uhci_alloc_td(uhci);
 		if (!td)
 			return -ENOMEM;
 
@@ -1497,6 +1487,7 @@
  rescan:
 	uhci->need_rescan = 0;
 
+	uhci_clear_next_interrupt(uhci);
 	uhci_get_current_frame_number(uhci);
 
 	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
@@ -1537,3 +1528,26 @@
 	/* Wake up anyone waiting for an URB to complete */
 	wake_up_all(&uhci->waitqh);
 }
+
+static void check_fsbr(struct uhci_hcd *uhci)
+{
+	struct urb_priv *up;
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		spin_lock(&u->lock);
+
+		/* Check if the FSBR timed out */
+		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+			uhci_fsbr_timeout(uhci, u);
+
+		spin_unlock(&u->lock);
+	}
+
+	/* Really disable FSBR */
+	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+		uhci->fsbrtimeout = 0;
+		uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	}
+}
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index db95c97..654ac45 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -639,6 +639,7 @@
 	idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
 	idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
 	idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
+	idev->dev = &(ati_remote->udev->dev);
 }
 
 static int ati_remote_initialize(struct ati_remote *ati_remote)
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index ae455c8..7398a7f 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1375,9 +1375,13 @@
 	    (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
 		camera_name = "STV0680";
 		PDEBUG (0, "STV(i): STV0680 camera found.");
+	} else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
+		   (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
+		camera_name = "Creative WebCam Go Mini";
+		PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
 	} else {
-		PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
-		PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
+		PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
+		PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
 		retval = -ENODEV;
 		goto error;
 	}
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h
index 7e0e314d..4459406 100644
--- a/drivers/usb/media/stv680.h
+++ b/drivers/usb/media/stv680.h
@@ -41,12 +41,17 @@
 
 #define USB_PENCAM_VENDOR_ID	0x0553
 #define USB_PENCAM_PRODUCT_ID	0x0202
+
+#define USB_CREATIVEGOMINI_VENDOR_ID	0x041e
+#define USB_CREATIVEGOMINI_PRODUCT_ID	0x4007
+
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
 #define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+	{USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
 	{}
 };
 MODULE_DEVICE_TABLE (usb, device_table);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index ce030d1..733acc2 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -1,4 +1,4 @@
-/* Siemens ID Mouse driver v0.5
+/* Siemens ID Mouse driver v0.6
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -11,6 +11,9 @@
   Derived from the USB Skeleton driver 1.1,
   Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
 
+  Additional information provided by Martin Reising
+  <Martin.Reising@natural-computing.de>
+
 */
 
 #include <linux/config.h>
@@ -25,29 +28,44 @@
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
+/* image constants */
 #define WIDTH 225
-#define HEIGHT 288
-#define HEADER "P5 225 288 255 "
+#define HEIGHT 289
+#define HEADER "P5 225 289 255 "
 #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
 
-/* Version Information */
-#define DRIVER_VERSION "0.5"
+/* version information */
+#define DRIVER_VERSION "0.6"
 #define DRIVER_SHORT   "idmouse"
 #define DRIVER_AUTHOR  "Florian 'Floe' Echtler <echtler@fs.tum.de>"
 #define DRIVER_DESC    "Siemens ID Mouse FingerTIP Sensor Driver"
 
-/* Siemens ID Mouse */
-#define USB_IDMOUSE_VENDOR_ID  0x0681
-#define USB_IDMOUSE_PRODUCT_ID 0x0005
-
-/* we still need a minor number */
+/* minor number for misc USB devices */
 #define USB_IDMOUSE_MINOR_BASE 132
 
+/* vendor and device IDs */
+#define ID_SIEMENS 0x0681
+#define ID_IDMOUSE 0x0005
+#define ID_CHERRY  0x0010
+
+/* device ID table */
 static struct usb_device_id idmouse_table[] = {
-	{USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)},
-	{} /* null entry at the end */
+	{USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
+	{USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board       */
+	{}                                    /* terminating null entry          */
 };
 
+/* sensor commands */
+#define FTIP_RESET   0x20
+#define FTIP_ACQUIRE 0x21
+#define FTIP_RELEASE 0x22
+#define FTIP_BLINK   0x23  /* LSB of value = blink pulse width */
+#define FTIP_SCROLL  0x24
+
+#define ftip_command(dev, command, value, index) \
+	usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \
+	USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
+
 MODULE_DEVICE_TABLE(usb, idmouse_table);
 
 /* structure to hold all of our device specific stuff */
@@ -57,7 +75,8 @@
 	struct usb_interface *interface; /* the interface for this device */
 
 	unsigned char *bulk_in_buffer; /* the buffer to receive data */
-	size_t bulk_in_size; /* the size of the receive buffer */
+	size_t bulk_in_size; /* the maximum bulk packet size */
+	size_t orig_bi_size; /* same as above, but reported by the device */
 	__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
 
 	int open; /* if the port is open or not */
@@ -103,7 +122,7 @@
 	.id_table = idmouse_table,
 };
 
-// prevent races between open() and disconnect()
+/* prevent races between open() and disconnect() */
 static DECLARE_MUTEX(disconnect_sem);
 
 static int idmouse_create_image(struct usb_idmouse *dev)
@@ -112,42 +131,34 @@
 	int bulk_read = 0;
 	int result = 0;
 
-	if (dev->bulk_in_size < sizeof(HEADER))
-		return -ENOMEM;
-
-	memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1);
+	memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1);
 	bytes_read += sizeof(HEADER)-1;
 
-	/* Dump the setup packets. Yes, they are uncommented, simply 
-	   because they were sniffed under Windows using SnoopyPro.
-	   I _guess_ that 0x22 is a kind of reset command and 0x21 
-	   means init..
-	*/
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+	/* reset the device and set a fast blink rate */
+	result = ftip_command(dev, FTIP_RELEASE, 0, 0);
 	if (result < 0)
-		return result;
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+		goto reset;
+	result = ftip_command(dev, FTIP_BLINK,   1, 0);
 	if (result < 0)
-		return result;
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
-	if (result < 0)
-		return result;
+		goto reset;
 
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+	/* initialize the sensor - sending this command twice */
+	/* significantly reduces the rate of failed reads     */
+	result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
 	if (result < 0)
-		return result;
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+		goto reset;
+	result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
 	if (result < 0)
-		return result;
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
+		goto reset;
+
+	/* start the readout - sending this command twice */
+	/* presumably enables the high dynamic range mode */
+	result = ftip_command(dev, FTIP_RESET,   0, 0);
 	if (result < 0)
-		return result;
+		goto reset;
+	result = ftip_command(dev, FTIP_RESET,   0, 0);
+	if (result < 0)
+		goto reset;
 
 	/* loop over a blocking bulk read to get data from the device */
 	while (bytes_read < IMGSIZE) {
@@ -155,22 +166,40 @@
 				usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
 				dev->bulk_in_buffer + bytes_read,
 				dev->bulk_in_size, &bulk_read, 5000);
-		if (result < 0)
-			return result;
-		if (signal_pending(current))
-			return -EINTR;
+		if (result < 0) {
+			/* Maybe this error was caused by the increased packet size? */
+			/* Reset to the original value and tell userspace to retry.  */
+			if (dev->bulk_in_size != dev->orig_bi_size) {
+				dev->bulk_in_size = dev->orig_bi_size;
+				result = -EAGAIN;
+			}
+			break;
+		}
+		if (signal_pending(current)) {
+			result = -EINTR;
+			break;
+		}
 		bytes_read += bulk_read;
 	}
 
 	/* reset the device */
-	result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
-				0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
-	if (result < 0)
-		return result;
+reset:
+	ftip_command(dev, FTIP_RELEASE, 0, 0);
 
-	/* should be IMGSIZE == 64815 */
+	/* check for valid image */
+	/* right border should be black (0x00) */
+	for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
+		if (dev->bulk_in_buffer[bytes_read] != 0x00)
+			return -EAGAIN;
+
+	/* lower border should be white (0xFF) */
+	for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++)
+		if (dev->bulk_in_buffer[bytes_read] != 0xFF)
+			return -EAGAIN;
+
+	/* should be IMGSIZE == 65040 */
 	dbg("read %d bytes fingerprint data", bytes_read);
-	return 0;
+	return result;
 }
 
 static inline void idmouse_delete(struct usb_idmouse *dev)
@@ -282,10 +311,10 @@
 
 	dev = (struct usb_idmouse *) file->private_data;
 
-	// lock this object
+	/* lock this object */
 	down (&dev->sem);
 
-	// verify that the device wasn't unplugged
+	/* verify that the device wasn't unplugged */
 	if (!dev->present) {
 		up (&dev->sem);
 		return -ENODEV;
@@ -296,8 +325,7 @@
 		return 0;
 	}
 
-	if (count > IMGSIZE - *ppos)
-		count = IMGSIZE - *ppos;
+	count = min ((loff_t)count, IMGSIZE - (*ppos));
 
 	if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) {
 		result = -EFAULT;
@@ -306,7 +334,7 @@
 		*ppos += count;
 	}
 
-	// unlock the device 
+	/* unlock the device */
 	up(&dev->sem);
 	return result;
 }
@@ -318,7 +346,6 @@
 	struct usb_idmouse *dev = NULL;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
-	size_t buffer_size;
 	int result;
 
 	/* check if we have gotten the data or the hid interface */
@@ -344,11 +371,11 @@
 		USB_ENDPOINT_XFER_BULK)) {
 
 		/* we found a bulk in endpoint */
-		buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-		dev->bulk_in_size = buffer_size;
+		dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
+		dev->bulk_in_size = 0x200; /* works _much_ faster */
 		dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
 		dev->bulk_in_buffer =
-			kmalloc(IMGSIZE + buffer_size, GFP_KERNEL);
+			kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
 
 		if (!dev->bulk_in_buffer) {
 			err("Unable to allocate input buffer.");
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 3104f28..cda7249 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -461,7 +461,7 @@
 
 static unsigned realworld = 1;
 module_param (realworld, uint, 0);
-MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
+MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance");
 
 static int get_altsetting (struct usbtest_dev *dev)
 {
@@ -604,9 +604,8 @@
 				USB_DIR_IN | USB_RECIP_DEVICE,
 				0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
 		if (retval != 1 || dev->buf [0] != expected) {
-			dev_dbg (&iface->dev,
-				"get config --> %d (%d)\n", retval,
-				expected);
+			dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+				retval, dev->buf[0], expected);
 			return (retval < 0) ? retval : -EDOM;
 		}
 	}
@@ -1243,7 +1242,7 @@
 	char			*what = "?";
 	struct usb_device	*udev;
 	
-	if (length > 0xffff || vary >= length)
+	if (length < 1 || length > 0xffff || vary >= length)
 		return -EINVAL;
 
 	buf = kmalloc(length, SLAB_KERNEL);
@@ -1266,6 +1265,11 @@
 				0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
 		if (retval != len) {
 			what = "write";
+			if (retval >= 0) {
+				INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+						retval, len);
+				retval = -EBADMSG;
+			}
 			break;
 		}
 
@@ -1275,6 +1279,11 @@
 				0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
 		if (retval != len) {
 			what = "read";
+			if (retval >= 0) {
+				INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+						retval, len);
+				retval = -EBADMSG;
+			}
 			break;
 		}
 
@@ -1293,8 +1302,13 @@
 		}
 
 		len += vary;
+
+		/* [real world] the "zero bytes IN" case isn't really used.
+		 * hardware can easily trip up in this wierd case, since its
+		 * status stage is IN, not OUT like other ep0in transfers.
+		 */
 		if (len > length)
-			len = 0;
+			len = realworld ? 1 : 0;
 	}
 
 	if (retval < 0)
@@ -1519,6 +1533,11 @@
 	if (down_interruptible (&dev->sem))
 		return -ERESTARTSYS;
 
+	if (intf->dev.power.power_state != PMSG_ON) {
+		up (&dev->sem);
+		return -EHOSTUNREACH;
+	}
+
 	/* some devices, like ez-usb default devices, need a non-default
 	 * altsetting to have any active endpoints.  some tests change
 	 * altsettings; force a default so most tests don't need to check.
@@ -1762,8 +1781,10 @@
 	case 14:
 		if (!dev->info->ctrl_out)
 			break;
-		dev_dbg (&intf->dev, "TEST 14:  %d ep0out, 0..%d vary %d\n",
-				param->iterations, param->length, param->vary);
+		dev_dbg (&intf->dev, "TEST 14:  %d ep0out, %d..%d vary %d\n",
+				param->iterations,
+				realworld ? 1 : 0, param->length,
+				param->vary);
 		retval = ctrl_out (dev, param->iterations, 
 				param->length, param->vary);
 		break;
@@ -1927,6 +1948,27 @@
 	return 0;
 }
 
+static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
+{
+	struct usbtest_dev	*dev = usb_get_intfdata (intf);
+
+	down (&dev->sem);
+	intf->dev.power.power_state = PMSG_SUSPEND;
+	up (&dev->sem);
+	return 0;
+}
+
+static int usbtest_resume (struct usb_interface *intf)
+{
+	struct usbtest_dev	*dev = usb_get_intfdata (intf);
+
+	down (&dev->sem);
+	intf->dev.power.power_state = PMSG_ON;
+	up (&dev->sem);
+	return 0;
+}
+
+
 static void usbtest_disconnect (struct usb_interface *intf)
 {
 	struct usbtest_dev	*dev = usb_get_intfdata (intf);
@@ -2115,6 +2157,8 @@
 	.probe =	usbtest_probe,
 	.ioctl =	usbtest_ioctl,
 	.disconnect =	usbtest_disconnect,
+	.suspend =	usbtest_suspend,
+	.resume =	usbtest_resume,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 4cbb408..8a945f4 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -1429,7 +1429,7 @@
 			info->ether = (void *) buf;
 			if (info->ether->bLength != sizeof *info->ether) {
 				dev_dbg (&intf->dev, "CDC ether len %u\n",
-					info->u->bLength);
+					info->ether->bLength);
 				goto bad_desc;
 			}
 			dev->net->mtu = le16_to_cpup (
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index 341ae5f..3b387b0 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -1884,12 +1884,53 @@
 	kfree(zd);
 }
 
+#ifdef CONFIG_PM
+
+static int zd1201_suspend(struct usb_interface *interface,
+			   pm_message_t message)
+{
+	struct zd1201 *zd = usb_get_intfdata(interface);
+
+	netif_device_detach(zd->dev);
+
+	zd->was_enabled = zd->mac_enabled;
+
+	if (zd->was_enabled)
+		return zd1201_disable(zd);
+	else
+		return 0;
+}
+
+static int zd1201_resume(struct usb_interface *interface)
+{
+	struct zd1201 *zd = usb_get_intfdata(interface);
+
+	if (!zd || !zd->dev)
+		return -ENODEV;
+
+	netif_device_attach(zd->dev);
+
+	if (zd->was_enabled)
+		return zd1201_enable(zd);
+	else
+		return 0;
+}
+
+#else
+
+#define zd1201_suspend NULL
+#define zd1201_resume  NULL
+
+#endif
+
 static struct usb_driver zd1201_usb = {
 	.owner = THIS_MODULE,
 	.name = "zd1201",
 	.probe = zd1201_probe,
 	.disconnect = zd1201_disconnect,
 	.id_table = zd1201_table,
+	.suspend = zd1201_suspend,
+	.resume = zd1201_resume,
 };
 
 static int __init zd1201_init(void)
diff --git a/drivers/usb/net/zd1201.h b/drivers/usb/net/zd1201.h
index 1627c71..235f0ee 100644
--- a/drivers/usb/net/zd1201.h
+++ b/drivers/usb/net/zd1201.h
@@ -46,6 +46,7 @@
 	char			essid[IW_ESSID_MAX_SIZE+1];
 	int			essidlen;
 	int			mac_enabled;
+	int			was_enabled;
 	int			monitor;
 	int			encode_enabled;
 	int			encode_restricted;
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 46a204c..b5b4310 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -213,10 +213,14 @@
 		return (0);
 	}
 
-	if (port->write_urb->status == -EINPROGRESS) {
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
 		dbg("%s - already writing", __FUNCTION__);
-		return (0);
+		return 0;
 	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -224,6 +228,7 @@
 		/* To much data for buffer. Reset buffer. */
 		priv->wrfilled=0;
 		spin_unlock_irqrestore(&priv->lock, flags);
+		port->write_urb_busy = 0;
 		return (0);
 	}
 
@@ -268,6 +273,7 @@
 			priv->wrfilled=0;
 			priv->wrsent=0;
 			spin_unlock_irqrestore(&priv->lock, flags);
+			port->write_urb_busy = 0;
 			return 0;
 		}
 
@@ -412,7 +418,8 @@
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
+
+	port->write_urb_busy = 0;
 	if (urb->status) {
 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
@@ -424,12 +431,6 @@
 	if( priv->wrfilled ) {
 		int length, blksize, result;
 
-		if (port->write_urb->status == -EINPROGRESS) {
-			dbg("%s - already writing", __FUNCTION__);
-			spin_unlock(&priv->lock);
-			return;
-		}
-
 		dbg("%s - transmitting data (frame n)", __FUNCTION__);
 
 		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 99214aa..ddde5fb 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -174,10 +174,14 @@
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
-		if (port->write_urb->status == -EINPROGRESS) {
+		spin_lock(&port->lock);
+		if (port->write_urb_busy) {
+			spin_unlock(&port->lock);
 			dbg("%s - already writing", __FUNCTION__);
-			return (0);
+			return 0;
 		}
+		port->write_urb_busy = 1;
+		spin_unlock(&port->lock);
 
 		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
@@ -195,17 +199,20 @@
 				     usb_serial_generic_write_bulk_callback), port);
 
 		/* send the data out the bulk port */
+		port->write_urb_busy = 1;
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
+		if (result) {
 			dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
-		else
+			/* don't have to grab the lock here, as we will retry if != 0 */
+			port->write_urb_busy = 0;
+		} else
 			result = count;
 
 		return result;
 	}
 
 	/* no bulk out, so return 0 bytes written */
-	return (0);
+	return 0;
 }
 
 int usb_serial_generic_write_room (struct usb_serial_port *port)
@@ -214,9 +221,9 @@
 	int room = 0;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
+
 	if (serial->num_bulk_out) {
-		if (port->write_urb->status != -EINPROGRESS)
+		if (port->write_urb_busy)
 			room = port->bulk_out_size;
 	}
 
@@ -232,7 +239,7 @@
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (serial->num_bulk_out) {
-		if (port->write_urb->status == -EINPROGRESS)
+		if (port->write_urb_busy)
 			chars = port->write_urb->transfer_buffer_length;
 	}
 
@@ -291,6 +298,7 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
+	port->write_urb_busy = 0;
 	if (urb->status) {
 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 3bd69c4..c05c2a2 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -818,11 +818,6 @@
 	struct ipaq_packet	*pkt, *tmp;
 	struct urb		*urb = port->write_urb;
 
-	if (urb->status == -EINPROGRESS) {
-		/* Should never happen */
-		err("%s - flushing while urb is active !", __FUNCTION__);
-		return;
-	}
 	room = URBDATA_SIZE;
 	list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
 		count = min(room, (int)(pkt->len - pkt->written));
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 11105d7..85e2424 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -399,16 +399,21 @@
 		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return 0;
 	}
-	
-	/* Racy and broken, FIXME properly! */
-	if (port->write_urb->status == -EINPROGRESS)
+
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
+		dbg("%s - already writing", __FUNCTION__);
 		return 0;
+	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	count = min(count, port->bulk_out_size);
 	memcpy(port->bulk_out_buffer, buf, count);
 
 	dbg("%s count now:%d", __FUNCTION__, count);
-	
+
 	usb_fill_bulk_urb(port->write_urb, dev,
 			  usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
 			  port->write_urb->transfer_buffer,
@@ -418,6 +423,7 @@
 
 	ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 	if (ret != 0) {
+		port->write_urb_busy = 0;
 		dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
 		return ret;
 	}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 59f234d..937b2fd 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -341,10 +341,14 @@
 	if (count == 0)
 		return 0;
 
-	if (port->write_urb->status == -EINPROGRESS) {
-		dbg ("%s - already writing", __FUNCTION__);
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
+		dbg("%s - already writing", __FUNCTION__);
 		return 0;
 	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	transfer_buffer = port->write_urb->transfer_buffer;
 	transfer_size = min(count, port->bulk_out_size - 1);
@@ -374,9 +378,10 @@
 	port->write_urb->transfer_flags = URB_ZERO_PACKET;
 
 	result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
-	if (result)
+	if (result) {
+		port->write_urb_busy = 0;
 		dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
-	else
+	} else
 		result = transfer_size;
 
 	return result;
@@ -387,7 +392,8 @@
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
+
+	port->write_urb_busy = 0;
 	if (urb->status) {
 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 7fd0aa9..635c384 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -520,9 +520,13 @@
 	   the TX urb is in-flight (wait until it completes)
 	   the device is full (wait until it says there is room)
 	*/
-	if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
-		return( 0 );
+	spin_lock(&port->lock);
+	if (port->write_urb_busy || priv->tx_throttled) {
+		spin_unlock(&port->lock);
+		return 0;
 	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	/* At this point the URB is in our control, nobody else can submit it
 	   again (the only sudden transition was the one from EINPROGRESS to
@@ -570,7 +574,7 @@
 		memcpy (port->write_urb->transfer_buffer, buf, count);
 		/* send the data out the bulk port */
 		port->write_urb->transfer_buffer_length = count;
-		
+
 		priv->tx_room -= count;
 
 		port->write_urb->dev = port->serial->dev;
@@ -593,6 +597,8 @@
 
 	rc = count;
 exit:
+	if (rc < 0)
+		port->write_urb_busy = 0;
 	return rc;
 }
 
@@ -602,6 +608,7 @@
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct keyspan_pda_private *priv;
 
+	port->write_urb_busy = 0;
 	priv = usb_get_serial_port_data(port);
 
 	/* queue up a wakeup at scheduler time */
@@ -626,12 +633,12 @@
 static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
 {
 	struct keyspan_pda_private *priv;
-	
+
 	priv = usb_get_serial_port_data(port);
-	
+
 	/* when throttled, return at least WAKEUP_CHARS to tell select() (via
 	   n_tty.c:normal_poll() ) that we're not writeable. */
-	if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+	if (port->write_urb_busy || priv->tx_throttled)
 		return 256;
 	return 0;
 }
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index b5f2c06..6a99ae1 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -254,10 +254,15 @@
 		dbg("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
-	if (wport->write_urb->status == -EINPROGRESS) {
+
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
 		dbg("%s - already writing", __FUNCTION__);
-		return (0);
+		return 0;
 	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
 
@@ -275,9 +280,10 @@
 
 	wport->write_urb->dev = serial->dev;
 	result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
-	if (result)
+	if (result) {
+		port->write_urb_busy = 0;
 		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
-	else
+	} else
 		result = count;
 
 	return result;
@@ -291,7 +297,7 @@
 
 	int room = 0; // Default: no room
 
-	if (wport->write_urb->status != -EINPROGRESS)
+	if (wport->write_urb_busy)
 		room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
 //	dbg("omninet_write_room returns %d", room);
@@ -306,6 +312,7 @@
 
 //	dbg("omninet_write_bulk_callback, port %0x\n", port);
 
+	port->write_urb_busy = 0;
 	if (urb->status) {
 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 0e85ed6..96a1756 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -299,10 +299,14 @@
 		dbg ("%s - write request of 0 bytes", __FUNCTION__);
 		return (0);
 	}
-	if (port->write_urb->status == -EINPROGRESS) {
-		dbg ("%s - already writing", __FUNCTION__);
-		return (0);
+	spin_lock(&port->lock);
+	if (port->write_urb_busy) {
+		spin_unlock(&port->lock);
+		dbg("%s - already writing", __FUNCTION__);
+		return 0;
 	}
+	port->write_urb_busy = 1;
+	spin_unlock(&port->lock);
 
 	packet_length = port->bulk_out_size;	// get max packetsize
 
@@ -354,6 +358,7 @@
 #endif
 	port->write_urb->dev = port->serial->dev;
 	if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+		port->write_urb_busy = 0;
 		err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 		return 0;
 	}
@@ -368,7 +373,7 @@
 
 	dbg ("%s", __FUNCTION__);
 
-	if (port->write_urb->status != -EINPROGRESS)
+	if (port->write_urb_busy)
 		room = port->bulk_out_size - (safe ? 2 : 0);
 
 	if (room) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 5da76dd..0267b26 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1047,6 +1047,7 @@
 		memset(port, 0x00, sizeof(struct usb_serial_port));
 		port->number = i + serial->minor;
 		port->serial = serial;
+		spin_lock_init(&port->lock);
 		INIT_WORK(&port->work, usb_serial_port_softint, port);
 		serial->port[i] = port;
 	}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index d1f0c40..57f92f0 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -69,6 +69,7 @@
  * usb_serial_port: structure for the specific ports of a device.
  * @serial: pointer back to the struct usb_serial owner of this port.
  * @tty: pointer to the corresponding tty for this port.
+ * @lock: spinlock to grab when updating portions of this structure.
  * @number: the number of the port (the minor number).
  * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
  * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@@ -98,6 +99,7 @@
 struct usb_serial_port {
 	struct usb_serial *	serial;
 	struct tty_struct *	tty;
+	spinlock_t		lock;
 	unsigned char		number;
 
 	unsigned char *		interrupt_in_buffer;
@@ -117,6 +119,7 @@
 	unsigned char *		bulk_out_buffer;
 	int			bulk_out_size;
 	struct urb *		write_urb;
+	int			write_urb_busy;
 	__u8			bulk_out_endpointAddress;
 
 	wait_queue_head_t	write_wait;
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e43eddc..af294bb 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -155,6 +155,15 @@
 		 * If this device makes that mistake, tell the sd driver. */
 		if (us->flags & US_FL_FIX_CAPACITY)
 			sdev->fix_capacity = 1;
+
+		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
+		 * Hardware Error) when any low-level error occurs,
+		 * recoverable or not.  Setting this flag tells the SCSI
+		 * midlayer to retry such commands, which frequently will
+		 * succeed and fix the error.  The worst this can lead to
+		 * is an occasional series of retries that will all fail. */
+		sdev->retry_hwerror = 1;
+
 	} else {
 
 		/* Non-disk-type devices don't need to blacklist any pages
@@ -255,50 +264,23 @@
 
 	/* lock the device pointers and do the reset */
 	down(&(us->dev_semaphore));
-	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-		result = FAILED;
-		US_DEBUGP("No reset during disconnect\n");
-	} else
-		result = us->transport_reset(us);
+	result = us->transport_reset(us);
 	up(&(us->dev_semaphore));
 
-	return result;
+	return result < 0 ? FAILED : SUCCESS;
 }
 
-/* This resets the device's USB port. */
-/* It refuses to work if there's more than one interface in
- * the device, so that other users are not affected. */
+/* Simulate a SCSI bus reset by resetting the device's USB port. */
 /* This is always called with scsi_lock(host) held */
 static int bus_reset(struct scsi_cmnd *srb)
 {
 	struct us_data *us = host_to_us(srb->device->host);
-	int result, rc;
+	int result;
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	/* The USB subsystem doesn't handle synchronisation between
-	 * a device's several drivers. Therefore we reset only devices
-	 * with just one interface, which we of course own. */
-
 	down(&(us->dev_semaphore));
-	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-		result = -EIO;
-		US_DEBUGP("No reset during disconnect\n");
-	} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
-		result = -EBUSY;
-		US_DEBUGP("Refusing to reset a multi-interface device\n");
-	} else {
-		rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
-		if (rc < 0) {
-			US_DEBUGP("unable to lock device for reset: %d\n", rc);
-			result = rc;
-		} else {
-			result = usb_reset_device(us->pusb_dev);
-			if (rc)
-				usb_unlock_device(us->pusb_dev);
-			US_DEBUGP("usb_reset_device returns %d\n", result);
-		}
-	}
+	result = usb_stor_port_reset(us);
 	up(&(us->dev_semaphore));
 
 	/* lock the host for the return */
@@ -320,6 +302,14 @@
 	}
 }
 
+/* Report a driver-initiated bus reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock. */
+void usb_stor_report_bus_reset(struct us_data *us)
+{
+	scsi_report_bus_reset(us_to_host(us), 0);
+}
+
 /***********************************************************************
  * /proc/scsi/ functions
  ***********************************************************************/
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
index d0a49af..737e4fa 100644
--- a/drivers/usb/storage/scsiglue.h
+++ b/drivers/usb/storage/scsiglue.h
@@ -42,6 +42,7 @@
 #define _SCSIGLUE_H_
 
 extern void usb_stor_report_device_reset(struct us_data *us);
+extern void usb_stor_report_bus_reset(struct us_data *us);
 
 extern unsigned char usb_stor_sense_invalidCDB[18];
 extern struct scsi_host_template usb_stor_host_template;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 9743e28..e6b1c6c 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -266,8 +266,9 @@
 		NULL, 0, 3*HZ);
 
 	/* reset the endpoint toggle */
-	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
-		usb_pipeout(pipe), 0);
+	if (result >= 0)
+		usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+				usb_pipeout(pipe), 0);
 
 	US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
 	return result;
@@ -540,15 +541,15 @@
 	 */
 	if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
 		US_DEBUGP("-- command was aborted\n");
-		goto Handle_Abort;
+		srb->result = DID_ABORT << 16;
+		goto Handle_Errors;
 	}
 
 	/* if there is a transport error, reset and don't auto-sense */
 	if (result == USB_STOR_TRANSPORT_ERROR) {
 		US_DEBUGP("-- transport indicates error, resetting\n");
-		us->transport_reset(us);
 		srb->result = DID_ERROR << 16;
-		return;
+		goto Handle_Errors;
 	}
 
 	/* if the transport provided its own sense data, don't auto-sense */
@@ -668,7 +669,8 @@
 
 		if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
 			US_DEBUGP("-- auto-sense aborted\n");
-			goto Handle_Abort;
+			srb->result = DID_ABORT << 16;
+			goto Handle_Errors;
 		}
 		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
 			US_DEBUGP("-- auto-sense failure\n");
@@ -677,9 +679,9 @@
 			 * multi-target device, since failure of an
 			 * auto-sense is perfectly valid
 			 */
-			if (!(us->flags & US_FL_SCM_MULT_TARG))
-				us->transport_reset(us);
 			srb->result = DID_ERROR << 16;
+			if (!(us->flags & US_FL_SCM_MULT_TARG))
+				goto Handle_Errors;
 			return;
 		}
 
@@ -720,12 +722,28 @@
 
 	return;
 
-	/* abort processing: the bulk-only transport requires a reset
-	 * following an abort */
-  Handle_Abort:
-	srb->result = DID_ABORT << 16;
-	if (us->protocol == US_PR_BULK)
+	/* Error and abort processing: try to resynchronize with the device
+	 * by issuing a port reset.  If that fails, try a class-specific
+	 * device reset. */
+  Handle_Errors:
+
+	/* Let the SCSI layer know we are doing a reset, set the
+	 * RESETTING bit, and clear the ABORTING bit so that the reset
+	 * may proceed. */
+	scsi_lock(us_to_host(us));
+	usb_stor_report_bus_reset(us);
+	set_bit(US_FLIDX_RESETTING, &us->flags);
+	clear_bit(US_FLIDX_ABORTING, &us->flags);
+	scsi_unlock(us_to_host(us));
+
+	result = usb_stor_port_reset(us);
+	if (result < 0) {
+		scsi_lock(us_to_host(us));
+		usb_stor_report_device_reset(us);
+		scsi_unlock(us_to_host(us));
 		us->transport_reset(us);
+	}
+	clear_bit(US_FLIDX_RESETTING, &us->flags);
 }
 
 /* Stop the current URB transfer */
@@ -1124,7 +1142,7 @@
  * It's handy that every transport mechanism uses the control endpoint for
  * resets.
  *
- * Basically, we send a reset with a 20-second timeout, so we don't get
+ * Basically, we send a reset with a 5-second timeout, so we don't get
  * jammed attempting to do the reset.
  */
 static int usb_stor_reset_common(struct us_data *us,
@@ -1133,28 +1151,18 @@
 {
 	int result;
 	int result2;
-	int rc = FAILED;
 
-	/* Let the SCSI layer know we are doing a reset, set the
-	 * RESETTING bit, and clear the ABORTING bit so that the reset
-	 * may proceed.
-	 */
-	scsi_lock(us_to_host(us));
-	usb_stor_report_device_reset(us);
-	set_bit(US_FLIDX_RESETTING, &us->flags);
-	clear_bit(US_FLIDX_ABORTING, &us->flags);
-	scsi_unlock(us_to_host(us));
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		US_DEBUGP("No reset during disconnect\n");
+		return -EIO;
+	}
 
-	/* A 20-second timeout may seem rather long, but a LaCie
-	 * StudioDrive USB2 device takes 16+ seconds to get going
-	 * following a powerup or USB attach event.
-	 */
 	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
 			request, requesttype, value, index, data, size,
-			20*HZ);
+			5*HZ);
 	if (result < 0) {
 		US_DEBUGP("Soft reset failed: %d\n", result);
-		goto Done;
+		return result;
 	}
 
  	/* Give the device some time to recover from the reset,
@@ -1164,7 +1172,7 @@
  			HZ*6);
 	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
 		US_DEBUGP("Reset interrupted by disconnect\n");
-		goto Done;
+		return -EIO;
 	}
 
 	US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
@@ -1173,17 +1181,14 @@
 	US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
 	result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
 
-	/* return a result code based on the result of the control message */
-	if (result < 0 || result2 < 0) {
+	/* return a result code based on the result of the clear-halts */
+	if (result >= 0)
+		result = result2;
+	if (result < 0)
 		US_DEBUGP("Soft reset failed\n");
-		goto Done;
-	}
-	US_DEBUGP("Soft reset done\n");
-	rc = SUCCESS;
-
-  Done:
-	clear_bit(US_FLIDX_RESETTING, &us->flags);
-	return rc;
+	else
+		US_DEBUGP("Soft reset done\n");
+	return result;
 }
 
 /* This issues a CB[I] Reset to the device in question
@@ -1213,3 +1218,32 @@
 				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 				 0, us->ifnum, NULL, 0);
 }
+
+/* Issue a USB port reset to the device.  But don't do anything if
+ * there's more than one interface in the device, so that other users
+ * are not affected. */
+int usb_stor_port_reset(struct us_data *us)
+{
+	int result, rc;
+
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		result = -EIO;
+		US_DEBUGP("No reset during disconnect\n");
+	} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
+		result = -EBUSY;
+		US_DEBUGP("Refusing to reset a multi-interface device\n");
+	} else {
+		result = rc =
+			usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+		if (result < 0) {
+			US_DEBUGP("unable to lock device for reset: %d\n",
+					result);
+		} else {
+			result = usb_reset_device(us->pusb_dev);
+			if (rc)
+				usb_unlock_device(us->pusb_dev);
+			US_DEBUGP("usb_reset_device returns %d\n", result);
+		}
+	}
+	return result;
+}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index e25f8d8..8d9e066 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -171,4 +171,5 @@
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, int use_sg, int *residual);
 
+extern int usb_stor_port_reset(struct us_data *us);
 #endif
diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h
index 1438c6c..054fb9a 100644
--- a/include/asm-arm/arch-omap/usb.h
+++ b/include/asm-arm/arch-omap/usb.h
@@ -47,6 +47,15 @@
 #	define	 HMC_TLLATTACH		(1 << 6)
 #	define	 OTG_HMC(w)		(((w)>>0)&0x3f)
 #define OTG_CTRL_REG			OTG_REG32(0x0c)
+#	define	 OTG_USB2_EN		(1 << 29)
+#	define	 OTG_USB2_DP		(1 << 28)
+#	define	 OTG_USB2_DM		(1 << 27)
+#	define	 OTG_USB1_EN		(1 << 26)
+#	define	 OTG_USB1_DP		(1 << 25)
+#	define	 OTG_USB1_DM		(1 << 24)
+#	define	 OTG_USB0_EN		(1 << 23)
+#	define	 OTG_USB0_DP		(1 << 22)
+#	define	 OTG_USB0_DM		(1 << 21)
 #	define	 OTG_ASESSVLD		(1 << 20)
 #	define	 OTG_BSESSEND		(1 << 19)
 #	define	 OTG_BSESSVLD		(1 << 18)
diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h
index f5fe94e..39e7ff4 100644
--- a/include/linux/usb_ch9.h
+++ b/include/linux/usb_ch9.h
@@ -6,11 +6,14 @@
  *
  * - the master/host side Linux-USB kernel driver API;
  * - the "usbfs" user space API; and
- * - (eventually) a Linux "gadget" slave/device side driver API.
+ * - the Linux "gadget" slave/device/peripheral side driver API.
  *
  * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
  * act either as a USB master/host or as a USB slave/device.  That means
- * the master and slave side APIs will benefit from working well together.
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
  */
 
 #ifndef __LINUX_USB_CH9_H
@@ -68,6 +71,18 @@
 #define USB_REQ_SET_INTERFACE		0x0B
 #define USB_REQ_SYNCH_FRAME		0x0C
 
+#define USB_REQ_SET_ENCRYPTION		0x0D	/* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION		0x0E
+#define USB_REQ_SET_HANDSHAKE		0x0F
+#define USB_REQ_GET_HANDSHAKE		0x10
+#define USB_REQ_SET_CONNECTION		0x11
+#define USB_REQ_SET_SECURITY_DATA	0x12
+#define USB_REQ_GET_SECURITY_DATA	0x13
+#define USB_REQ_SET_WUSB_DATA		0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE	0x15
+#define USB_REQ_LOOPBACK_DATA_READ	0x16
+#define USB_REQ_SET_INTERFACE_DS	0x17
+
 /*
  * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
  * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
@@ -75,10 +90,12 @@
  */
 #define USB_DEVICE_SELF_POWERED		0	/* (read only) */
 #define USB_DEVICE_REMOTE_WAKEUP	1	/* dev may initiate wakeup */
-#define USB_DEVICE_TEST_MODE		2	/* (high speed only) */
-#define USB_DEVICE_B_HNP_ENABLE		3	/* dev may initiate HNP */
-#define USB_DEVICE_A_HNP_SUPPORT	4	/* RH port supports HNP */
-#define USB_DEVICE_A_ALT_HNP_SUPPORT	5	/* other RH port does */
+#define USB_DEVICE_TEST_MODE		2	/* (wired high speed only) */
+#define USB_DEVICE_BATTERY		2	/* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE		3	/* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE		3	/* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT	4	/* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT	5	/* (otg) other RH port does */
 #define USB_DEVICE_DEBUG_MODE		6	/* (special devices only) */
 
 #define USB_ENDPOINT_HALT		0	/* IN/OUT will STALL */
@@ -135,6 +152,13 @@
 #define USB_DT_OTG			0x09
 #define USB_DT_DEBUG			0x0a
 #define USB_DT_INTERFACE_ASSOCIATION	0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY			0x0c
+#define USB_DT_KEY			0x0d
+#define USB_DT_ENCRYPTION_TYPE		0x0e
+#define USB_DT_BOS			0x0f
+#define USB_DT_DEVICE_CAPABILITY	0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP	0x11
 
 /* conventional codes for class-specific descriptors */
 #define USB_DT_CS_DEVICE		0x21
@@ -192,6 +216,7 @@
 #define USB_CLASS_CSCID			0x0b	/* chip+ smart card */
 #define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_VIDEO			0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER	0xe0
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
@@ -223,6 +248,7 @@
 #define USB_CONFIG_ATT_ONE		(1 << 7)	/* must be set */
 #define USB_CONFIG_ATT_SELFPOWER	(1 << 6)	/* self powered */
 #define USB_CONFIG_ATT_WAKEUP		(1 << 5)	/* can wakeup */
+#define USB_CONFIG_ATT_BATTERY		(1 << 4)	/* battery powered */
 
 /*-------------------------------------------------------------------------*/
 
@@ -289,6 +315,7 @@
 #define USB_ENDPOINT_XFER_ISOC		1
 #define USB_ENDPOINT_XFER_BULK		2
 #define USB_ENDPOINT_XFER_INT		3
+#define USB_ENDPOINT_MAX_ADJUSTABLE	0x80
 
 
 /*-------------------------------------------------------------------------*/
@@ -352,12 +379,154 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_SECURITY:  group of wireless security descriptors, including
+ * encryption types available for setting up a CC/association.
+ */
+struct usb_security_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__le16 wTotalLength;
+	__u8  bNumEncryptionTypes;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
+ * may be retrieved.
+ */
+struct usb_key_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  tTKID[3];
+	__u8  bReserved;
+	__u8  bKeyData[0];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
+struct usb_encryption_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  bEncryptionType;
+#define	USB_ENC_TYPE_UNSECURE		0
+#define	USB_ENC_TYPE_WIRED		1	/* non-wireless mode */
+#define	USB_ENC_TYPE_CCM_1		2	/* aes128/cbc session */
+#define	USB_ENC_TYPE_RSA_1		3	/* rsa3072/sha1 auth */
+	__u8  bEncryptionValue;		/* use in SET_ENCRYPTION */
+	__u8  bAuthKeyIndex;
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_BOS:  group of wireless capabilities */
+struct usb_bos_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__le16 wTotalLength;
+	__u8  bNumDeviceCaps;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
+struct usb_dev_cap_header {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDevCapabilityType;
+};
+
+#define	USB_CAP_TYPE_WIRELESS_USB	1
+
+struct usb_wireless_cap_descriptor {	/* Ultra Wide Band */
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDevCapabilityType;
+
+	__u8  bmAttributes;
+#define	USB_WIRELESS_P2P_DRD		(1 << 1)
+#define	USB_WIRELESS_BEACON_MASK	(3 << 2)
+#define	USB_WIRELESS_BEACON_SELF	(1 << 2)
+#define	USB_WIRELESS_BEACON_DIRECTED	(2 << 2)
+#define	USB_WIRELESS_BEACON_NONE	(3 << 2)
+	__le16 wPHYRates;	/* bit rates, Mbps */
+#define	USB_WIRELESS_PHY_53		(1 << 0)	/* always set */
+#define	USB_WIRELESS_PHY_80		(1 << 1)
+#define	USB_WIRELESS_PHY_107		(1 << 2)	/* always set */
+#define	USB_WIRELESS_PHY_160		(1 << 3)
+#define	USB_WIRELESS_PHY_200		(1 << 4)	/* always set */
+#define	USB_WIRELESS_PHY_320		(1 << 5)
+#define	USB_WIRELESS_PHY_400		(1 << 6)
+#define	USB_WIRELESS_PHY_480		(1 << 7)
+	__u8  bmTFITXPowerInfo;	/* TFI power levels */
+	__u8  bmFFITXPowerInfo;	/* FFI power levels */
+	__le16 bmBandGroup;
+	__u8  bReserved;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
+ * each endpoint descriptor for a wireless device
+ */
+struct usb_wireless_ep_comp_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  bMaxBurst;
+	__u8  bMaxSequence;
+	__le16 wMaxStreamDelay;
+	__le16 wOverTheAirPacketSize;
+	__u8  bOverTheAirInterval;
+	__u8  bmCompAttributes;
+#define USB_ENDPOINT_SWITCH_MASK	0x03	/* in bmCompAttributes */
+#define USB_ENDPOINT_SWITCH_NO		0
+#define USB_ENDPOINT_SWITCH_SWITCH	1
+#define USB_ENDPOINT_SWITCH_SCALE	2
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
+ * host and a device for connection set up, mutual authentication, and
+ * exchanging short lived session keys.  The handshake depends on a CC.
+ */
+struct usb_handshake {
+	__u8 bMessageNumber;
+	__u8 bStatus;
+	__u8 tTKID[3];
+	__u8 bReserved;
+	__u8 CDID[16];
+	__u8 nonce[16];
+	__u8 MIC[8];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
+ * A CC may also be set up using non-wireless secure channels (including
+ * wired USB!), and some devices may support CCs with multiple hosts.
+ */
+struct usb_connection_context {
+	__u8 CHID[16];		/* persistent host id */
+	__u8 CDID[16];		/* device id (unique w/in host context) */
+	__u8 CK[16];		/* connection key */
+};
+
+/*-------------------------------------------------------------------------*/
+
 /* USB 2.0 defines three speeds, here's how Linux identifies them */
 
 enum usb_device_speed {
 	USB_SPEED_UNKNOWN = 0,			/* enumerating */
 	USB_SPEED_LOW, USB_SPEED_FULL,		/* usb 1.1 */
-	USB_SPEED_HIGH				/* usb 2.0 */
+	USB_SPEED_HIGH,				/* usb 2.0 */
+	USB_SPEED_VARIABLE,			/* wireless (usb 2.5) */
 };
 
 enum usb_device_state {
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
index 9bba999..b00f127 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb_gadget.h
@@ -711,7 +711,7 @@
  * 	the hardware level driver. Most calls must be handled by
  * 	the gadget driver, including descriptor and configuration
  * 	management.  The 16 bit members of the setup data are in
- * 	cpu order. Called in_interrupt; this may not sleep.  Driver
+ * 	USB byte order. Called in_interrupt; this may not sleep.  Driver
  *	queues a response to ep0, or returns negative to stall.
  * @disconnect: Invoked after all transfers have been stopped,
  * 	when the host is disconnected.  May be called in_interrupt; this
diff --git a/include/linux/usb_isp116x.h b/include/linux/usb_isp116x.h
new file mode 100644
index 0000000..5f5a9d9
--- /dev/null
+++ b/include/linux/usb_isp116x.h
@@ -0,0 +1,47 @@
+
+/*
+ * Board initialization code should put one of these into dev->platform_data
+ * and place the isp116x onto platform_bus.
+ */
+
+struct isp116x_platform_data {
+	/* Enable internal resistors on downstream ports */
+	unsigned sel15Kres:1;
+	/* Chip's internal clock won't be stopped in suspended state.
+	   Setting/unsetting this bit takes effect only if
+	   'remote_wakeup_enable' below is not set. */
+	unsigned clknotstop:1;
+	/* On-chip overcurrent protection */
+	unsigned oc_enable:1;
+	/* INT output polarity */
+	unsigned int_act_high:1;
+	/* INT edge or level triggered */
+	unsigned int_edge_triggered:1;
+	/* WAKEUP pin connected - NOT SUPPORTED  */
+	/* unsigned remote_wakeup_connected:1; */
+	/* Wakeup by devices on usb bus enabled */
+	unsigned remote_wakeup_enable:1;
+	/* Switch or not to switch (keep always powered) */
+	unsigned no_power_switching:1;
+	/* Ganged port power switching (0) or individual port
+	   power switching (1) */
+	unsigned power_switching_mode:1;
+	/* Given port_power, msec/2 after power on till power good */
+	u8 potpg;
+	/* Hardware reset set/clear. If implemented, this function must:
+	   if set == 0,   deassert chip's HW reset pin
+	   otherwise,     assert chip's HW reset pin       */
+	void (*reset) (struct device * dev, int set);
+	/* Hardware clock start/stop. If implemented, this function must:
+	   if start == 0,    stop the external clock
+	   otherwise,        start the external clock
+	 */
+	void (*clock) (struct device * dev, int start);
+	/* Inter-io delay (ns). The chip is picky about access timings; it
+	   expects at least:
+	   150ns delay between consecutive accesses to DATA_REG,
+	   300ns delay between access to ADDR_REG and DATA_REG
+	   OE, WE MUST NOT be changed during these intervals
+	 */
+	void (*delay) (struct device * dev, int delay);
+};