diff -Nru a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
--- a/drivers/usb/host/Config.in	2003-11-28 13:26:20.000000000 -0500
+++ b/drivers/usb/host/Config.in	2005-02-03 16:00:59.000000000 -0500
@@ -3,6 +3,9 @@
 #
 comment 'USB Host Controller Drivers'
 dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_USB_EHCI_HCD" != "n" ]; then
+   bool '    Root Hub Transaction Translators (EXPERIMENTAL)' CONFIG_USB_EHCI_ROOT_HUB_TT $CONFIG_USB $CONFIG_EXPERIMENTAL
+fi
 if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
    dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
 fi
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	2004-02-18 08:36:31.000000000 -0500
+++ b/drivers/usb/host/ehci.h	2005-02-04 16:02:37.000000000 -0500
@@ -85,6 +85,8 @@
 	unsigned long		actions;
 	unsigned		stamp;
 
+	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
+
 	/* irq statistics */
 #ifdef EHCI_STATS
 	struct ehci_stats	stats;
@@ -105,6 +107,7 @@
 	TIMER_IAA_WATCHDOG,
 	TIMER_ASYNC_SHRINK,
 	TIMER_ASYNC_OFF,
+	TIMER_UNLINK_QTD
 };
 
 static inline void
@@ -129,6 +132,9 @@
 		case TIMER_ASYNC_OFF:
 			t = EHCI_ASYNC_JIFFIES;
 			break;
+		case TIMER_UNLINK_QTD:
+			t = EHCI_UNLINK_QTD_JIFFIES;
+			break;
 		// case TIMER_ASYNC_SHRINK:
 		default:
 			t = EHCI_SHRINK_JIFFIES;
@@ -363,6 +369,8 @@
 	struct list_head	qtd_list;	/* sw qtd list */
 	struct ehci_qtd		*dummy;
 	struct ehci_qh		*reclaim;	/* next to reclaim */
+	u8			unhalt;		/* Unhalt this qh (delay 1ms)*/
+	u32			unhalt_frame;	/* Unhalt after this frame */
 
 	atomic_t		refcount;
 	unsigned		stamp;
@@ -565,4 +573,41 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature.  Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+#define	ehci_is_TDI(e)			((e)->is_tdi_rh_tt)
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+{
+	if (ehci_is_TDI(ehci)) {
+		switch ((portsc>>26)&3) {
+		case 0:
+			return 0;
+		case 1:
+			return (1<<USB_PORT_FEAT_LOWSPEED);
+		case 2:
+		default:
+			return (1<<USB_PORT_FEAT_HIGHSPEED);
+		}
+	}
+	return (1<<USB_PORT_FEAT_HIGHSPEED);
+}
+
+#else
+
+#define	ehci_is_TDI(e)			(0)
+
+#define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
+#endif
+/*-------------------------------------------------------------------------*/
+
 #endif /* __LINUX_EHCI_HCD_H */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	2004-11-17 06:54:21.000000000 -0500
+++ b/drivers/usb/host/ehci-hcd.c	2005-02-04 16:08:45.000000000 -0500
@@ -124,6 +124,7 @@
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
 #define EHCI_SHRINK_JIFFIES	(HZ/200)	/* async qh unlink delay */
+#define EHCI_UNLINK_QTD_JIFFIES	(HZ/4000)	/* Wait to unhalt QH */
 
 /* Initial IRQ latency:  lower than default */
 static int log2_irq_thresh = 0;		// 0 to 6
@@ -194,16 +195,37 @@
 	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
 }
 
+/* put TDI/ARC silicon into EHCI mode */
+static void tdi_reset (struct ehci_hcd *ehci)
+{
+	u32		*reg_ptr;
+	u32		tmp;
+
+	reg_ptr = (u32 *)ehci->regs + (0x68/4);
+	tmp = readl (reg_ptr);
+	tmp |= 0x3;
+	writel (tmp, reg_ptr);
+}
+
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
+	int	retval;
 	u32	command = readl (&ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	writel (command, &ehci->regs->command);
 	ehci->hcd.state = USB_STATE_HALT;
-	return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+
+	if (retval)
+		return retval;
+
+	if (ehci->is_tdi_rh_tt)
+		tdi_reset (ehci);
+
+	return retval;
 }
 
 /* idle the controller (from running) */
@@ -347,7 +369,17 @@
 	hcc_params = readl (&ehci->caps->hcc_params);
 
 	/* EHCI 0.96 and later may have "extended capabilities" */
+	switch (ehci->hcd.pdev->vendor) {
+	case PCI_VENDOR_ID_TDI:
+		if (ehci->hcd.pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+			ehci->is_tdi_rh_tt = 1;
+			tdi_reset (ehci);
+		}
+		break;
+	}
+
 	temp = HCC_EXT_CAPS (hcc_params);
+ 
 	while (temp) {
 		u32		cap;
 
@@ -368,6 +400,9 @@
 		temp = (cap >> 8) & 0xff;
 	}
 
+	if (ehci->is_tdi_rh_tt)
+		ehci_reset (ehci);
+
 	/* cache this readonly data; minimize PCI reads */
 	ehci->hcs_params = readl (&ehci->caps->hcs_params);
 
@@ -399,7 +434,6 @@
 		ehci_mem_cleanup (ehci);
 		return retval;
 	}
-	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
 	/*
@@ -517,6 +551,8 @@
 		goto done2;
 	}
 
+	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+
 	create_debug_files (ehci);
 
 	return 0;
@@ -527,6 +563,7 @@
 static void ehci_stop (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u8			rh_ports, port;
 
 	ehci_dbg (ehci, "stop\n");
 
@@ -538,6 +575,14 @@
 		return;
 	}
 	del_timer_sync (&ehci->watchdog);
+
+	/* Turn off port power on all root hub ports. */
+	rh_ports = HCS_N_PORTS (ehci->hcs_params);
+	for (port = 1; port <= rh_ports; port++) {
+		ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,
+			port, NULL, 0);
+	}
+
 	ehci_reset (ehci);
 
 	/* let companion controllers work when we aren't */
diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
--- a/drivers/usb/host/ehci-hub.c	2004-04-14 09:05:33.000000000 -0400
+++ b/drivers/usb/host/ehci-hub.c	2005-02-03 16:00:59.000000000 -0500
@@ -40,6 +40,15 @@
 
 	/* if reset finished and it's still not enabled -- handoff */
 	if (!(port_status & PORT_PE)) {
+
+		/* with integrated TT, there's nobody to hand it to! */
+		if (ehci_is_TDI(ehci)) {
+			ehci_dbg (ehci,
+				"Failed to enable port %d on root hub TT\n",
+				index+1);
+			return port_status;
+		}
+
 		ehci_dbg (ehci, "port %d full speed --> companion\n",
 			index + 1);
 
@@ -257,7 +266,8 @@
 		if (!(temp & PORT_OWNER)) {
 			if (temp & PORT_CONNECT) {
 				status |= 1 << USB_PORT_FEAT_CONNECTION;
-				status |= 1 << USB_PORT_FEAT_HIGHSPEED;
+				// status may be from integrated TT
+				status |= ehci_port_speed(ehci, temp);
 			}
 			if (temp & PORT_PE)
 				status |= 1 << USB_PORT_FEAT_ENABLE;
@@ -307,8 +317,12 @@
 					&ehci->regs->port_status [wIndex]);
 			break;
 		case USB_PORT_FEAT_RESET:
-			/* line status bits may report this as low speed */
+			/* line status bits may report this as low speed,
+			 * which can be fine if this root hub has a
+			 * transaction translator built in.
+			 */
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& !ehci_is_TDI(ehci)
 					&& PORT_USB11 (temp)) {
 				ehci_dbg (ehci,
 					"port %d low speed --> companion\n",
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	2004-02-18 08:36:31.000000000 -0500
+++ b/drivers/usb/host/ehci-q.c	2005-02-03 16:00:59.000000000 -0500
@@ -91,9 +91,26 @@
 	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
 	qh->hw_alt_next = EHCI_LIST_END;
 
-	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
-	wmb ();
-	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+	if ((qh->hw_token & QTD_STS_HALT) &&
+	    (HCD_IS_RUNNING (ehci->hcd.state))) {
+
+		/* Don't unhalt the queue right now, schedule a task to do it.
+		 * This should insure that the EHCI controller has seen
+		 * the updated pointers to the top of the qtd list.
+		 */
+		qh->unhalt = 1;
+		qh->unhalt_frame = readl (&ehci->regs->frame_index);
+
+	} else {
+
+		/* HC must see latest qtd and qh data before we clear
+		 * ACTIVE+HALT
+		 */
+		wmb ();
+		qh->hw_token &=
+			__constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+	}
+
 }
 
 /*-------------------------------------------------------------------------*/
@@ -161,7 +178,10 @@
 				usb_endpoint_halt (urb->dev,
 					usb_pipeendpoint (pipe),
 					usb_pipeout (pipe));
-			if (urb->dev->tt && !usb_pipeint (pipe)) {
+			if (urb->dev->tt && !usb_pipeint (pipe)
+				&& (!ehci_is_TDI(ehci)
+					|| urb->dev->tt->hub !=
+						ehci->hcd.bus->root_hub)) { 
 #ifdef DEBUG
 				struct usb_device *tt = urb->dev->tt->hub;
 				dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
@@ -707,7 +727,13 @@
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
-		info2 |= urb->dev->tt->hub->devnum << 16;
+
+		/* set the address of the TT; for TDI's integrated
+		 * root hub tt, leave it zeroed.
+		 */
+		if (!ehci_is_TDI(ehci)
+				|| urb->dev->tt->hub != ehci->hcd.bus->root_hub)
+			info2 |= urb->dev->tt->hub->devnum << 16;
 
 		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
 
@@ -742,6 +768,8 @@
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
 	qh->hw_info2 = cpu_to_le32 (info2);
+	qh->unhalt = 0;
+	qh->unhalt_frame = 0;
 	qh_update (ehci, qh, qh->dummy);
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	return qh;
@@ -1079,14 +1107,19 @@
 {
 	struct ehci_qh		*qh;
 	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
+	u8			sched_unhalt;
 
 	if (!++(ehci->stamp))
 		ehci->stamp++;
 	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
+	timer_action_done (ehci, TIMER_UNLINK_QTD);
+
 rescan:
 	qh = ehci->async->qh_next.qh;
+	sched_unhalt = 0;
 	if (likely (qh != 0)) {
 		do {
+
 			/* clean any finished work for this qh */
 			if (!list_empty (&qh->qtd_list)
 					&& qh->stamp != ehci->stamp) {
@@ -1106,6 +1139,33 @@
 				}
 			}
 
+			/* The cleanup after a stall is finished, now we need
+			 * to unhalt the qh.
+			 */
+			if (qh->unhalt) {
+				unsigned int frames;
+
+				frames = readl (&ehci->regs->frame_index);
+
+				/* If the HCD is running then make sure that
+				 * two micro-frames have passed since we
+				 * changed the qtd pointer for this qh.
+			 	 */
+			 	if ((frames != 0) &&
+				    ((frames > qh->unhalt_frame+1) ||
+				    (qh->unhalt_frame > frames))) {
+
+					qh->unhalt = 0;
+					if (qh->hw_token & QTD_STS_HALT) {
+						qh->hw_token &=
+						  __constant_cpu_to_le32(
+						    QTD_TOGGLE | QTD_STS_PING);
+					}
+				} else {
+					sched_unhalt = 1;
+				}
+			}
+
 			/* unlink idle entries, reducing HC PCI usage as well
 			 * as HCD schedule-scanning costs.  delay for any qh
 			 * we just scanned, there's a not-unusual case that it
@@ -1123,6 +1183,11 @@
 			qh = qh->qh_next.qh;
 		} while (qh);
 	}
+
 	if (action == TIMER_ASYNC_SHRINK)
 		timer_action (ehci, TIMER_ASYNC_SHRINK);
+
+	if (sched_unhalt)
+		timer_action (ehci, TIMER_UNLINK_QTD);
+
 }
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	2004-11-17 06:54:22.000000000 -0500
+++ b/include/linux/pci_ids.h	2005-02-03 16:00:59.000000000 -0500
@@ -1757,6 +1757,9 @@
 #define PCI_DEVICE_ID_ALTIMA_AC9100	0x03ea
 #define PCI_DEVICE_ID_ALTIMA_AC1003	0x03eb
 
+#define PCI_VENDOR_ID_TDI		0x192E
+#define PCI_DEVICE_ID_TDI_EHCI		0x0101
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
