summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/patches-2.6.30
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/patches-2.6.30')
-rw-r--r--target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-nonewfiles.patch1336
-rw-r--r--target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-Kconfig.patch52
-rw-r--r--target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial-option.patch77
-rw-r--r--target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial.patch11
-rw-r--r--target/linux/realtek/patches-2.6.30/003-include-paths.diff24
-rw-r--r--target/linux/realtek/patches-2.6.30/114-rlx_819x_usb.patch100
-rw-r--r--target/linux/realtek/patches-2.6.30/2.6.30-to-32-usb.patch2840
-rw-r--r--target/linux/realtek/patches-2.6.30/300-dont-ask-for-usb-serial-option-define.patch12
-rw-r--r--target/linux/realtek/patches-2.6.30/9995-net-rtl819x-include-paths.patch11
9 files changed, 3080 insertions, 1383 deletions
diff --git a/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-nonewfiles.patch b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-nonewfiles.patch
index a04cbfc2f..3c0f44cf4 100644
--- a/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-nonewfiles.patch
+++ b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-nonewfiles.patch
@@ -6156,1339 +6156,3 @@
obj-$(CONFIG_USB_RSPI) += rspiusb/
obj-$(CONFIG_INPUT_MIMIO) += mimio/
obj-$(CONFIG_TRANZPORT) += frontier/
---- linux-2.6.30.9/drivers/usb/c67x00/c67x00-hcd.h 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/c67x00/c67x00-hcd.h 2013-05-02 01:47:56.720226816 +0300
-@@ -28,7 +28,13 @@
- #include <linux/spinlock.h>
- #include <linux/list.h>
- #include <linux/usb.h>
-+
-+#if defined(CONFIG_USB_UWIFI_HOST)
-+#include "../core_uWiFi/hcd.h"
-+#else
- #include "../core/hcd.h"
-+#endif
-+
- #include "c67x00.h"
-
- /*
---- linux-2.6.30.9/drivers/usb/core/devio.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/core/devio.c 2013-05-02 01:47:56.726226815 +0300
-@@ -476,6 +476,9 @@ static int releaseintf(struct dev_state
- else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
- usb_driver_release_interface(&usbfs_driver, intf);
- err = 0;
-+ #if defined(CONFIG_RTL_8198) || defined(CONFIG_RTL_819XD)
-+ mdelay(100);
-+ #endif
- }
- return err;
- }
---- linux-2.6.30.9/drivers/usb/core/hcd.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/core/hcd.c 2013-05-02 01:47:56.728226815 +0300
-@@ -82,7 +82,7 @@
- /*-------------------------------------------------------------------------*/
-
- /* Keep track of which host controller drivers are loaded */
--unsigned long usb_hcds_loaded;
-+unsigned long usb_hcds_loaded=0;
- EXPORT_SYMBOL_GPL(usb_hcds_loaded);
-
- /* host controllers we manage */
-@@ -878,7 +878,7 @@ static void usb_deregister_bus (struct u
- * to register the usb device. It also assigns the root hub's USB address
- * (always 1).
- */
--static int register_root_hub(struct usb_hcd *hcd)
-+int register_root_hub(struct usb_hcd *hcd)
- {
- struct device *parent_dev = hcd->self.controller;
- struct usb_device *usb_dev = hcd->self.root_hub;
-@@ -923,6 +923,8 @@ static int register_root_hub(struct usb_
- return retval;
- }
-
-+EXPORT_SYMBOL(register_root_hub);
-+
-
- /*-------------------------------------------------------------------------*/
-
---- linux-2.6.30.9/drivers/usb/core/hub.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/core/hub.c 2013-05-02 01:47:56.731226815 +0300
-@@ -30,6 +30,13 @@
- #include "hcd.h"
- #include "hub.h"
-
-+//#include "rtl865xc_asicregs.h"
-+
-+#define REG32(reg) (*(volatile unsigned int *)((unsigned int)reg))
-+#define PABCD_DIR 0xb8003508
-+#define PABCD_DAT 0xb800350C
-+#define USB_LED_OFFSET 19
-+
- /* if we are in debug mode, always announce new devices */
- #ifdef DEBUG
- #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
-@@ -1432,8 +1439,12 @@ void usb_disconnect(struct usb_device **
- * this quiesces everyting except pending urbs.
- */
- usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-+ //RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) | (1 << EN_USB_LED)));
-+ REG32(PABCD_DIR) = REG32(PABCD_DIR) |(0x1<<USB_LED_OFFSET);
-+ REG32(PABCD_DAT) = REG32(PABCD_DAT) | (0x1<<USB_LED_OFFSET);
- dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
-
-+
- usb_lock_device(udev);
-
- /* Free up all the children before we remove this device */
-@@ -1775,14 +1786,21 @@ static unsigned hub_is_wusb(struct usb_h
- return hcd->wireless;
- }
-
--
-+#ifdef CONFIG_RTL_USB_OTG
- #define PORT_RESET_TRIES 5
-+#else
-+#define PORT_RESET_TRIES 20
-+#endif
- #define SET_ADDRESS_TRIES 2
- #define GET_DESCRIPTOR_TRIES 2
- #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
- #define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first)
-
-+#ifdef CONFIG_RTL_USB_OTG
- #define HUB_ROOT_RESET_TIME 50 /* times are in msec */
-+#else
-+#define HUB_ROOT_RESET_TIME 500 /* times are in msec */
-+#endif
- #define HUB_SHORT_RESET_TIME 10
- #define HUB_LONG_RESET_TIME 200
- #define HUB_RESET_TIMEOUT 500
-@@ -1842,8 +1859,13 @@ static int hub_port_wait_reset(struct us
- static int hub_port_reset(struct usb_hub *hub, int port1,
- struct usb_device *udev, unsigned int delay)
- {
-+#ifdef CONFIG_RTL_OTGCTRL
-+ //slove the usb phy debonce. close the auto-det interrupt
-+ extern unsigned int TurnOn_OTGCtrl_Interrupt(unsigned int); //wei add
-+ int old=TurnOn_OTGCtrl_Interrupt(0); //wei add
-+#endif
- int i, status;
--
-+ unsigned char retry=3; //realtek patch, if failed, retry 3 times
- /* Block EHCI CF initialization during the port reset.
- * Some companion controllers don't like it when they mix.
- */
-@@ -1868,12 +1890,19 @@ static int hub_port_reset(struct usb_hub
- /* return on disconnect or reset */
- switch (status) {
- case 0:
-+ retry = 0; //realtek patch
- /* TRSTRCY = 10 ms; plus some extra */
- msleep(10 + 40);
- update_address(udev, 0);
- /* FALL THROUGH */
- case -ENOTCONN:
- case -ENODEV:
-+//realtek patch
-+ if(retry){
-+ retry--;
-+ continue;
-+ }
-+////
- clear_port_feature(hub->hdev,
- port1, USB_PORT_FEAT_C_RESET);
- /* FIXME need disconnect() for NOTATTACHED device */
-@@ -1895,6 +1924,10 @@ static int hub_port_reset(struct usb_hub
-
- done:
- up_read(&ehci_cf_port_reset_rwsem);
-+
-+#ifdef CONFIG_RTL_OTGCTRL
-+ TurnOn_OTGCtrl_Interrupt(old); //wei add
-+#endif
- return status;
- }
-
-@@ -2152,15 +2185,31 @@ static int finish_port_resume(struct usb
- *
- * Returns 0 on success, else negative errno.
- */
-+ #define RTL_R32(addr) (*(volatile unsigned long *)(addr))
-+#define RTL_W32(addr, l) ((*(volatile unsigned long*)(addr)) = (l))
-+extern Enable_OTG_Suspend(int sel, int en) ;
- int usb_port_resume(struct usb_device *udev, pm_message_t msg)
- {
- struct usb_hub *hub = hdev_to_hub(udev->parent);
- int port1 = udev->portnum;
- int status;
- u16 portchange, portstatus;
--
-+ unsigned int tmp32=0;
- /* Skip the initial Clear-Suspend step for a remote wakeup */
- status = hub_port_status(hub, port1, &portstatus, &portchange);
-+#if defined(CONFIG_RTL_8196E) && defined(CONFIG_DWC_OTG)
-+ //Notify OTG Host to resume
-+ msleep(10);
-+ Enable_OTG_Suspend(0,0);
-+ msleep(10);
-+ tmp32 = 0x41100000;
-+ RTL_W32(0xB8030440, tmp32);
-+ msleep(10);
-+ tmp32 = 0x01100000;
-+ RTL_W32(0xB8030440, tmp32);
-+ msleep(10);
-+ /////////////////////////
-+#endif
- if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
- goto SuspendCleared;
-
-@@ -2451,6 +2500,13 @@ hub_port_init (struct usb_hub *hub, stru
- /* root hub ports have a slightly longer reset period
- * (from USB 2.0 spec, section 7.1.7.5)
- */
-+
-+ //RTL_W32(AUTOCFG_LED_DATABASE, (RTL_R32(AUTOCFG_LED_DATABASE) & 0xffffbfff));
-+
-+ REG32(PABCD_DIR) = REG32(PABCD_DIR) |(0x1<<USB_LED_OFFSET);
-+ REG32(PABCD_DAT) = REG32(PABCD_DAT) &(~ (0x1<<USB_LED_OFFSET));
-+
-+
- if (!hdev->parent) {
- delay = HUB_ROOT_RESET_TIME;
- if (port1 == hdev->bus->otg_port)
---- linux-2.6.30.9/drivers/usb/core/urb.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/core/urb.c 2013-05-02 01:47:56.735226815 +0300
-@@ -8,6 +8,12 @@
- #include <linux/wait.h>
- #include "hcd.h"
-
-+#include "bspchip.h"
-+
-+#ifndef __IRAM_USB
-+#define __IRAM_USB
-+#endif
-+
- #define to_urb(d) container_of(d, struct urb, kref)
-
-
-@@ -87,6 +93,7 @@ EXPORT_SYMBOL_GPL(usb_alloc_urb);
- * Note: The transfer buffer associated with the urb is not freed unless the
- * URB_FREE_BUFFER transfer flag is set.
- */
-+__IRAM_USB
- void usb_free_urb(struct urb *urb)
- {
- if (urb)
-@@ -104,6 +111,7 @@ EXPORT_SYMBOL_GPL(usb_free_urb);
- *
- * A pointer to the urb with the incremented reference counter is returned.
- */
-+__IRAM_USB
- struct urb *usb_get_urb(struct urb *urb)
- {
- if (urb)
-@@ -285,6 +293,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
- * GFP_NOIO, unless b) or c) apply
- *
- */
-+__IRAM_USB
- int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
- {
- int xfertype, max;
---- linux-2.6.30.9/drivers/usb/core/usb.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/core/usb.c 2013-05-02 01:47:56.736226814 +0300
-@@ -43,6 +43,10 @@
- #include "hcd.h"
- #include "usb.h"
-
-+#define REG32(reg) (*(volatile unsigned int *)((unsigned int)reg))
-+#define PIN_MUX_SEL_2 0xb8000044
-+#define PABCD_DIR 0xb8003508
-+#define PABCD_DAT 0xb800350C
-
- const char *usbcore_name = "usbcore";
-
-@@ -1001,6 +1005,16 @@ static struct notifier_block usb_bus_nb
- .notifier_call = usb_bus_notify,
- };
-
-+
-+static void usb_led_init(void)
-+{
-+ REG32(PIN_MUX_SEL_2) = REG32(PIN_MUX_SEL_2) |(0x7<<21);
-+ REG32(PABCD_DIR) = REG32(PABCD_DIR) |(0x1<<19);
-+ REG32(PABCD_DAT) = REG32(PABCD_DAT) |(0x1<<19);
-+}
-+
-+
-+
- /*
- * Init
- */
-@@ -1011,7 +1025,7 @@ static int __init usb_init(void)
- pr_info("%s: USB support disabled\n", usbcore_name);
- return 0;
- }
--
-+ usb_led_init();
- retval = ksuspend_usb_init();
- if (retval)
- goto out;
---- linux-2.6.30.9/drivers/usb/gadget/dummy_hcd.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/gadget/dummy_hcd.c 2013-05-02 01:47:56.782226811 +0300
-@@ -55,7 +55,11 @@
- #include <asm/unaligned.h>
-
-
-+#if defined(CONFIG_USB_UWIFI_HOST)
-+#include "../core_uWiFi/hcd.h"
-+#else
- #include "../core/hcd.h"
-+#endif
-
-
- #define DRIVER_DESC "USB Host+Gadget Emulator"
---- linux-2.6.30.9/drivers/usb/host/ehci.h 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ehci.h 2013-05-02 01:47:56.828226807 +0300
-@@ -36,6 +36,11 @@ typedef __u16 __bitwise __hc16;
- #define __hc32 __le32
- #define __hc16 __le16
- #endif
-+#include "bspchip.h"
-+
-+#ifndef __IRAM_USB
-+#define __IRAM_USB
-+#endif
-
- /* statistics can be kept for for tuning/monitoring */
- struct ehci_stats {
-@@ -602,6 +607,9 @@ ehci_port_speed(struct ehci_hcd *ehci, u
- static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
- __u32 __iomem * regs)
- {
-+#if defined(CONFIG_RTL_819X)
-+ return (le32_to_cpu((*(volatile unsigned long *)(regs))));
-+#else
- #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
- return ehci_big_endian_mmio(ehci) ?
- readl_be(regs) :
-@@ -609,11 +617,15 @@ static inline unsigned int ehci_readl(co
- #else
- return readl(regs);
- #endif
-+#endif
- }
-
- static inline void ehci_writel(const struct ehci_hcd *ehci,
- const unsigned int val, __u32 __iomem *regs)
- {
-+#if defined(CONFIG_RTL_819X)
-+ ((*(volatile unsigned long *)(regs))=cpu_to_le32(val));
-+#else
- #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
- ehci_big_endian_mmio(ehci) ?
- writel_be(val, regs) :
-@@ -621,6 +633,7 @@ static inline void ehci_writel(const str
- #else
- writel(val, regs);
- #endif
-+#endif
- }
-
- /*
---- linux-2.6.30.9/drivers/usb/host/ehci-hcd.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ehci-hcd.c 2013-05-02 01:47:56.825226807 +0300
-@@ -169,10 +169,10 @@ static int handshake (struct ehci_hcd *e
- u32 result;
-
- do {
-- result = ehci_readl(ehci, ptr);
-+ result = (ehci_readl(ehci, ptr))&0xffff;
- if (result == ~(u32)0) /* card removed */
- return -ENODEV;
-- result &= mask;
-+ result &= (mask)&0xffff;
- if (result == done)
- return 0;
- udelay (1);
-@@ -429,6 +429,7 @@ static void ehci_port_power (struct ehci
- * ehci_work is called from some interrupts, timers, and so on.
- * it calls driver completion functions, after dropping ehci->lock.
- */
-+__IRAM_USB
- static void ehci_work (struct ehci_hcd *ehci)
- {
- timer_action_done (ehci, TIMER_IO_WATCHDOG);
-@@ -677,7 +678,7 @@ static int ehci_run (struct usb_hcd *hcd
- }
-
- /*-------------------------------------------------------------------------*/
--
-+__IRAM_USB
- static irqreturn_t ehci_irq (struct usb_hcd *hcd)
- {
- struct ehci_hcd *ehci = hcd_to_ehci (hcd);
-@@ -786,7 +787,19 @@ dead:
- }
-
- if (bh)
-+ {
-+ #if 1
-+ __asm__ __volatile__( \
-+ ".set push\n\t" \
-+ ".set noreorder\n\t" \
-+ "nop\n\t" \
-+ "nop\n\t" \
-+ "nop\n\t" \
-+ ".set pop\n\t");
-+ #endif
-+
- ehci_work (ehci);
-+ }
- spin_unlock (&ehci->lock);
- if (pcd_status)
- usb_hcd_poll_rh_status(hcd);
-@@ -807,6 +820,7 @@ dead:
- * NOTE: control, bulk, and interrupt share the same code to append TDs
- * to a (possibly active) QH, and the same QH scanning code.
- */
-+__IRAM_USB
- static int ehci_urb_enqueue (
- struct usb_hcd *hcd,
- struct urb *urb,
-@@ -1040,48 +1054,35 @@ MODULE_DESCRIPTION(DRIVER_DESC);
- MODULE_AUTHOR (DRIVER_AUTHOR);
- MODULE_LICENSE ("GPL");
-
--#ifdef CONFIG_PCI
-+#ifdef CONFIG_USB_VIA_PCI
- #include "ehci-pci.c"
- #define PCI_DRIVER ehci_pci_driver
- #endif
-
--#ifdef CONFIG_USB_EHCI_FSL
--#include "ehci-fsl.c"
--#define PLATFORM_DRIVER ehci_fsl_driver
--#endif
--
--#ifdef CONFIG_SOC_AU1200
--#include "ehci-au1xxx.c"
--#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
--#endif
--
--#ifdef CONFIG_PPC_PS3
--#include "ehci-ps3.c"
--#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
--#endif
--
--#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
--#include "ehci-ppc-of.c"
--#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
--#endif
--
--#ifdef CONFIG_PLAT_ORION
--#include "ehci-orion.c"
--#define PLATFORM_DRIVER ehci_orion_driver
-+#if defined(CONFIG_RTL_819X)
-+#include "ehci-rtl8652.c"
-+#define PLATFORM_DRIVER ehci_rtl8652_driver
- #endif
-
--#ifdef CONFIG_ARCH_IXP4XX
--#include "ehci-ixp4xx.c"
--#define PLATFORM_DRIVER ixp4xx_ehci_driver
-+#ifdef CONFIG_USB_EHCI_DWC
-+#include "ehci-dwc.c"
-+#define PLATFORM_DRIVER ehci_dwc_driver
- #endif
-
--#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
-- !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
-+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
- #error "missing bus glue for ehci-hcd"
- #endif
-
-+#if defined(CONFIG_RTL_ULINKER)
-+int ehci_hcd_init(void)
-+#else
- static int __init ehci_hcd_init(void)
-+#endif
- {
-+ if (test_bit(USB_EHCI_LOADED, &usb_hcds_loaded))
-+ { printk("EHCI-HCD: already init \n");
-+ return -1;
-+ }
- int retval = 0;
-
- if (usb_disabled())
-@@ -1099,6 +1100,13 @@ static int __init ehci_hcd_init(void)
- sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
- sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
-
-+#if defined(CONFIG_RTL_819X)
-+ if(ehci_rtl8652_init() !=0)
-+ { retval = -1; //wei add
-+ goto err_out; //wei add
-+ }
-+#endif
-+
- #ifdef DEBUG
- ehci_debug_root = debugfs_create_dir("ehci", NULL);
- if (!ehci_debug_root) {
-@@ -1119,27 +1127,8 @@ static int __init ehci_hcd_init(void)
- goto clean1;
- #endif
-
--#ifdef PS3_SYSTEM_BUS_DRIVER
-- retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
-- if (retval < 0)
-- goto clean2;
--#endif
--
--#ifdef OF_PLATFORM_DRIVER
-- retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
-- if (retval < 0)
-- goto clean3;
--#endif
- return retval;
-
--#ifdef OF_PLATFORM_DRIVER
-- /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
--clean3:
--#endif
--#ifdef PS3_SYSTEM_BUS_DRIVER
-- ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
--clean2:
--#endif
- #ifdef PCI_DRIVER
- pci_unregister_driver(&PCI_DRIVER);
- clean1:
-@@ -1153,25 +1142,36 @@ clean0:
- ehci_debug_root = NULL;
- err_debug:
- #endif
-+err_out:
-+
-+#if defined(CONFIG_RTL_819X)
-+ ehci_rtl8652_cleanup(); //wei add
-+#endif
-+
- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- return retval;
- }
- module_init(ehci_hcd_init);
--
-+//-----------------------------------------------------------
-+#if defined(CONFIG_RTL_ULINKER)
-+void ehci_hcd_cleanup(void) //wei add
-+#else
- static void __exit ehci_hcd_cleanup(void)
--{
--#ifdef OF_PLATFORM_DRIVER
-- of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
--#endif
--#ifdef PLATFORM_DRIVER
-- platform_driver_unregister(&PLATFORM_DRIVER);
- #endif
-+{
-+ if (!test_bit(USB_EHCI_LOADED, &usb_hcds_loaded))
-+ { printk("EHCI-HCD: not init, cannot cleanup \n");
-+ return;
-+ }
-+
- #ifdef PCI_DRIVER
- pci_unregister_driver(&PCI_DRIVER);
- #endif
--#ifdef PS3_SYSTEM_BUS_DRIVER
-- ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
-+
-+#ifdef PLATFORM_DRIVER
-+ platform_driver_unregister(&PLATFORM_DRIVER);
- #endif
-+
- #ifdef DEBUG
- debugfs_remove(ehci_debug_root);
- #endif
-@@ -1175,6 +1175,10 @@ static void __exit ehci_hcd_cleanup(void
- #ifdef DEBUG
- debugfs_remove(ehci_debug_root);
- #endif
-+
-+#if defined(CONFIG_RTL_819X)
-+ ehci_rtl8652_cleanup(); //wei add
-+#endif
- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- }
- module_exit(ehci_hcd_cleanup);
---- linux-2.6.30.9/drivers/usb/host/ehci-hub.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ehci-hub.c 2013-05-02 01:47:56.825226807 +0300
-@@ -412,6 +412,16 @@ static int check_reset_complete (
- u32 __iomem *status_reg,
- int port_status
- ) {
-+//realtek patch
-+#if 1 /* patch for synopsis USB 2.0 */
-+ int i;
-+ #ifdef CONFIG_DWC_OTG
-+ static unsigned char retry=1; //if failed, retry 1 times
-+ #else
-+ static unsigned char retry=3; //if failed, retry 3 times
-+ #endif
-+#endif
-+////
- if (!(port_status & PORT_CONNECT))
- return port_status;
-
-@@ -425,7 +435,12 @@ static int check_reset_complete (
- index+1);
- return port_status;
- }
--
-+ //realtek patch
-+ if(--retry) {
-+ return port_status;
-+ }
-+ retry = 3;
-+ /////
- ehci_dbg (ehci, "port %d full speed --> companion\n",
- index + 1);
-
-@@ -438,6 +453,9 @@ static int check_reset_complete (
- if (ehci->has_amcc_usb23)
- set_ohci_hcfs(ehci, 1);
- } else {
-+ //realtek patch
-+ retry = 3; //realtek patch
-+ ////
- ehci_dbg (ehci, "port %d high speed\n", index + 1);
- /* ensure 440EPx ohci controller state is suspended */
- if (ehci->has_amcc_usb23)
---- linux-2.6.30.9/drivers/usb/host/ehci-q.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ehci-q.c 2013-05-02 01:47:56.827226807 +0300
-@@ -41,7 +41,7 @@
- /*-------------------------------------------------------------------------*/
-
- /* fill a qtd, returning how much of the buffer we were able to queue up */
--
-+__IRAM_USB
- static int
- qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
- size_t len, int token, int maxpacket)
-@@ -83,7 +83,7 @@ qtd_fill(struct ehci_hcd *ehci, struct e
- }
-
- /*-------------------------------------------------------------------------*/
--
-+__IRAM_USB
- static inline void
- qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
- {
-@@ -118,6 +118,7 @@ qh_update (struct ehci_hcd *ehci, struct
- * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
- * recovery (including urb dequeue) would need software changes to a QH...
- */
-+__IRAM_USB
- static void
- qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
- {
-@@ -138,7 +139,7 @@ qh_refresh (struct ehci_hcd *ehci, struc
- }
-
- /*-------------------------------------------------------------------------*/
--
-+__IRAM_USB
- static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
-
- static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
-@@ -187,7 +188,7 @@ static void ehci_clear_tt_buffer(struct
- }
- }
- }
--
-+__IRAM_USB
- static int qtd_copy_status (
- struct ehci_hcd *ehci,
- struct urb *urb,
-@@ -248,7 +249,7 @@ static int qtd_copy_status (
-
- return status;
- }
--
-+__IRAM_USB
- static void
- ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
- __releases(ehci->lock)
-@@ -570,6 +571,7 @@ static void qtd_list_free (
- /*
- * create a list of filled qtds for this URB; won't link into qh.
- */
-+__IRAM_USB
- static struct list_head *
- qh_urb_transaction (
- struct ehci_hcd *ehci,
-@@ -952,6 +954,7 @@ static void qh_link_async (struct ehci_h
- * Returns null if it can't allocate a QH it needs to.
- * If the QH has TDs (urbs) already, that's great.
- */
-+__IRAM_USB
- static struct ehci_qh *qh_append_tds (
- struct ehci_hcd *ehci,
- struct urb *urb,
-@@ -1033,6 +1036,7 @@ static struct ehci_qh *qh_append_tds (
-
- /*-------------------------------------------------------------------------*/
-
-+__IRAM_USB
- static int
- submit_async (
- struct ehci_hcd *ehci,
-@@ -1091,6 +1095,7 @@ submit_async (
-
- /* the async qh for the qtds being reclaimed are now unlinked from the HC */
-
-+__IRAM_USB
- static void end_unlink_async (struct ehci_hcd *ehci)
- {
- struct ehci_qh *qh = ehci->reclaim;
-@@ -1132,6 +1137,7 @@ static void end_unlink_async (struct ehc
- /* makes sure the async qh will become idle */
- /* caller must own ehci->lock */
-
-+__IRAM_USB
- static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
- {
- int cmd = ehci_readl(ehci, &ehci->regs->command);
-@@ -1189,6 +1195,7 @@ static void start_unlink_async (struct e
-
- /*-------------------------------------------------------------------------*/
-
-+__IRAM_USB
- static void scan_async (struct ehci_hcd *ehci)
- {
- struct ehci_qh *qh;
---- linux-2.6.30.9/drivers/usb/host/ehci-sched.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ehci-sched.c 2013-05-02 01:47:56.828226807 +0300
-@@ -33,7 +33,7 @@
- * It keeps track of every ITD (or SITD) that's linked, and holds enough
- * pre-calculated schedule data to make appending to the queue be quick.
- */
--
-+// #define CONFIG_USB_3G_SUPPORT //for specifical dongle
- static int ehci_get_frame (struct usb_hcd *hcd);
-
- /*-------------------------------------------------------------------------*/
-@@ -323,7 +323,11 @@ static int tt_available (
- * already scheduled transactions
- */
- if (125 < usecs) {
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ nt ufs = (usecs / 125) - 1;
-+#else
- int ufs = (usecs / 125);
-+#endif
- int i;
- for (i = uframe; i < (uframe + ufs) && i < 8; i++)
- if (0 < tt_usecs[i]) {
-@@ -436,15 +440,23 @@ static int enable_periodic (struct ehci_
- {
- u32 cmd;
- int status;
--
-+#ifndef CONFIG_USB_3G_SUPPORT
- if (ehci->periodic_sched++)
- return 0;
-+#else
-+ udelay(1024);
-+#endif
-
- /* did clearing PSE did take effect yet?
- * takes effect only at frame boundaries...
- */
- status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
-- STS_PSS, 0, 9 * 125);
-+ STS_PSS, 0,
-+ #ifdef CONFIG_USB_3G_SUPPORT
-+ 120000 * 125);
-+ #else
-+ 9 * 125);
-+ #endif
- if (status)
- return status;
-
-@@ -471,7 +483,12 @@ static int disable_periodic (struct ehci
- * takes effect only at frame boundaries...
- */
- status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
-- STS_PSS, STS_PSS, 9 * 125);
-+ STS_PSS, STS_PSS,
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ 120000 * 125);
-+#else
-+ 9 * 125);
-+#endif
- if (status)
- return status;
-
-@@ -550,7 +567,14 @@ static int qh_link_periodic (struct ehci
- : (qh->usecs * 8);
-
- /* maybe enable periodic schedule processing */
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ if (!ehci->periodic_sched++)
- return enable_periodic(ehci);
-+ return 0;
-+
-+#else
-+ return enable_periodic(ehci);
-+#endif
- }
-
- static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
-@@ -589,7 +613,14 @@ static int qh_unlink_periodic(struct ehc
- qh_put (qh);
-
- /* maybe turn off periodic schedule */
-+ #ifdef CONFIG_USB_3G_SUPPORT
-+ ehci->periodic_sched--;
-+ if (!ehci->periodic_sched)
-+ (void) disable_periodic (ehci);
-+
-+ #else
- return disable_periodic(ehci);
-+ #endif
- }
-
- static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
-@@ -606,9 +637,18 @@ static void intr_deschedule (struct ehci
- if (list_empty (&qh->qtd_list)
- || (cpu_to_hc32(ehci, QH_CMASK)
- & qh->hw_info2) != 0)
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ wait = 55;
-+#else
- wait = 2;
-+#endif
- else
-+#ifdef CONFIG_RTL_USB_OTG
- wait = 55; /* worst case: 3 * 1024 */
-+#else
-+ //wait = 55; /* worst case: 3 * 1024 */
-+ wait = 3 * 1024;
-+#endif
-
- udelay (wait);
- qh->qh_state = QH_STATE_IDLE;
-@@ -1564,7 +1604,13 @@ itd_link_urb (
- urb->hcpriv = NULL;
-
- timer_action (ehci, TIMER_IO_WATCHDOG);
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ if (unlikely (!ehci->periodic_sched++))
-+ return enable_periodic(ehci);
-+ return 0;
-+#else
- return enable_periodic(ehci);
-+#endif
- }
-
- #define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
-@@ -1645,7 +1691,14 @@ itd_complete (
- ehci_urb_done(ehci, urb, 0);
- retval = true;
- urb = NULL;
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ /* defer stopping schedule; completion can submit */
-+ ehci->periodic_sched--;
-+ if (unlikely (!ehci->periodic_sched))
-+
-+#else
- (void) disable_periodic(ehci);
-+#endif
- ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
-
- if (unlikely(list_is_singular(&stream->td_list))) {
-@@ -1967,7 +2020,13 @@ sitd_link_urb (
- urb->hcpriv = NULL;
-
- timer_action (ehci, TIMER_IO_WATCHDOG);
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ if (!ehci->periodic_sched++)
- return enable_periodic(ehci);
-+ return 0;
-+#else
-+ return enable_periodic(ehci);
-+#endif
- }
-
- /*-------------------------------------------------------------------------*/
-@@ -2034,6 +2093,11 @@ sitd_complete (
- ehci_urb_done(ehci, urb, 0);
- retval = true;
- urb = NULL;
-+#ifdef CONFIG_USB_3G_SUPPORT
-+ /* defer stopping schedule; completion can submit */
-+ ehci->periodic_sched--;
-+ if (!ehci->periodic_sched)
-+#endif
- (void) disable_periodic(ehci);
- ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
-
---- linux-2.6.30.9/drivers/usb/host/Kconfig 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/Kconfig 2013-05-02 01:47:56.823226807 +0300
-@@ -78,6 +78,12 @@ config USB_EHCI_BIG_ENDIAN_DESC
- depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX)
- default y
-
-+#config USB_EHCI_DWC
-+# bool "Support for Synopsys DWC EHCI USB controller"
-+# depends on USB_EHCI_HCD
-+# select USB_EHCI_ROOT_HUB_TT
-+# default y
-+
- config USB_EHCI_FSL
- bool "Support for Freescale on-chip EHCI USB controller"
- depends on USB_EHCI_HCD && FSL_SOC
-@@ -88,7 +94,6 @@ config USB_EHCI_FSL
- config USB_EHCI_HCD_PPC_OF
- bool "EHCI support for PPC USB controller on OF platform bus"
- depends on USB_EHCI_HCD && PPC_OF
-- default y
- ---help---
- Enables support for the USB controller present on the PowerPC
- OpenFirmware platform bus.
---- linux-2.6.30.9/drivers/usb/host/Makefile 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/Makefile 2013-05-02 01:47:56.823226807 +0300
-@@ -6,6 +6,9 @@ ifeq ($(CONFIG_USB_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
- endif
-
-+ifeq ($(CONFIG_RTL_819X),y)
-+ EXTRA_CFLAGS += -I$(DIR_BOARD)
-+endif
- isp1760-objs := isp1760-hcd.o isp1760-if.o
- fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
- fhci-tds.o fhci-sched.o
---- linux-2.6.30.9/drivers/usb/host/ohci.h 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ohci.h 2013-05-02 01:47:56.839226806 +0300
-@@ -544,6 +544,9 @@ static inline struct usb_hcd *ohci_to_hc
- static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
- __hc32 __iomem * regs)
- {
-+#if defined(CONFIG_RTL_819X)
-+ return (le32_to_cpu((*(volatile unsigned long *)(regs))));
-+#else
- #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
- return big_endian_mmio(ohci) ?
- readl_be (regs) :
-@@ -551,11 +554,15 @@ static inline unsigned int _ohci_readl (
- #else
- return readl (regs);
- #endif
-+#endif
- }
-
- static inline void _ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
- {
-+#if defined(CONFIG_RTL_819X)
-+ ((*(volatile unsigned long *)(regs))=cpu_to_le32(val));
-+#else
- #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
- big_endian_mmio(ohci) ?
- writel_be (val, regs) :
-@@ -563,6 +570,7 @@ static inline void _ohci_writel (const s
- #else
- writel (val, regs);
- #endif
-+#endif
- }
-
- #ifdef CONFIG_ARCH_LH7A404
---- linux-2.6.30.9/drivers/usb/host/ohci-hcd.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/host/ohci-hcd.c 2013-05-02 01:47:56.835226806 +0300
-@@ -1047,6 +1047,11 @@ MODULE_LICENSE ("GPL");
- #define PLATFORM_DRIVER usb_hcd_pnx4008_driver
- #endif
-
-+#if defined(CONFIG_RTL_819X)
-+#include "ohci-rtl8652.c"
-+#define PLATFORM_DRIVER ohci_hcd_rtl8652_driver
-+#endif
-+
- #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721) || \
- defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-@@ -1092,8 +1097,17 @@ MODULE_LICENSE ("GPL");
- #error "missing bus glue for ohci-hcd"
- #endif
-
-+#if defined(CONFIG_RTL_ULINKER)
-+int ohci_hcd_mod_init(void) //wei add
-+#else
- static int __init ohci_hcd_mod_init(void)
-+#endif
- {
-+ if ( test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
-+ { printk("OHCI-HCD: already init \n");
-+ return -1;
-+ }
-+
- int retval = 0;
-
- if (usb_disabled())
-@@ -1104,6 +1118,13 @@ static int __init ohci_hcd_mod_init(void
- sizeof (struct ed), sizeof (struct td));
- set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
-
-+#if defined(CONFIG_RTL_819X)
-+ if(ohci_rtl8652_init() !=0)
-+ { retval = -1; //wei add
-+ goto err_out; //wei add
-+ }
-+#endif
-+
- #ifdef DEBUG
- ohci_debug_root = debugfs_create_dir("ohci", NULL);
- if (!ohci_debug_root) {
-@@ -1200,14 +1221,26 @@ static int __init ohci_hcd_mod_init(void
- ohci_debug_root = NULL;
- error_debug:
- #endif
--
-+err_out:
-+#if defined(CONFIG_RTL_819X)
-+ ohci_rtl8652_cleanup(); //wei add
-+#endif
- clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
- return retval;
- }
- module_init(ohci_hcd_mod_init);
--
-+//-----------------------------------------------------------
-+#if defined(CONFIG_RTL_ULINKER)
-+void ohci_hcd_mod_exit(void) //wei add
-+#else
- static void __exit ohci_hcd_mod_exit(void)
-+#endif
- {
-+ if (!test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
-+ { printk("OHCI-HCD: not init, cannot cleanup \n");
-+ return;
-+ }
-+
- #ifdef TMIO_OHCI_DRIVER
- platform_driver_unregister(&TMIO_OHCI_DRIVER);
- #endif
-@@ -1235,6 +1268,10 @@ static void __exit ohci_hcd_mod_exit(voi
- #ifdef DEBUG
- debugfs_remove(ohci_debug_root);
- #endif
-+
-+#if defined(CONFIG_RTL_819X) //wei add
-+ ohci_rtl8652_cleanup();
-+#endif
- clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
- }
- module_exit(ohci_hcd_mod_exit);
---- linux-2.6.30.9/drivers/usb/Kconfig 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/Kconfig 2013-05-09 15:45:47.582603984 +0300
-@@ -19,45 +19,18 @@ config USB_ARCH_HAS_HCD
- boolean
- default y if USB_ARCH_HAS_OHCI
- default y if USB_ARCH_HAS_EHCI
-- default y if PCMCIA && !M32R # sl811_cs
-- default y if ARM # SL-811
-- default y if SUPERH # r8a66597-hcd
-- default PCI
-+ default y if RTL_819X
-+ default y if SOC_HAS_USB
-
- # many non-PCI SOC chips embed OHCI
- config USB_ARCH_HAS_OHCI
- boolean
-- # ARM:
-- default y if SA1111
-- default y if ARCH_OMAP
-- default y if ARCH_LH7A404
-- default y if ARCH_S3C2410
-- default y if PXA27x
-- default y if PXA3xx
-- default y if ARCH_EP93XX
-- default y if ARCH_AT91
-- default y if ARCH_PNX4008 && I2C
-- default y if MFD_TC6393XB
-- # PPC:
-- default y if STB03xxx
-- default y if PPC_MPC52xx
-- # MIPS:
-- default y if SOC_AU1X00
-- # SH:
-- default y if CPU_SUBTYPE_SH7720
-- default y if CPU_SUBTYPE_SH7721
-- default y if CPU_SUBTYPE_SH7763
-- default y if CPU_SUBTYPE_SH7786
-- # more:
-- default PCI
-+ default y if RTL_819X
-
- # some non-PCI hcds implement EHCI
- config USB_ARCH_HAS_EHCI
- boolean
-- default y if PPC_83xx
-- default y if SOC_AU1200
-- default y if ARCH_IXP4XX
-- default PCI
-+ default y if RTL_819X
-
- # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
- config USB
-@@ -149,8 +122,11 @@ source "drivers/usb/misc/Kconfig"
-
- source "drivers/usb/atm/Kconfig"
-
--source "drivers/usb/gadget/Kconfig"
-+source "drivers/usb/gadget_cathy/Kconfig"
-+#source "drivers/usb/gadget/Kconfig"
-
- source "drivers/usb/otg/Kconfig"
-
-+source "drivers/usb/dwc_otg/Kconfig"
-+
- endif # USB_SUPPORT
---- linux-2.6.30.9/drivers/usb/Makefile 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/Makefile 2013-05-02 01:47:56.716226816 +0300
-@@ -4,10 +4,27 @@
-
- # Object files in subdirectories
-
-+ifeq ($(CONFIG_USB_UWIFI_HOST),y)
-+obj-$(CONFIG_USB) += core_uWiFi/
-+else
- obj-$(CONFIG_USB) += core/
-+endif
-
- obj-$(CONFIG_USB_MON) += mon/
-
-+ifeq ($(CONFIG_USB_UWIFI_HOST),y)
-+obj-$(CONFIG_PCI) += host_uWiFi/
-+obj-$(CONFIG_USB_EHCI_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_ISP116X_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_OHCI_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_UHCI_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_FHCI_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_SL811_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_U132_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_R8A66597_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_HWA_HCD) += host_uWiFi/
-+obj-$(CONFIG_USB_ISP1760_HCD) += host_uWiFi/
-+else
- obj-$(CONFIG_PCI) += host/
- obj-$(CONFIG_USB_EHCI_HCD) += host/
- obj-$(CONFIG_USB_ISP116X_HCD) += host/
-@@ -19,6 +36,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
- obj-$(CONFIG_USB_R8A66597_HCD) += host/
- obj-$(CONFIG_USB_HWA_HCD) += host/
- obj-$(CONFIG_USB_ISP1760_HCD) += host/
-+endif
-
- obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
-
-@@ -29,9 +47,13 @@ obj-$(CONFIG_USB_PRINTER) += class/
- obj-$(CONFIG_USB_WDM) += class/
- obj-$(CONFIG_USB_TMC) += class/
-
-+ifeq ($(CONFIG_USB_UWIFI_HOST),y)
-+obj-$(CONFIG_USB_STORAGE) += storage_uWiFi/
-+obj-$(CONFIG_USB) += storage_uWiFi/
-+else
- obj-$(CONFIG_USB_STORAGE) += storage/
- obj-$(CONFIG_USB) += storage/
--
-+endif
- obj-$(CONFIG_USB_MDC800) += image/
- obj-$(CONFIG_USB_MICROTEK) += image/
-
-@@ -41,3 +63,12 @@ obj-$(CONFIG_USB) += misc/
-
- obj-$(CONFIG_USB_ATM) += atm/
- obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
-+
-+obj-$(CONFIG_DWC_OTG) += dwc_otg/
-+
-+#wei add for otg device mode
-+ifeq ($(CONFIG_RTL_USB_OTG),y)
-+obj-$(CONFIG_USB_GADGET) += gadget_cathy/
-+else
-+obj-$(CONFIG_USB_GADGET) += gadget/
-+endif
---- linux-2.6.30.9/drivers/usb/misc/ftdi-elan.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/misc/ftdi-elan.c 2013-05-02 01:47:56.875226803 +0300
-@@ -73,7 +73,12 @@ static struct list_head ftdi_static_list
- */
- #include "usb_u132.h"
- #include <asm/io.h>
-+
-+#if defined(CONFIG_USB_UWIFI_HOST)
-+#include "../core_uWiFi/hcd.h"
-+#else
- #include "../core/hcd.h"
-+#endif
-
- /* FIXME ohci.h is ONLY for internal use by the OHCI driver.
- * If you're going to try stuff like this, you need to split
---- linux-2.6.30.9/drivers/usb/misc/Kconfig 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/misc/Kconfig 2013-05-02 01:47:56.873226803 +0300
-@@ -255,4 +255,4 @@ config USB_VST
- To compile this driver as a module, choose M here: the
- module will be called vstusb.
-
--
-+#source "drivers/usb/misc/rts51xx/Kconfig"
---- linux-2.6.30.9/drivers/usb/misc/Makefile 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/misc/Makefile 2013-05-02 01:47:56.873226803 +0300
-@@ -26,6 +26,7 @@ obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
- obj-$(CONFIG_USB_VST) += vstusb.o
-
- obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
-+#obj-$(CONFIG_RTS5139) += rts51xx/
-
- ifeq ($(CONFIG_USB_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
---- linux-2.6.30.9/drivers/usb/mon/mon_main.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/mon/mon_main.c 2013-05-02 01:47:56.892226802 +0300
-@@ -13,7 +13,12 @@
- #include <linux/mutex.h>
-
- #include "usb_mon.h"
-+
-+#if defined(CONFIG_USB_UWIFI_HOST)
-+#include "../core_uWiFi/hcd.h"
-+#else
- #include "../core/hcd.h"
-+#endif
-
- static void mon_stop(struct mon_bus *mbus);
- static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
---- linux-2.6.30.9/drivers/usb/musb/musb_core.h 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/musb/musb_core.h 2013-05-02 01:47:56.895226802 +0300
-@@ -60,7 +60,12 @@ struct musb_ep;
- #include "musb_regs.h"
-
- #include "musb_gadget.h"
-+
-+#if defined(CONFIG_USB_UWIFI_HOST)
-+#include "../core_uWiFi/hcd.h"
-+#else
- #include "../core/hcd.h"
-+#endif
- #include "musb_host.h"
-
-
---- linux-2.6.30.9/drivers/usb/serial/option.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/serial/option.c 2013-05-02 01:47:56.919226800 +0300
-@@ -161,6 +161,7 @@ static int option_resume(struct usb_ser
- #define HUAWEI_PRODUCT_E143D 0x143D
- #define HUAWEI_PRODUCT_E143E 0x143E
- #define HUAWEI_PRODUCT_E143F 0x143F
-+#define HUAWEI_PRODUCT_K4505 0x1464
-
- #define QUANTA_VENDOR_ID 0x0408
- #define QUANTA_PRODUCT_Q101 0xEA02
-@@ -297,6 +298,8 @@ static int option_resume(struct usb_ser
- #define ZTE_PRODUCT_MF628 0x0015
- #define ZTE_PRODUCT_MF626 0x0031
- #define ZTE_PRODUCT_CDMA_TECH 0xfffe
-+#define ZTE_PRODUCT_AC8710 0xfff1
-+#define ZTE_PRODUCT_AC2726 0xfff5
-
- #define BENQ_VENDOR_ID 0x04a5
- #define BENQ_PRODUCT_H10 0x4068
-@@ -304,6 +307,19 @@ static int option_resume(struct usb_ser
- #define DLINK_VENDOR_ID 0x1186
- #define DLINK_PRODUCT_DWM_652 0x3e04
-
-+#define QISDA_VENDOR_ID 0x1da5
-+#define QISDA_PRODUCT_H21_4512 0x4512
-+#define QISDA_PRODUCT_H21_4523 0x4523
-+#define QISDA_PRODUCT_H20_4515 0x4515
-+#define QISDA_PRODUCT_H20_4519 0x4519
-+
-+/* SMPS PRODUCTS */
-+#define SMPS_VENDOR_ID 0xfeed
-+#define SMPS_PRODUCT_TITAN20 0x1234
-+
-+/* VIBO */
-+#define VIBO_VENDOR_ID 0x1c9e
-+#define VIBO_PRODUCT_D200 0x9605
-
- static struct usb_device_id option_ids[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
-@@ -522,7 +538,25 @@ static struct usb_device_id option_ids[]
- { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
- { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
- { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
-- { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
-+
-+ /* bruce: for qisda */
-+ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
-+ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
-+ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
-+ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
-+
-+ /* bruce: for ZTE */
-+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
-+
-+ /* mobilepeak */
-+ { USB_DEVICE_AND_INTERFACE_INFO(SMPS_VENDOR_ID, SMPS_PRODUCT_TITAN20, 0xff, 0xff, 0xff) },
-+
-+ /* Huawei*/
-+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
-+
-+ /* vibo */
-+ { USB_DEVICE(VIBO_VENDOR_ID, VIBO_PRODUCT_D200) },
-+
- { } /* Terminating entry */
- };
- MODULE_DEVICE_TABLE(usb, option_ids);
-@@ -833,8 +867,9 @@ static void option_instat_callback(struc
- dbg("%s: type %x req %x", __func__,
- req_pkt->bRequestType, req_pkt->bRequest);
- }
-- } else
-+ } else {/////TODO
- err("%s: error %d", __func__, status);
-+ }
-
- /* Resubmit urb so we continue receiving IRQ data */
- if (status != -ESHUTDOWN && status != -ENOENT) {
---- linux-2.6.30.9/drivers/usb/serial/usb-serial.c 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/serial/usb-serial.c 2013-05-02 01:47:56.923226799 +0300
-@@ -35,6 +35,10 @@
- #include <linux/usb/serial.h>
- #include "pl2303.h"
-
-+#if CONFIG_USB_SERIAL_OPTION
-+#include <linux/smp_lock.h> /* brucehou, 2010/05/21, for lock_kernel & unlock_kernel */
-+#endif
-+
- /*
- * Version Information
- */
---- linux-2.6.30.9/drivers/usb/storage/unusual_devs.h 2009-10-05 18:38:08.000000000 +0300
-+++ linux-2.6.30.9-rsdk/drivers/usb/storage/unusual_devs.h 2013-05-02 01:47:56.933226799 +0300
-@@ -1865,6 +1865,13 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0
- "Digital MP3 Audio Player",
- US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
-
-+/* brucehou@RTK for AMOI H01 */
-+UNUSUAL_DEV( 0x1614, 0x0800, 0x0000, 0x0000,
-+ "Amoi",
-+ "Mass Storage",
-+ US_SC_DEVICE, US_PR_DEVICE, option_ms_init,
-+ 0),
-+
- /* Control/Bulk transport for all SubClass values */
- USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
- USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
diff --git a/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-Kconfig.patch b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-Kconfig.patch
new file mode 100644
index 000000000..81f055498
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-Kconfig.patch
@@ -0,0 +1,52 @@
+--- linux-2.6.30.9/drivers/usb/Kconfig 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.30.9-rsdk/drivers/usb/Kconfig 2013-05-09 15:45:47.582603984 +0300
+@@ -19,45 +19,18 @@ config USB_ARCH_HAS_HCD
+ boolean
+ default y if USB_ARCH_HAS_OHCI
+ default y if USB_ARCH_HAS_EHCI
+- default y if PCMCIA && !M32R # sl811_cs
+- default y if ARM # SL-811
+- default y if SUPERH # r8a66597-hcd
+- default PCI
++ default y if RTL_819X
++ default y if SOC_HAS_USB
+
+ # many non-PCI SOC chips embed OHCI
+ config USB_ARCH_HAS_OHCI
+ boolean
+- # ARM:
+- default y if SA1111
+- default y if ARCH_OMAP
+- default y if ARCH_LH7A404
+- default y if ARCH_S3C2410
+- default y if PXA27x
+- default y if PXA3xx
+- default y if ARCH_EP93XX
+- default y if ARCH_AT91
+- default y if ARCH_PNX4008 && I2C
+- default y if MFD_TC6393XB
+- # PPC:
+- default y if STB03xxx
+- default y if PPC_MPC52xx
+- # MIPS:
+- default y if SOC_AU1X00
+- # SH:
+- default y if CPU_SUBTYPE_SH7720
+- default y if CPU_SUBTYPE_SH7721
+- default y if CPU_SUBTYPE_SH7763
+- default y if CPU_SUBTYPE_SH7786
+- # more:
+- default PCI
++ default y if RTL_819X
+
+ # some non-PCI hcds implement EHCI
+ config USB_ARCH_HAS_EHCI
+ boolean
+- default y if PPC_83xx
+- default y if SOC_AU1200
+- default y if ARCH_IXP4XX
+- default PCI
++ default y if RTL_819X
+
+ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+ config USB
diff --git a/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial-option.patch b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial-option.patch
new file mode 100644
index 000000000..c12798187
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial-option.patch
@@ -0,0 +1,77 @@
+--- linux-2.6.30.9/drivers/usb/serial/option.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.30.9-rsdk/drivers/usb/serial/option.c 2013-05-02 01:47:56.919226800 +0300
+@@ -161,6 +161,7 @@ static int option_resume(struct usb_ser
+ #define HUAWEI_PRODUCT_E143D 0x143D
+ #define HUAWEI_PRODUCT_E143E 0x143E
+ #define HUAWEI_PRODUCT_E143F 0x143F
++#define HUAWEI_PRODUCT_K4505 0x1464
+
+ #define QUANTA_VENDOR_ID 0x0408
+ #define QUANTA_PRODUCT_Q101 0xEA02
+@@ -297,6 +298,8 @@ static int option_resume(struct usb_ser
+ #define ZTE_PRODUCT_MF628 0x0015
+ #define ZTE_PRODUCT_MF626 0x0031
+ #define ZTE_PRODUCT_CDMA_TECH 0xfffe
++#define ZTE_PRODUCT_AC8710 0xfff1
++#define ZTE_PRODUCT_AC2726 0xfff5
+
+ #define BENQ_VENDOR_ID 0x04a5
+ #define BENQ_PRODUCT_H10 0x4068
+@@ -304,6 +307,19 @@ static int option_resume(struct usb_ser
+ #define DLINK_VENDOR_ID 0x1186
+ #define DLINK_PRODUCT_DWM_652 0x3e04
+
++#define QISDA_VENDOR_ID 0x1da5
++#define QISDA_PRODUCT_H21_4512 0x4512
++#define QISDA_PRODUCT_H21_4523 0x4523
++#define QISDA_PRODUCT_H20_4515 0x4515
++#define QISDA_PRODUCT_H20_4519 0x4519
++
++/* SMPS PRODUCTS */
++#define SMPS_VENDOR_ID 0xfeed
++#define SMPS_PRODUCT_TITAN20 0x1234
++
++/* VIBO */
++#define VIBO_VENDOR_ID 0x1c9e
++#define VIBO_PRODUCT_D200 0x9605
+
+ static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+@@ -522,7 +538,25 @@ static struct usb_device_id option_ids[]
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
+ { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
+ { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
+- { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
++
++ /* bruce: for qisda */
++ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
++ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
++ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
++ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
++
++ /* bruce: for ZTE */
++ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
++
++ /* mobilepeak */
++ { USB_DEVICE_AND_INTERFACE_INFO(SMPS_VENDOR_ID, SMPS_PRODUCT_TITAN20, 0xff, 0xff, 0xff) },
++
++ /* Huawei*/
++ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
++
++ /* vibo */
++ { USB_DEVICE(VIBO_VENDOR_ID, VIBO_PRODUCT_D200) },
++
+ { } /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(usb, option_ids);
+@@ -833,8 +867,9 @@ static void option_instat_callback(struc
+ dbg("%s: type %x req %x", __func__,
+ req_pkt->bRequestType, req_pkt->bRequest);
+ }
+- } else
++ } else {/////TODO
+ err("%s: error %d", __func__, status);
++ }
+
+ /* Resubmit urb so we continue receiving IRQ data */
+ if (status != -ESHUTDOWN && status != -ENOENT) {
diff --git a/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial.patch b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial.patch
new file mode 100644
index 000000000..6ab40e6d5
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/0002-rsdk-drivers-usb-serial.patch
@@ -0,0 +1,11 @@
+--- linux-2.6.30.9/drivers/usb/serial/usb-serial.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.30.9-rsdk/drivers/usb/serial/usb-serial.c 2013-05-02 01:47:56.923226799 +0300
+@@ -35,6 +35,8 @@
+ #include <linux/usb/serial.h>
+ #include "pl2303.h"
+
++#include <linux/smp_lock.h> /* brucehou, 2010/05/21, for lock_kernel & unlock_kernel */
++
+ /*
+ * Version Information
+ */
diff --git a/target/linux/realtek/patches-2.6.30/003-include-paths.diff b/target/linux/realtek/patches-2.6.30/003-include-paths.diff
index 341cbe8f2..e63b53b12 100644
--- a/target/linux/realtek/patches-2.6.30/003-include-paths.diff
+++ b/target/linux/realtek/patches-2.6.30/003-include-paths.diff
@@ -1,13 +1,3 @@
-commit 82b68e4028feb70c7c6d6f2c380f342945a6b7f7
-Author: Roman Yeryomin <roman@advem.lv>
-Date: Tue Feb 5 01:40:38 2013 +0200
-
- adopt 003-include-paths.diff
-
- Signed-off-by: Roman Yeryomin <roman@advem.lv>
-
-diff --git a/drivers/net/rtl819x/Makefile b/drivers/net/rtl819x/Makefile
-index 7a08142..cfd0152 100644
--- a/drivers/net/rtl819x/Makefile
+++ b/drivers/net/rtl819x/Makefile
@@ -11,7 +11,7 @@
@@ -19,17 +9,3 @@ index 7a08142..cfd0152 100644
#obj-y := rtl_glue.o
#Add mips16 Support
-diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
-index 9e62ed1..19afd87 100644
---- a/drivers/usb/host/Makefile
-+++ b/drivers/usb/host/Makefile
-@@ -9,6 +9,9 @@ endif
- ifeq ($(CONFIG_RTL_819X),y)
- EXTRA_CFLAGS += -I$(DIR_BOARD)
- endif
-+
-+EXTRA_CFLAGS += -I$(TOPDIR)/arch/rlx
-+
- isp1760-objs := isp1760-hcd.o isp1760-if.o
- fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
- fhci-tds.o fhci-sched.o
diff --git a/target/linux/realtek/patches-2.6.30/114-rlx_819x_usb.patch b/target/linux/realtek/patches-2.6.30/114-rlx_819x_usb.patch
new file mode 100644
index 000000000..8bc1f0096
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/114-rlx_819x_usb.patch
@@ -0,0 +1,100 @@
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -1142,6 +1142,11 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER ehci_atmel_driver
+ #endif
+
++#ifdef CONFIG_RTL_819X
++#include "ehci-rtl819x.c"
++#define PLATFORM_DRIVER ehci_rtl819x_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
+ #error "missing bus glue for ehci-hcd"
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -1085,6 +1085,11 @@ MODULE_LICENSE ("GPL");
+ #define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver
+ #endif
+
++#ifdef CONFIG_RTL_819X
++#include "ohci-rtl819x.c"
++#define PLATFORM_DRIVER ohci_hcd_rtl819x_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OF_PLATFORM_DRIVER) && \
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -611,6 +611,9 @@ ehci_port_speed(struct ehci_hcd *ehci, u
+ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
+ __u32 __iomem * regs)
+ {
++#if defined(CONFIG_RTL_819X)
++ return (le32_to_cpu((*(volatile unsigned long *)(regs))));
++#else
+ #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ return ehci_big_endian_mmio(ehci) ?
+ readl_be(regs) :
+@@ -618,11 +621,15 @@ static inline unsigned int ehci_readl(co
+ #else
+ return readl(regs);
+ #endif
++#endif
+ }
+
+ static inline void ehci_writel(const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
+ {
++#if defined(CONFIG_RTL_819X)
++ ((*(volatile unsigned long *)(regs))=cpu_to_le32(val));
++#else
+ #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci_big_endian_mmio(ehci) ?
+ writel_be(val, regs) :
+@@ -630,6 +637,7 @@ static inline void ehci_writel(const str
+ #else
+ writel(val, regs);
+ #endif
++#endif
+ }
+
+ /*
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -553,6 +553,9 @@ static inline struct usb_hcd *ohci_to_hc
+ static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+ __hc32 __iomem * regs)
+ {
++#if defined(CONFIG_RTL_819X)
++ return (le32_to_cpu((*(volatile unsigned long *)(regs))));
++#else
+ #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ return big_endian_mmio(ohci) ?
+ readl_be (regs) :
+@@ -560,11 +563,15 @@ static inline unsigned int _ohci_readl (
+ #else
+ return readl (regs);
+ #endif
++#endif
+ }
+
+ static inline void _ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
+ {
++#if defined(CONFIG_RTL_819X)
++ ((*(volatile unsigned long *)(regs))=cpu_to_le32(val));
++#else
+ #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ big_endian_mmio(ohci) ?
+ writel_be (val, regs) :
+@@ -572,6 +579,7 @@ static inline void _ohci_writel (const s
+ #else
+ writel (val, regs);
+ #endif
++#endif
+ }
+
+ #ifdef CONFIG_ARCH_LH7A404
diff --git a/target/linux/realtek/patches-2.6.30/2.6.30-to-32-usb.patch b/target/linux/realtek/patches-2.6.30/2.6.30-to-32-usb.patch
new file mode 100644
index 000000000..e532924f6
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/2.6.30-to-32-usb.patch
@@ -0,0 +1,2840 @@
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci.h linux-2.6.32.27/drivers/usb/host/ehci.h
+--- linux-2.6.30.9/drivers/usb/host/ehci.h 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci.h 2010-12-09 23:29:45.000000000 +0200
+@@ -37,7 +37,7 @@
+ #define __hc16 __le16
+ #endif
+
+-/* statistics can be kept for for tuning/monitoring */
++/* statistics can be kept for tuning/monitoring */
+ struct ehci_stats {
+ /* irq usage */
+ unsigned long normal;
+@@ -87,8 +87,9 @@
+ int next_uframe; /* scan periodic, start here */
+ unsigned periodic_sched; /* periodic activity count */
+
+- /* list of itds completed while clock_frame was still active */
++ /* list of itds & sitds completed while clock_frame was still active */
+ struct list_head cached_itd_list;
++ struct list_head cached_sitd_list;
+ unsigned clock_frame;
+
+ /* per root hub port */
+@@ -116,7 +117,9 @@
+ struct timer_list watchdog;
+ unsigned long actions;
+ unsigned stamp;
++ unsigned random_frame;
+ unsigned long next_statechange;
++ ktime_t last_periodic_enable;
+ u32 command;
+
+ /* SILICON QUIRKS */
+@@ -125,6 +128,8 @@
+ unsigned big_endian_mmio:1;
+ unsigned big_endian_desc:1;
+ unsigned has_amcc_usb23:1;
++ unsigned need_io_watchdog:1;
++ unsigned broken_periodic:1;
+
+ /* required for usb32 quirk */
+ #define OHCI_CTRL_HCFS (3 << 6)
+@@ -134,6 +139,7 @@
+ #define OHCI_HCCTRL_OFFSET 0x4
+ #define OHCI_HCCTRL_LEN 0x4
+ __hc32 *ohci_hcctrl_reg;
++ unsigned has_hostpc:1;
+
+ u8 sbrn; /* packed release number */
+
+@@ -190,7 +196,7 @@
+ clear_bit (action, &ehci->actions);
+ }
+
+-static void free_cached_itd_list(struct ehci_hcd *ehci);
++static void free_cached_lists(struct ehci_hcd *ehci);
+
+ /*-------------------------------------------------------------------------*/
+
+@@ -297,8 +303,8 @@
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+-struct ehci_qh {
+- /* first part defined by EHCI spec */
++/* first part defined by EHCI spec */
++struct ehci_qh_hw {
+ __hc32 hw_next; /* see EHCI 3.6.1 */
+ __hc32 hw_info1; /* see EHCI 3.6.2 */
+ #define QH_HEAD 0x00008000
+@@ -316,7 +322,10 @@
+ __hc32 hw_token;
+ __hc32 hw_buf [5];
+ __hc32 hw_buf_hi [5];
++} __attribute__ ((aligned(32)));
+
++struct ehci_qh {
++ struct ehci_qh_hw *hw;
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ union ehci_shadow qh_next; /* ptr to qh; or periodic */
+@@ -335,6 +344,7 @@
+ u32 refcount;
+ unsigned stamp;
+
++ u8 needs_rescan; /* Dequeue during giveback */
+ u8 qh_state;
+ #define QH_STATE_LINKED 1 /* HC sees this */
+ #define QH_STATE_UNLINK 2 /* HC may still see this */
+@@ -356,7 +366,7 @@
+
+ struct usb_device *dev; /* access to TT */
+ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
+-} __attribute__ ((aligned (32)));
++};
+
+ /*-------------------------------------------------------------------------*/
+
+@@ -385,9 +395,8 @@
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+ struct ehci_iso_stream {
+- /* first two fields match QH, but info1 == 0 */
+- __hc32 hw_next;
+- __hc32 hw_info1;
++ /* first field matches ehci_hq, but is NULL */
++ struct ehci_qh_hw *hw;
+
+ u32 refcount;
+ u8 bEndpointAddress;
+@@ -543,7 +552,7 @@
+ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ {
+ if (ehci_is_TDI(ehci)) {
+- switch ((portsc>>26)&3) {
++ switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
+ case 0:
+ return 0;
+ case 1:
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-hcd.c linux-2.6.32.27/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-hcd.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-hcd.c 2010-12-09 23:29:45.000000000 +0200
+@@ -28,9 +28,9 @@
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/timer.h>
++#include <linux/ktime.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+-#include <linux/reboot.h>
+ #include <linux/usb.h>
+ #include <linux/moduleparam.h>
+ #include <linux/dma-mapping.h>
+@@ -127,6 +127,8 @@
+
+ switch (action) {
+ case TIMER_IO_WATCHDOG:
++ if (!ehci->need_io_watchdog)
++ return;
+ t = EHCI_IO_JIFFIES;
+ break;
+ case TIMER_ASYNC_OFF:
+@@ -239,6 +241,11 @@
+ int retval;
+ u32 command = ehci_readl(ehci, &ehci->regs->command);
+
++ /* If the EHCI debug controller is active, special care must be
++ * taken before and after a host controller reset */
++ if (ehci->debug && !dbgp_reset_prep())
++ ehci->debug = NULL;
++
+ command |= CMD_RESET;
+ dbg_cmd (ehci, "reset", command);
+ ehci_writel(ehci, command, &ehci->regs->command);
+@@ -247,12 +254,21 @@
+ retval = handshake (ehci, &ehci->regs->command,
+ CMD_RESET, 0, 250 * 1000);
+
++ if (ehci->has_hostpc) {
++ ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
++ (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
++ ehci_writel(ehci, TXFIFO_DEFAULT,
++ (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
++ }
+ if (retval)
+ return retval;
+
+ if (ehci_is_TDI(ehci))
+ tdi_reset (ehci);
+
++ if (ehci->debug)
++ dbgp_external_startup();
++
+ return retval;
+ }
+
+@@ -505,9 +521,14 @@
+ u32 temp;
+ int retval;
+ u32 hcc_params;
++ struct ehci_qh_hw *hw;
+
+ spin_lock_init(&ehci->lock);
+
++ /*
++ * keep io watchdog by default, those good HCDs could turn off it later
++ */
++ ehci->need_io_watchdog = 1;
+ init_timer(&ehci->watchdog);
+ ehci->watchdog.function = ehci_watchdog;
+ ehci->watchdog.data = (unsigned long) ehci;
+@@ -522,6 +543,7 @@
+ */
+ ehci->periodic_size = DEFAULT_I_TDPS;
+ INIT_LIST_HEAD(&ehci->cached_itd_list);
++ INIT_LIST_HEAD(&ehci->cached_sitd_list);
+ if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
+ return retval;
+
+@@ -544,12 +566,13 @@
+ * from automatically advancing to the next td after short reads.
+ */
+ ehci->async->qh_next.qh = NULL;
+- ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
+- ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+- ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
+- ehci->async->hw_qtd_next = EHCI_LIST_END(ehci);
++ hw = ehci->async->hw;
++ hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
++ hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
++ hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
++ hw->hw_qtd_next = EHCI_LIST_END(ehci);
+ ehci->async->qh_state = QH_STATE_LINKED;
+- ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
++ hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
+
+ /* clear interrupt enables, set irq latency */
+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+@@ -655,6 +678,7 @@
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ msleep(5);
+ up_write(&ehci_cf_port_reset_rwsem);
++ ehci->last_periodic_enable = ktime_get_real();
+
+ temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci_info (ehci,
+@@ -762,9 +786,10 @@
+
+ /* start 20 msec resume signaling from this port,
+ * and make khubd collect PORT_STAT_C_SUSPEND to
+- * stop that signaling.
++ * stop that signaling. Use 5 ms extra for safety,
++ * like usb_port_resume() does.
+ */
+- ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
++ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
+ ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
+ mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
+ }
+@@ -850,12 +875,18 @@
+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
+ end_unlink_async(ehci);
+
+- /* if it's not linked then there's nothing to do */
+- if (qh->qh_state != QH_STATE_LINKED)
+- ;
++ /* If the QH isn't linked then there's nothing we can do
++ * unless we were called during a giveback, in which case
++ * qh_completions() has to deal with it.
++ */
++ if (qh->qh_state != QH_STATE_LINKED) {
++ if (qh->qh_state == QH_STATE_COMPLETING)
++ qh->needs_rescan = 1;
++ return;
++ }
+
+ /* defer till later if busy */
+- else if (ehci->reclaim) {
++ if (ehci->reclaim) {
+ struct ehci_qh *last;
+
+ for (last = ehci->reclaim;
+@@ -915,8 +946,9 @@
+ break;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
++ case QH_STATE_COMPLETING:
+ intr_deschedule (ehci, qh);
+- /* FALL THROUGH */
++ break;
+ case QH_STATE_IDLE:
+ qh_completions (ehci, qh);
+ break;
+@@ -925,23 +957,6 @@
+ qh, qh->qh_state);
+ goto done;
+ }
+-
+- /* reschedule QH iff another request is queued */
+- if (!list_empty (&qh->qtd_list)
+- && HC_IS_RUNNING (hcd->state)) {
+- rc = qh_schedule(ehci, qh);
+-
+- /* An error here likely indicates handshake failure
+- * or no space left in the schedule. Neither fault
+- * should happen often ...
+- *
+- * FIXME kill the now-dysfunctional queued urbs
+- */
+- if (rc != 0)
+- ehci_err(ehci,
+- "can't reschedule qh %p, err %d",
+- qh, rc);
+- }
+ break;
+
+ case PIPE_ISOCHRONOUS:
+@@ -979,7 +994,7 @@
+ /* endpoints can be iso streams. for now, we don't
+ * accelerate iso completions ... so spin a while.
+ */
+- if (qh->hw_info1 == 0) {
++ if (qh->hw == NULL) {
+ ehci_vdbg (ehci, "iso delay\n");
+ goto idle_timeout;
+ }
+@@ -988,14 +1003,16 @@
+ qh->qh_state = QH_STATE_IDLE;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
++ case QH_STATE_COMPLETING:
+ for (tmp = ehci->async->qh_next.qh;
+ tmp && tmp != qh;
+ tmp = tmp->qh_next.qh)
+ continue;
+- /* periodic qh self-unlinks on empty */
+- if (!tmp)
+- goto nogood;
+- unlink_async (ehci, qh);
++ /* periodic qh self-unlinks on empty, and a COMPLETING qh
++ * may already be unlinked.
++ */
++ if (tmp)
++ unlink_async(ehci, qh);
+ /* FALL THROUGH */
+ case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
+@@ -1012,7 +1029,6 @@
+ }
+ /* else FALL THROUGH */
+ default:
+-nogood:
+ /* caller was supposed to have unlinked any requests;
+ * that's not our job. just leak this memory.
+ */
+@@ -1027,6 +1043,47 @@
+ return;
+ }
+
++static void
++ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ struct ehci_qh *qh;
++ int eptype = usb_endpoint_type(&ep->desc);
++ int epnum = usb_endpoint_num(&ep->desc);
++ int is_out = usb_endpoint_dir_out(&ep->desc);
++ unsigned long flags;
++
++ if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
++ return;
++
++ spin_lock_irqsave(&ehci->lock, flags);
++ qh = ep->hcpriv;
++
++ /* For Bulk and Interrupt endpoints we maintain the toggle state
++ * in the hardware; the toggle bits in udev aren't used at all.
++ * When an endpoint is reset by usb_clear_halt() we must reset
++ * the toggle bit in the QH.
++ */
++ if (qh) {
++ usb_settoggle(qh->dev, epnum, is_out, 0);
++ if (!list_empty(&qh->qtd_list)) {
++ WARN_ONCE(1, "clear_halt for a busy endpoint\n");
++ } else if (qh->qh_state == QH_STATE_LINKED ||
++ qh->qh_state == QH_STATE_COMPLETING) {
++
++ /* The toggle value in the QH can't be updated
++ * while the QH is active. Unlink it now;
++ * re-linking will call qh_refresh().
++ */
++ if (eptype == USB_ENDPOINT_XFER_BULK)
++ unlink_async(ehci, qh);
++ else
++ intr_deschedule(ehci, qh);
++ }
++ }
++ spin_unlock_irqrestore(&ehci->lock, flags);
++}
++
+ static int ehci_get_frame (struct usb_hcd *hcd)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+@@ -1075,6 +1132,16 @@
+ #define PLATFORM_DRIVER ixp4xx_ehci_driver
+ #endif
+
++#ifdef CONFIG_USB_W90X900_EHCI
++#include "ehci-w90x900.c"
++#define PLATFORM_DRIVER ehci_hcd_w90x900_driver
++#endif
++
++#ifdef CONFIG_ARCH_AT91
++#include "ehci-atmel.c"
++#define PLATFORM_DRIVER ehci_atmel_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
+ #error "missing bus glue for ehci-hcd"
+@@ -1100,7 +1167,7 @@
+ sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+
+ #ifdef DEBUG
+- ehci_debug_root = debugfs_create_dir("ehci", NULL);
++ ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
+ if (!ehci_debug_root) {
+ retval = -ENOENT;
+ goto err_debug;
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-hub.c linux-2.6.32.27/drivers/usb/host/ehci-hub.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-hub.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-hub.c 2010-12-09 23:29:45.000000000 +0200
+@@ -111,6 +111,7 @@
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ int port;
+ int mask;
++ u32 __iomem *hostpc_reg = NULL;
+
+ ehci_dbg(ehci, "suspend root hub\n");
+
+@@ -119,9 +120,26 @@
+ del_timer_sync(&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);
+
+- port = HCS_N_PORTS (ehci->hcs_params);
+ spin_lock_irq (&ehci->lock);
+
++ /* Once the controller is stopped, port resumes that are already
++ * in progress won't complete. Hence if remote wakeup is enabled
++ * for the root hub and any ports are in the middle of a resume or
++ * remote wakeup, we must fail the suspend.
++ */
++ if (hcd->self.root_hub->do_remote_wakeup) {
++ port = HCS_N_PORTS(ehci->hcs_params);
++ while (port--) {
++ if (ehci->reset_done[port] != 0) {
++ spin_unlock_irq(&ehci->lock);
++ ehci_dbg(ehci, "suspend failed because "
++ "port %d is resuming\n",
++ port + 1);
++ return -EBUSY;
++ }
++ }
++ }
++
+ /* stop schedules, clean any completed work */
+ if (HC_IS_RUNNING(hcd->state)) {
+ ehci_quiesce (ehci);
+@@ -137,11 +155,15 @@
+ */
+ ehci->bus_suspended = 0;
+ ehci->owned_ports = 0;
++ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ u32 __iomem *reg = &ehci->regs->port_status [port];
+ u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+ u32 t2 = t1;
+
++ if (ehci->has_hostpc)
++ hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
++ + HOSTPC0 + 4 * (port & 0xff));
+ /* keep track of which ports we suspend */
+ if (t1 & PORT_OWNER)
+ set_bit(port, &ehci->owned_ports);
+@@ -151,15 +173,37 @@
+ }
+
+ /* enable remote wakeup on all ports */
+- if (hcd->self.root_hub->do_remote_wakeup)
+- t2 |= PORT_WAKE_BITS;
+- else
++ if (hcd->self.root_hub->do_remote_wakeup) {
++ /* only enable appropriate wake bits, otherwise the
++ * hardware can not go phy low power mode. If a race
++ * condition happens here(connection change during bits
++ * set), the port change detection will finally fix it.
++ */
++ if (t1 & PORT_CONNECT) {
++ t2 |= PORT_WKOC_E | PORT_WKDISC_E;
++ t2 &= ~PORT_WKCONN_E;
++ } else {
++ t2 |= PORT_WKOC_E | PORT_WKCONN_E;
++ t2 &= ~PORT_WKDISC_E;
++ }
++ } else
+ t2 &= ~PORT_WAKE_BITS;
+
+ if (t1 != t2) {
+ ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
+ port + 1, t1, t2);
+ ehci_writel(ehci, t2, reg);
++ if (hostpc_reg) {
++ u32 t3;
++
++ msleep(5);/* 5ms for HCD enter low pwr mode */
++ t3 = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
++ t3 = ehci_readl(ehci, hostpc_reg);
++ ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
++ port, (t3 & HOSTPC_PHCD) ?
++ "succeeded" : "failed");
++ }
+ }
+ }
+
+@@ -183,6 +227,11 @@
+
+ ehci->next_statechange = jiffies + msecs_to_jiffies(10);
+ spin_unlock_irq (&ehci->lock);
++
++ /* ehci_work() may have re-enabled the watchdog timer, which we do not
++ * want, and so we must delete any pending watchdog timer events.
++ */
++ del_timer_sync(&ehci->watchdog);
+ return 0;
+ }
+
+@@ -204,6 +253,13 @@
+ return -ESHUTDOWN;
+ }
+
++ if (unlikely(ehci->debug)) {
++ if (ehci->debug && !dbgp_reset_prep())
++ ehci->debug = NULL;
++ else
++ dbgp_external_startup();
++ }
++
+ /* Ideally and we've got a real resume here, and no port's power
+ * was lost. (For PCI, that means Vaux was maintained.) But we
+ * could instead be restoring a swsusp snapshot -- so that BIOS was
+@@ -236,6 +292,16 @@
+ /* manually resume the ports we suspended during bus_suspend() */
+ i = HCS_N_PORTS (ehci->hcs_params);
+ while (i--) {
++ /* clear phy low power mode before resume */
++ if (ehci->has_hostpc) {
++ u32 __iomem *hostpc_reg =
++ (u32 __iomem *)((u8 *)ehci->regs
++ + HOSTPC0 + 4 * (i & 0xff));
++ temp = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, temp & ~HOSTPC_PHCD,
++ hostpc_reg);
++ mdelay(5);
++ }
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ if (test_bit(i, &ehci->bus_suspended) &&
+@@ -391,7 +457,7 @@
+
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+- i = device_create_file(ehci_to_hcd(ehci)->self.dev,
++ i = device_create_file(ehci_to_hcd(ehci)->self.controller,
+ &dev_attr_companion);
+ }
+
+@@ -399,7 +465,7 @@
+ {
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+- device_remove_file(ehci_to_hcd(ehci)->self.dev,
++ device_remove_file(ehci_to_hcd(ehci)->self.controller,
+ &dev_attr_companion);
+ }
+
+@@ -563,7 +629,8 @@
+ int ports = HCS_N_PORTS (ehci->hcs_params);
+ u32 __iomem *status_reg = &ehci->regs->port_status[
+ (wIndex & 0xff) - 1];
+- u32 temp, status;
++ u32 __iomem *hostpc_reg = NULL;
++ u32 temp, temp1, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+@@ -575,6 +642,9 @@
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
++ if (ehci->has_hostpc)
++ hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
++ + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
+ spin_lock_irqsave (&ehci->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+@@ -616,6 +686,13 @@
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
++ /* clear phy low power mode before resume */
++ if (hostpc_reg) {
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
++ hostpc_reg);
++ mdelay(5);
++ }
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ ehci_writel(ehci, temp | PORT_RESUME,
+@@ -773,7 +850,11 @@
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ // status may be from integrated TT
+- status |= ehci_port_speed(ehci, temp);
++ if (ehci->has_hostpc) {
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ status |= ehci_port_speed(ehci, temp1);
++ } else
++ status |= ehci_port_speed(ehci, temp);
+ }
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+@@ -816,6 +897,15 @@
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
++ if (unlikely(ehci->debug)) {
++ /* If the debug port is active any port
++ * feature requests should get denied */
++ if (wIndex == HCS_DEBUG_PORT(ehci->hcs_params) &&
++ (readl(&ehci->debug->control) & DBGP_ENABLED)) {
++ retval = -ENODEV;
++ goto error_exit;
++ }
++ }
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+@@ -832,6 +922,24 @@
+ || (temp & PORT_RESET) != 0)
+ goto error;
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
++ /* After above check the port must be connected.
++ * Set appropriate bit thus could put phy into low power
++ * mode if we have hostpc feature
++ */
++ if (hostpc_reg) {
++ temp &= ~PORT_WKCONN_E;
++ temp |= (PORT_WKDISC_E | PORT_WKOC_E);
++ ehci_writel(ehci, temp | PORT_SUSPEND,
++ status_reg);
++ msleep(5);/* 5ms for HCD enter low pwr mode */
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, temp1 | HOSTPC_PHCD,
++ hostpc_reg);
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
++ wIndex, (temp1 & HOSTPC_PHCD) ?
++ "succeeded" : "failed");
++ }
+ set_bit(wIndex, &ehci->suspended_ports);
+ break;
+ case USB_PORT_FEAT_POWER:
+@@ -894,6 +1002,7 @@
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
++error_exit:
+ spin_unlock_irqrestore (&ehci->lock, flags);
+ return retval;
+ }
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-mem.c linux-2.6.32.27/drivers/usb/host/ehci-mem.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-mem.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-mem.c 2010-12-09 23:29:45.000000000 +0200
+@@ -75,7 +75,8 @@
+ }
+ if (qh->dummy)
+ ehci_qtd_free (ehci, qh->dummy);
+- dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
++ dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
++ kfree(qh);
+ }
+
+ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
+@@ -83,12 +84,14 @@
+ struct ehci_qh *qh;
+ dma_addr_t dma;
+
+- qh = (struct ehci_qh *)
+- dma_pool_alloc (ehci->qh_pool, flags, &dma);
++ qh = kzalloc(sizeof *qh, GFP_ATOMIC);
+ if (!qh)
+- return qh;
+-
+- memset (qh, 0, sizeof *qh);
++ goto done;
++ qh->hw = (struct ehci_qh_hw *)
++ dma_pool_alloc(ehci->qh_pool, flags, &dma);
++ if (!qh->hw)
++ goto fail;
++ memset(qh->hw, 0, sizeof *qh->hw);
+ qh->refcount = 1;
+ qh->ehci = ehci;
+ qh->qh_dma = dma;
+@@ -99,10 +102,15 @@
+ qh->dummy = ehci_qtd_alloc (ehci, flags);
+ if (qh->dummy == NULL) {
+ ehci_dbg (ehci, "no dummy td\n");
+- dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+- qh = NULL;
++ goto fail1;
+ }
++done:
+ return qh;
++fail1:
++ dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
++fail:
++ kfree(qh);
++ return NULL;
+ }
+
+ /* to share a qh (cpu threads, or hc) */
+@@ -128,7 +136,7 @@
+
+ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+ {
+- free_cached_itd_list(ehci);
++ free_cached_lists(ehci);
+ if (ehci->async)
+ qh_put (ehci->async);
+ ehci->async = NULL;
+@@ -180,7 +188,7 @@
+ /* QHs for control/bulk/intr transfers */
+ ehci->qh_pool = dma_pool_create ("ehci_qh",
+ ehci_to_hcd(ehci)->self.controller,
+- sizeof (struct ehci_qh),
++ sizeof(struct ehci_qh_hw),
+ 32 /* byte alignment (for hw parts) */,
+ 4096 /* can't cross 4K */);
+ if (!ehci->qh_pool) {
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-pci.c linux-2.6.32.27/drivers/usb/host/ehci-pci.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-pci.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-pci.c 2010-12-09 23:29:45.000000000 +0200
+@@ -27,28 +27,8 @@
+ /* called after powerup, by probe or system-pm "wakeup" */
+ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
+ {
+- u32 temp;
+ int retval;
+
+- /* optional debug port, normally in the first BAR */
+- temp = pci_find_capability(pdev, 0x0a);
+- if (temp) {
+- pci_read_config_dword(pdev, temp, &temp);
+- temp >>= 16;
+- if ((temp & (3 << 13)) == (1 << 13)) {
+- temp &= 0x1fff;
+- ehci->debug = ehci_to_hcd(ehci)->regs + temp;
+- temp = ehci_readl(ehci, &ehci->debug->control);
+- ehci_info(ehci, "debug port %d%s\n",
+- HCS_DEBUG_PORT(ehci->hcs_params),
+- (temp & DBGP_ENABLED)
+- ? " IN USE"
+- : "");
+- if (!(temp & DBGP_ENABLED))
+- ehci->debug = NULL;
+- }
+- }
+-
+ /* we expect static quirk code to handle the "extended capabilities"
+ * (currently just BIOS handoff) allowed starting with EHCI 0.96
+ */
+@@ -129,6 +109,13 @@
+ return retval;
+
+ switch (pdev->vendor) {
++ case PCI_VENDOR_ID_INTEL:
++ ehci->need_io_watchdog = 0;
++ if (pdev->device == 0x27cc) {
++ ehci->broken_periodic = 1;
++ ehci_info(ehci, "using broken periodic workaround\n");
++ }
++ break;
+ case PCI_VENDOR_ID_TDI:
+ if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+ hcd->has_tt = 1;
+@@ -192,6 +179,25 @@
+ break;
+ }
+
++ /* optional debug port, normally in the first BAR */
++ temp = pci_find_capability(pdev, 0x0a);
++ if (temp) {
++ pci_read_config_dword(pdev, temp, &temp);
++ temp >>= 16;
++ if ((temp & (3 << 13)) == (1 << 13)) {
++ temp &= 0x1fff;
++ ehci->debug = ehci_to_hcd(ehci)->regs + temp;
++ temp = ehci_readl(ehci, &ehci->debug->control);
++ ehci_info(ehci, "debug port %d%s\n",
++ HCS_DEBUG_PORT(ehci->hcs_params),
++ (temp & DBGP_ENABLED)
++ ? " IN USE"
++ : "");
++ if (!(temp & DBGP_ENABLED))
++ ehci->debug = NULL;
++ }
++ }
++
+ ehci_reset(ehci);
+
+ /* at least the Genesys GL880S needs fixup here */
+@@ -242,7 +248,7 @@
+ * System suspend currently expects to be able to suspend the entire
+ * device tree, device-at-a-time. If we failed selective suspend
+ * reports, system suspend would fail; so the root hub code must claim
+- * success. That's lying to usbcore, and it matters for for runtime
++ * success. That's lying to usbcore, and it matters for runtime
+ * PM scenarios with selective suspend and remote wakeup...
+ */
+ if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
+@@ -268,7 +274,7 @@
+ * Also they depend on separate root hub suspend/resume.
+ */
+
+-static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
++static int ehci_pci_suspend(struct usb_hcd *hcd)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ unsigned long flags;
+@@ -293,12 +299,6 @@
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+- /* make sure snapshot being resumed re-enumerates everything */
+- if (message.event == PM_EVENT_PRETHAW) {
+- ehci_halt(ehci);
+- ehci_reset(ehci);
+- }
+-
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ehci->lock, flags);
+@@ -309,7 +309,7 @@
+ return rc;
+ }
+
+-static int ehci_pci_resume(struct usb_hcd *hcd)
++static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+@@ -322,10 +322,12 @@
+ /* Mark hardware accessible again as we are out of D3 state by now */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+- /* If CF is still set, we maintained PCI Vaux power.
++ /* If CF is still set and we aren't resuming from hibernation
++ * then we maintained PCI Vaux power.
+ * Just undo the effect of ehci_pci_suspend().
+ */
+- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
++ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
++ !hibernated) {
+ int mask = INTR_MASK;
+
+ if (!hcd->self.root_hub->do_remote_wakeup)
+@@ -335,7 +337,6 @@
+ return 0;
+ }
+
+- ehci_dbg(ehci, "lost power, restarting\n");
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ /* Else reset, to cope with power loss or flush-to-storage
+@@ -393,6 +394,7 @@
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
++ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+@@ -431,10 +433,11 @@
+
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
++ .shutdown = usb_hcd_pci_shutdown,
+
+-#ifdef CONFIG_PM
+- .suspend = usb_hcd_pci_suspend,
+- .resume = usb_hcd_pci_resume,
++#ifdef CONFIG_PM_SLEEP
++ .driver = {
++ .pm = &usb_hcd_pci_pm_ops
++ },
+ #endif
+- .shutdown = usb_hcd_pci_shutdown,
+ };
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-q.c linux-2.6.32.27/drivers/usb/host/ehci-q.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-q.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-q.c 2010-12-09 23:29:45.000000000 +0200
+@@ -87,31 +87,33 @@
+ static inline void
+ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
+ {
++ struct ehci_qh_hw *hw = qh->hw;
++
+ /* writes to an active overlay are unsafe */
+ BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+- qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
+- qh->hw_alt_next = EHCI_LIST_END(ehci);
++ hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
++ hw->hw_alt_next = EHCI_LIST_END(ehci);
+
+ /* Except for control endpoints, we make hardware maintain data
+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+ * ever clear it.
+ */
+- if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
++ if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+ unsigned is_out, epnum;
+
+ is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+- epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
++ epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
+ if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+- qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
++ hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+ usb_settoggle (qh->dev, epnum, is_out, 1);
+ }
+ }
+
+ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+ wmb ();
+- qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
++ hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
+ }
+
+ /* if it weren't for a common silicon quirk (writing the dummy into the qh
+@@ -129,7 +131,7 @@
+ qtd = list_entry (qh->qtd_list.next,
+ struct ehci_qtd, qtd_list);
+ /* first qtd may already be partially processed */
+- if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current)
++ if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current)
+ qtd = NULL;
+ }
+
+@@ -214,6 +216,14 @@
+ if (token & QTD_STS_BABBLE) {
+ /* FIXME "must" disable babbling device's port too */
+ status = -EOVERFLOW;
++ /* CERR nonzero + halt --> stall */
++ } else if (QTD_CERR(token)) {
++ status = -EPIPE;
++
++ /* In theory, more than one of the following bits can be set
++ * since they are sticky and the transaction is retried.
++ * Which to test first is rather arbitrary.
++ */
+ } else if (token & QTD_STS_MMF) {
+ /* fs/ls interrupt xfer missed the complete-split */
+ status = -EPROTO;
+@@ -222,21 +232,15 @@
+ ? -ENOSR /* hc couldn't read data */
+ : -ECOMM; /* hc couldn't write data */
+ } else if (token & QTD_STS_XACT) {
+- /* timeout, bad crc, wrong PID, etc; retried */
+- if (QTD_CERR (token))
+- status = -EPIPE;
+- else {
+- ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
+- urb->dev->devpath,
+- usb_pipeendpoint (urb->pipe),
+- usb_pipein (urb->pipe) ? "in" : "out");
+- status = -EPROTO;
+- }
+- /* CERR nonzero + no errors + halt --> stall */
+- } else if (QTD_CERR (token))
+- status = -EPIPE;
+- else /* unknown */
++ /* timeout, bad CRC, wrong PID, etc */
++ ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n",
++ urb->dev->devpath,
++ usb_pipeendpoint(urb->pipe),
++ usb_pipein(urb->pipe) ? "in" : "out");
+ status = -EPROTO;
++ } else { /* unknown */
++ status = -EPROTO;
++ }
+
+ ehci_vdbg (ehci,
+ "dev%d ep%d%s qtd token %08x --> status %d\n",
+@@ -258,7 +262,7 @@
+ struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
+
+ /* S-mask in a QH means it's an interrupt urb */
+- if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
++ if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
+
+ /* ... update hc-wide periodic stats (for usbfs) */
+ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
+@@ -295,7 +299,6 @@
+ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+ /*
+@@ -306,13 +309,14 @@
+ static unsigned
+ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+- struct ehci_qtd *last = NULL, *end = qh->dummy;
++ struct ehci_qtd *last, *end = qh->dummy;
+ struct list_head *entry, *tmp;
+- int last_status = -EINPROGRESS;
++ int last_status;
+ int stopped;
+ unsigned count = 0;
+ u8 state;
+- __le32 halt = HALT_BIT(ehci);
++ const __le32 halt = HALT_BIT(ehci);
++ struct ehci_qh_hw *hw = qh->hw;
+
+ if (unlikely (list_empty (&qh->qtd_list)))
+ return count;
+@@ -322,11 +326,20 @@
+ * they add urbs to this qh's queue or mark them for unlinking.
+ *
+ * NOTE: unlinking expects to be done in queue order.
++ *
++ * It's a bug for qh->qh_state to be anything other than
++ * QH_STATE_IDLE, unless our caller is scan_async() or
++ * scan_periodic().
+ */
+ state = qh->qh_state;
+ qh->qh_state = QH_STATE_COMPLETING;
+ stopped = (state == QH_STATE_IDLE);
+
++ rescan:
++ last = NULL;
++ last_status = -EINPROGRESS;
++ qh->needs_rescan = 0;
++
+ /* remove de-activated QTDs from front of queue.
+ * after faults (including short reads), cleanup this urb
+ * then let the queue advance.
+@@ -373,12 +386,11 @@
+ */
+ if ((token & QTD_STS_XACT) &&
+ QTD_CERR(token) == 0 &&
+- --qh->xacterrs > 0 &&
++ ++qh->xacterrs < QH_XACTERR_MAX &&
+ !urb->unlinked) {
+ ehci_dbg(ehci,
+ "detected XactErr len %zu/%zu retry %d\n",
+- qtd->length - QTD_LENGTH(token), qtd->length,
+- QH_XACTERR_MAX - qh->xacterrs);
++ qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
+
+ /* reset the token in the qtd and the
+ * qh overlay (which still contains
+@@ -391,7 +403,8 @@
+ qtd->hw_token = cpu_to_hc32(ehci,
+ token);
+ wmb();
+- qh->hw_token = cpu_to_hc32(ehci, token);
++ hw->hw_token = cpu_to_hc32(ehci,
++ token);
+ goto retry_xacterr;
+ }
+ stopped = 1;
+@@ -434,8 +447,8 @@
+ /* qh unlinked; token in overlay may be most current */
+ if (state == QH_STATE_IDLE
+ && cpu_to_hc32(ehci, qtd->qtd_dma)
+- == qh->hw_current) {
+- token = hc32_to_cpu(ehci, qh->hw_token);
++ == hw->hw_current) {
++ token = hc32_to_cpu(ehci, hw->hw_token);
+
+ /* An unlink may leave an incomplete
+ * async transaction in the TT buffer.
+@@ -448,9 +461,9 @@
+ * patch the qh later and so that completions can't
+ * activate it while we "know" it's stopped.
+ */
+- if ((halt & qh->hw_token) == 0) {
++ if ((halt & hw->hw_token) == 0) {
+ halt:
+- qh->hw_token |= halt;
++ hw->hw_token |= halt;
+ wmb ();
+ }
+ }
+@@ -474,8 +487,20 @@
+ * we must clear the TT buffer (11.17.5).
+ */
+ if (unlikely(last_status != -EINPROGRESS &&
+- last_status != -EREMOTEIO))
+- ehci_clear_tt_buffer(ehci, qh, urb, token);
++ last_status != -EREMOTEIO)) {
++ /* The TT's in some hubs malfunction when they
++ * receive this request following a STALL (they
++ * stop sending isochronous packets). Since a
++ * STALL can't leave the TT buffer in a busy
++ * state (if you believe Figures 11-48 - 11-51
++ * in the USB 2.0 spec), we won't clear the TT
++ * buffer in this case. Strictly speaking this
++ * is a violation of the spec.
++ */
++ if (last_status != -EPIPE)
++ ehci_clear_tt_buffer(ehci, qh, urb,
++ token);
++ }
+ }
+
+ /* if we're removing something not at the queue head,
+@@ -492,7 +517,7 @@
+ last = qtd;
+
+ /* reinit the xacterr counter for the next qtd */
+- qh->xacterrs = QH_XACTERR_MAX;
++ qh->xacterrs = 0;
+ }
+
+ /* last urb's completion might still need calling */
+@@ -502,6 +527,21 @@
+ ehci_qtd_free (ehci, last);
+ }
+
++ /* Do we need to rescan for URBs dequeued during a giveback? */
++ if (unlikely(qh->needs_rescan)) {
++ /* If the QH is already unlinked, do the rescan now. */
++ if (state == QH_STATE_IDLE)
++ goto rescan;
++
++ /* Otherwise we have to wait until the QH is fully unlinked.
++ * Our caller will start an unlink if qh->needs_rescan is
++ * set. But if an unlink has already started, nothing needs
++ * to be done.
++ */
++ if (state != QH_STATE_LINKED)
++ qh->needs_rescan = 0;
++ }
++
+ /* restore original state; caller must unlink or relink */
+ qh->qh_state = state;
+
+@@ -509,7 +549,7 @@
+ * it after fault cleanup, or recovering from silicon wrongly
+ * overlaying the dummy qtd (which reduces DMA chatter).
+ */
+- if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) {
++ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
+ switch (state) {
+ case QH_STATE_IDLE:
+ qh_refresh(ehci, qh);
+@@ -526,12 +566,9 @@
+ * That should be rare for interrupt transfers,
+ * except maybe high bandwidth ...
+ */
+- if ((cpu_to_hc32(ehci, QH_SMASK)
+- & qh->hw_info2) != 0) {
+- intr_deschedule (ehci, qh);
+- (void) qh_schedule (ehci, qh);
+- } else
+- unlink_async (ehci, qh);
++
++ /* Tell the caller to start an unlink */
++ qh->needs_rescan = 1;
+ break;
+ /* otherwise, unlink already started */
+ }
+@@ -648,7 +685,7 @@
+ * (this will usually be overridden later.)
+ */
+ if (is_input)
+- qtd->hw_alt_next = ehci->async->hw_alt_next;
++ qtd->hw_alt_next = ehci->async->hw->hw_alt_next;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+@@ -743,6 +780,7 @@
+ int is_input, type;
+ int maxp = 0;
+ struct usb_tt *tt = urb->dev->tt;
++ struct ehci_qh_hw *hw;
+
+ if (!qh)
+ return qh;
+@@ -789,9 +827,10 @@
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+- dbg ("intr period %d uframes, NYET!",
+- urb->interval);
+- goto done;
++ urb->interval = 1;
++ } else if (qh->period > ehci->periodic_size) {
++ qh->period = ehci->periodic_size;
++ urb->interval = qh->period << 3;
+ }
+ } else {
+ int think_time;
+@@ -814,6 +853,10 @@
+ usb_calc_bus_time (urb->dev->speed,
+ is_input, 0, max_packet (maxp)));
+ qh->period = urb->interval;
++ if (qh->period > ehci->periodic_size) {
++ qh->period = ehci->periodic_size;
++ urb->interval = qh->period;
++ }
+ }
+ }
+
+@@ -889,8 +932,9 @@
+
+ /* init as live, toggle clear, advance to dummy */
+ qh->qh_state = QH_STATE_IDLE;
+- qh->hw_info1 = cpu_to_hc32(ehci, info1);
+- qh->hw_info2 = cpu_to_hc32(ehci, info2);
++ hw = qh->hw;
++ hw->hw_info1 = cpu_to_hc32(ehci, info1);
++ hw->hw_info2 = cpu_to_hc32(ehci, info2);
+ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+ qh_refresh (ehci, qh);
+ return qh;
+@@ -909,6 +953,8 @@
+ if (unlikely(qh->clearing_tt))
+ return;
+
++ WARN_ON(qh->qh_state != QH_STATE_IDLE);
++
+ /* (re)start the async schedule? */
+ head = ehci->async;
+ timer_action_done (ehci, TIMER_ASYNC_OFF);
+@@ -927,19 +973,18 @@
+ }
+
+ /* clear halt and/or toggle; and maybe recover from silicon quirk */
+- if (qh->qh_state == QH_STATE_IDLE)
+- qh_refresh (ehci, qh);
++ qh_refresh(ehci, qh);
+
+ /* splice right after start */
+ qh->qh_next = head->qh_next;
+- qh->hw_next = head->hw_next;
++ qh->hw->hw_next = head->hw->hw_next;
+ wmb ();
+
+ head->qh_next.qh = qh;
+- head->hw_next = dma;
++ head->hw->hw_next = dma;
+
+ qh_get(qh);
+- qh->xacterrs = QH_XACTERR_MAX;
++ qh->xacterrs = 0;
+ qh->qh_state = QH_STATE_LINKED;
+ /* qtd completions reported later by interrupt */
+ }
+@@ -983,7 +1028,7 @@
+
+ /* usb_reset_device() briefly reverts to address 0 */
+ if (usb_pipedevice (urb->pipe) == 0)
+- qh->hw_info1 &= ~qh_addr_mask;
++ qh->hw->hw_info1 &= ~qh_addr_mask;
+ }
+
+ /* just one way to queue requests: swap with the dummy qtd.
+@@ -1168,7 +1213,7 @@
+ while (prev->qh_next.qh != qh)
+ prev = prev->qh_next.qh;
+
+- prev->hw_next = qh->hw_next;
++ prev->hw->hw_next = qh->hw->hw_next;
+ prev->qh_next = qh->qh_next;
+ wmb ();
+
+@@ -1213,6 +1258,8 @@
+ qh = qh_get (qh);
+ qh->stamp = ehci->stamp;
+ temp = qh_completions (ehci, qh);
++ if (qh->needs_rescan)
++ unlink_async(ehci, qh);
+ qh_put (qh);
+ if (temp != 0) {
+ goto rescan;
+diff -ur linux-2.6.30.9/drivers/usb/host/ehci-sched.c linux-2.6.32.27/drivers/usb/host/ehci-sched.c
+--- linux-2.6.30.9/drivers/usb/host/ehci-sched.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ehci-sched.c 2010-12-09 23:29:45.000000000 +0200
+@@ -60,6 +60,20 @@
+ }
+ }
+
++static __hc32 *
++shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic,
++ __hc32 tag)
++{
++ switch (hc32_to_cpu(ehci, tag)) {
++ /* our ehci_shadow.qh is actually software part */
++ case Q_TYPE_QH:
++ return &periodic->qh->hw->hw_next;
++ /* others are hw parts */
++ default:
++ return periodic->hw_next;
++ }
++}
++
+ /* caller must hold ehci->lock */
+ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+ {
+@@ -71,7 +85,8 @@
+ while (here.ptr && here.ptr != ptr) {
+ prev_p = periodic_next_shadow(ehci, prev_p,
+ Q_NEXT_TYPE(ehci, *hw_p));
+- hw_p = here.hw_next;
++ hw_p = shadow_next_periodic(ehci, &here,
++ Q_NEXT_TYPE(ehci, *hw_p));
+ here = *prev_p;
+ }
+ /* an interrupt entry (at list end) could have been shared */
+@@ -83,7 +98,7 @@
+ */
+ *prev_p = *periodic_next_shadow(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+- *hw_p = *here.hw_next;
++ *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+ }
+
+ /* how many of the uframe's 125 usecs are allocated? */
+@@ -93,18 +108,20 @@
+ __hc32 *hw_p = &ehci->periodic [frame];
+ union ehci_shadow *q = &ehci->pshadow [frame];
+ unsigned usecs = 0;
++ struct ehci_qh_hw *hw;
+
+ while (q->ptr) {
+ switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
+ case Q_TYPE_QH:
++ hw = q->qh->hw;
+ /* is it in the S-mask? */
+- if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
++ if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
+ usecs += q->qh->usecs;
+ /* ... or C-mask? */
+- if (q->qh->hw_info2 & cpu_to_hc32(ehci,
++ if (hw->hw_info2 & cpu_to_hc32(ehci,
+ 1 << (8 + uframe)))
+ usecs += q->qh->c_usecs;
+- hw_p = &q->qh->hw_next;
++ hw_p = &hw->hw_next;
+ q = &q->qh->qh_next;
+ break;
+ // case Q_TYPE_FSTN:
+@@ -237,10 +254,10 @@
+ continue;
+ case Q_TYPE_QH:
+ if (same_tt(dev, q->qh->dev)) {
+- uf = tt_start_uframe(ehci, q->qh->hw_info2);
++ uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
+ tt_usecs[uf] += q->qh->tt_usecs;
+ }
+- hw_p = &q->qh->hw_next;
++ hw_p = &q->qh->hw->hw_next;
+ q = &q->qh->qh_next;
+ continue;
+ case Q_TYPE_SITD:
+@@ -375,6 +392,7 @@
+ for (; frame < ehci->periodic_size; frame += period) {
+ union ehci_shadow here;
+ __hc32 type;
++ struct ehci_qh_hw *hw;
+
+ here = ehci->pshadow [frame];
+ type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
+@@ -385,17 +403,18 @@
+ here = here.itd->itd_next;
+ continue;
+ case Q_TYPE_QH:
++ hw = here.qh->hw;
+ if (same_tt (dev, here.qh->dev)) {
+ u32 mask;
+
+ mask = hc32_to_cpu(ehci,
+- here.qh->hw_info2);
++ hw->hw_info2);
+ /* "knows" no gap is needed */
+ mask |= mask >> 8;
+ if (mask & uf_mask)
+ break;
+ }
+- type = Q_NEXT_TYPE(ehci, here.qh->hw_next);
++ type = Q_NEXT_TYPE(ehci, hw->hw_next);
+ here = here.qh->qh_next;
+ continue;
+ case Q_TYPE_SITD:
+@@ -456,6 +475,8 @@
+ /* make sure ehci_work scans these */
+ ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+ % (ehci->periodic_size << 3);
++ if (unlikely(ehci->broken_periodic))
++ ehci->last_periodic_enable = ktime_get_real();
+ return 0;
+ }
+
+@@ -467,6 +488,16 @@
+ if (--ehci->periodic_sched)
+ return 0;
+
++ if (unlikely(ehci->broken_periodic)) {
++ /* delay experimentally determined */
++ ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
++ ktime_t now = ktime_get_real();
++ s64 delay = ktime_us_delta(safe, now);
++
++ if (unlikely(delay > 0))
++ udelay(delay);
++ }
++
+ /* did setting PSE not take effect yet?
+ * takes effect only at frame boundaries...
+ */
+@@ -498,7 +529,8 @@
+
+ dev_dbg (&qh->dev->dev,
+ "link qh%d-%04x/%p start %d [%d/%d us]\n",
+- period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
++ period, hc32_to_cpup(ehci, &qh->hw->hw_info2)
++ & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* high bandwidth, or otherwise every microframe */
+@@ -517,7 +549,7 @@
+ if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
+ break;
+ prev = periodic_next_shadow(ehci, prev, type);
+- hw_p = &here.qh->hw_next;
++ hw_p = shadow_next_periodic(ehci, &here, type);
+ here = *prev;
+ }
+
+@@ -528,20 +560,21 @@
+ if (qh->period > here.qh->period)
+ break;
+ prev = &here.qh->qh_next;
+- hw_p = &here.qh->hw_next;
++ hw_p = &here.qh->hw->hw_next;
+ here = *prev;
+ }
+ /* link in this qh, unless some earlier pass did that */
+ if (qh != here.qh) {
+ qh->qh_next = here;
+ if (here.qh)
+- qh->hw_next = *hw_p;
++ qh->hw->hw_next = *hw_p;
+ wmb ();
+ prev->qh = qh;
+ *hw_p = QH_NEXT (ehci, qh->qh_dma);
+ }
+ }
+ qh->qh_state = QH_STATE_LINKED;
++ qh->xacterrs = 0;
+ qh_get (qh);
+
+ /* update per-qh bandwidth for usbfs */
+@@ -580,7 +613,7 @@
+ dev_dbg (&qh->dev->dev,
+ "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+ qh->period,
+- hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
++ hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* qh->qh_next still "live" to HC */
+@@ -594,7 +627,19 @@
+
+ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+- unsigned wait;
++ unsigned wait;
++ struct ehci_qh_hw *hw = qh->hw;
++ int rc;
++
++ /* If the QH isn't linked then there's nothing we can do
++ * unless we were called during a giveback, in which case
++ * qh_completions() has to deal with it.
++ */
++ if (qh->qh_state != QH_STATE_LINKED) {
++ if (qh->qh_state == QH_STATE_COMPLETING)
++ qh->needs_rescan = 1;
++ return;
++ }
+
+ qh_unlink_periodic (ehci, qh);
+
+@@ -605,15 +650,33 @@
+ */
+ if (list_empty (&qh->qtd_list)
+ || (cpu_to_hc32(ehci, QH_CMASK)
+- & qh->hw_info2) != 0)
++ & hw->hw_info2) != 0)
+ wait = 2;
+ else
+ wait = 55; /* worst case: 3 * 1024 */
+
+ udelay (wait);
+ qh->qh_state = QH_STATE_IDLE;
+- qh->hw_next = EHCI_LIST_END(ehci);
++ hw->hw_next = EHCI_LIST_END(ehci);
+ wmb ();
++
++ qh_completions(ehci, qh);
++
++ /* reschedule QH iff another request is queued */
++ if (!list_empty(&qh->qtd_list) &&
++ HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
++ rc = qh_schedule(ehci, qh);
++
++ /* An error here likely indicates handshake failure
++ * or no space left in the schedule. Neither fault
++ * should happen often ...
++ *
++ * FIXME kill the now-dysfunctional queued urbs
++ */
++ if (rc != 0)
++ ehci_err(ehci, "can't reschedule qh %p, err %d\n",
++ qh, rc);
++ }
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -738,14 +801,15 @@
+ unsigned uframe;
+ __hc32 c_mask;
+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
++ struct ehci_qh_hw *hw = qh->hw;
+
+ qh_refresh(ehci, qh);
+- qh->hw_next = EHCI_LIST_END(ehci);
++ hw->hw_next = EHCI_LIST_END(ehci);
+ frame = qh->start;
+
+ /* reuse the previous schedule slots, if we can */
+ if (frame < qh->period) {
+- uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK);
++ uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK);
+ status = check_intr_schedule (ehci, frame, --uframe,
+ qh, &c_mask);
+ } else {
+@@ -760,8 +824,10 @@
+ if (status) {
+ /* "normal" case, uframing flexible except with splits */
+ if (qh->period) {
+- frame = qh->period - 1;
+- do {
++ int i;
++
++ for (i = qh->period; status && i > 0; --i) {
++ frame = ++ehci->random_frame % qh->period;
+ for (uframe = 0; uframe < 8; uframe++) {
+ status = check_intr_schedule (ehci,
+ frame, uframe, qh,
+@@ -769,7 +835,7 @@
+ if (status == 0)
+ break;
+ }
+- } while (status && frame--);
++ }
+
+ /* qh->period == 0 means every uframe */
+ } else {
+@@ -781,11 +847,11 @@
+ qh->start = frame;
+
+ /* reset S-frame and (maybe) C-frame masks */
+- qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
+- qh->hw_info2 |= qh->period
++ hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
++ hw->hw_info2 |= qh->period
+ ? cpu_to_hc32(ehci, 1 << uframe)
+ : cpu_to_hc32(ehci, QH_SMASK);
+- qh->hw_info2 |= c_mask;
++ hw->hw_info2 |= c_mask;
+ } else
+ ehci_dbg (ehci, "reused qh %p schedule\n", qh);
+
+@@ -1055,8 +1121,8 @@
+ urb->interval);
+ }
+
+- /* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */
+- } else if (unlikely (stream->hw_info1 != 0)) {
++ /* if dev->ep [epnum] is a QH, hw is set */
++ } else if (unlikely (stream->hw != NULL)) {
+ ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n",
+ urb->dev->devpath, epnum,
+ usb_pipein(urb->pipe) ? "in" : "out");
+@@ -1346,6 +1412,10 @@
+ goto fail;
+ }
+
++ period = urb->interval;
++ if (!stream->highspeed)
++ period <<= 3;
++
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
+
+ /* when's the last uframe this urb could start? */
+@@ -1363,14 +1433,15 @@
+
+ /* Fell behind (by up to twice the slop amount)? */
+ if (start >= max - 2 * 8 * SCHEDULE_SLOP)
+- start += stream->interval * DIV_ROUND_UP(
+- max - start, stream->interval) - mod;
++ start += period * DIV_ROUND_UP(
++ max - start, period) - mod;
+
+ /* Tried to schedule too far into the future? */
+ if (unlikely((start + sched->span) >= max)) {
+ status = -EFBIG;
+ goto fail;
+ }
++ stream->next_uframe = start;
+ goto ready;
+ }
+
+@@ -1386,10 +1457,6 @@
+
+ /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
+
+- period = urb->interval;
+- if (!stream->highspeed)
+- period <<= 3;
+-
+ /* find a uframe slot with enough bandwidth */
+ for (; start < (stream->next_uframe + period); start++) {
+ int enough_space;
+@@ -1486,13 +1553,27 @@
+ static inline void
+ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+ {
+- /* always prepend ITD/SITD ... only QH tree is order-sensitive */
+- itd->itd_next = ehci->pshadow [frame];
+- itd->hw_next = ehci->periodic [frame];
+- ehci->pshadow [frame].itd = itd;
++ union ehci_shadow *prev = &ehci->pshadow[frame];
++ __hc32 *hw_p = &ehci->periodic[frame];
++ union ehci_shadow here = *prev;
++ __hc32 type = 0;
++
++ /* skip any iso nodes which might belong to previous microframes */
++ while (here.ptr) {
++ type = Q_NEXT_TYPE(ehci, *hw_p);
++ if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
++ break;
++ prev = periodic_next_shadow(ehci, prev, type);
++ hw_p = shadow_next_periodic(ehci, &here, type);
++ here = *prev;
++ }
++
++ itd->itd_next = here;
++ itd->hw_next = *hw_p;
++ prev->itd = itd;
+ itd->frame = frame;
+ wmb ();
+- ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
++ *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
+ }
+
+ /* fit urb's itds into the selected schedule slot; activate as needed */
+@@ -2046,13 +2127,27 @@
+ (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+ }
+ iso_stream_put (ehci, stream);
+- /* OK to recycle this SITD now that its completion callback ran. */
++
+ done:
+ sitd->urb = NULL;
+- sitd->stream = NULL;
+- list_move(&sitd->sitd_list, &stream->free_list);
+- iso_stream_put(ehci, stream);
+-
++ if (ehci->clock_frame != sitd->frame) {
++ /* OK to recycle this SITD now. */
++ sitd->stream = NULL;
++ list_move(&sitd->sitd_list, &stream->free_list);
++ iso_stream_put(ehci, stream);
++ } else {
++ /* HW might remember this SITD, so we can't recycle it yet.
++ * Move it to a safe place until a new frame starts.
++ */
++ list_move(&sitd->sitd_list, &ehci->cached_sitd_list);
++ if (stream->refcount == 2) {
++ /* If iso_stream_put() were called here, stream
++ * would be freed. Instead, just prevent reuse.
++ */
++ stream->ep->hcpriv = NULL;
++ stream->ep = NULL;
++ }
++ }
+ return retval;
+ }
+
+@@ -2118,9 +2213,10 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static void free_cached_itd_list(struct ehci_hcd *ehci)
++static void free_cached_lists(struct ehci_hcd *ehci)
+ {
+ struct ehci_itd *itd, *n;
++ struct ehci_sitd *sitd, *sn;
+
+ list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
+ struct ehci_iso_stream *stream = itd->stream;
+@@ -2128,6 +2224,13 @@
+ list_move(&itd->itd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
+ }
++
++ list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
++ struct ehci_iso_stream *stream = sitd->stream;
++ sitd->stream = NULL;
++ list_move(&sitd->sitd_list, &stream->free_list);
++ iso_stream_put(ehci, stream);
++ }
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -2154,7 +2257,7 @@
+ clock_frame = -1;
+ }
+ if (ehci->clock_frame != clock_frame) {
+- free_cached_itd_list(ehci);
++ free_cached_lists(ehci);
+ ehci->clock_frame = clock_frame;
+ }
+ clock %= mod;
+@@ -2185,10 +2288,11 @@
+ case Q_TYPE_QH:
+ /* handle any completions */
+ temp.qh = qh_get (q.qh);
+- type = Q_NEXT_TYPE(ehci, q.qh->hw_next);
++ type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
+ q = q.qh->qh_next;
+ modified = qh_completions (ehci, temp.qh);
+- if (unlikely (list_empty (&temp.qh->qtd_list)))
++ if (unlikely(list_empty(&temp.qh->qtd_list) ||
++ temp.qh->needs_rescan))
+ intr_deschedule (ehci, temp.qh);
+ qh_put (temp.qh);
+ break;
+@@ -2316,7 +2420,7 @@
+ clock = now;
+ clock_frame = clock >> 3;
+ if (ehci->clock_frame != clock_frame) {
+- free_cached_itd_list(ehci);
++ free_cached_lists(ehci);
+ ehci->clock_frame = clock_frame;
+ }
+ } else {
+diff -ur linux-2.6.30.9/drivers/usb/host/hwa-hc.c linux-2.6.32.27/drivers/usb/host/hwa-hc.c
+--- linux-2.6.30.9/drivers/usb/host/hwa-hc.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/hwa-hc.c 2010-12-09 23:29:45.000000000 +0200
+@@ -172,25 +172,6 @@
+
+ }
+
+-static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
+-{
+- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+- dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__,
+- usb_hcd, hwahc, *(unsigned long *) &msg);
+- return -ENOSYS;
+-}
+-
+-static int hwahc_op_resume(struct usb_hcd *usb_hcd)
+-{
+- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+-
+- dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
+- usb_hcd, hwahc);
+- return -ENOSYS;
+-}
+-
+ /*
+ * No need to abort pipes, as when this is called, all the children
+ * has been disconnected and that has done it [through
+@@ -598,8 +579,6 @@
+ .flags = HCD_USB2, /* FIXME */
+ .reset = hwahc_op_reset,
+ .start = hwahc_op_start,
+- .pci_suspend = hwahc_op_suspend,
+- .pci_resume = hwahc_op_resume,
+ .stop = hwahc_op_stop,
+ .get_frame_number = hwahc_op_get_frame_number,
+ .urb_enqueue = hwahc_op_urb_enqueue,
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci-dbg.c linux-2.6.32.27/drivers/usb/host/ohci-dbg.c
+--- linux-2.6.30.9/drivers/usb/host/ohci-dbg.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci-dbg.c 2010-12-09 23:29:45.000000000 +0200
+@@ -431,7 +431,7 @@
+
+ struct debug_buffer {
+ ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
+- struct device *dev;
++ struct ohci_hcd *ohci;
+ struct mutex mutex; /* protect filling of buffer */
+ size_t count; /* number of characters filled into buffer */
+ char *page;
+@@ -505,15 +505,11 @@
+
+ static ssize_t fill_async_buffer(struct debug_buffer *buf)
+ {
+- struct usb_bus *bus;
+- struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ size_t temp;
+ unsigned long flags;
+
+- bus = dev_get_drvdata(buf->dev);
+- hcd = bus_to_hcd(bus);
+- ohci = hcd_to_ohci(hcd);
++ ohci = buf->ohci;
+
+ /* display control and bulk lists together, for simplicity */
+ spin_lock_irqsave (&ohci->lock, flags);
+@@ -529,8 +525,6 @@
+
+ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+ {
+- struct usb_bus *bus;
+- struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct ed **seen, *ed;
+ unsigned long flags;
+@@ -542,9 +536,7 @@
+ return 0;
+ seen_count = 0;
+
+- bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
+- hcd = bus_to_hcd(bus);
+- ohci = hcd_to_ohci(hcd);
++ ohci = buf->ohci;
+ next = buf->page;
+ size = PAGE_SIZE;
+
+@@ -626,7 +618,6 @@
+
+ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+ {
+- struct usb_bus *bus;
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct ohci_regs __iomem *regs;
+@@ -635,9 +626,8 @@
+ char *next;
+ u32 rdata;
+
+- bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
+- hcd = bus_to_hcd(bus);
+- ohci = hcd_to_ohci(hcd);
++ ohci = buf->ohci;
++ hcd = ohci_to_hcd(ohci);
+ regs = ohci->regs;
+ next = buf->page;
+ size = PAGE_SIZE;
+@@ -710,7 +700,7 @@
+ return PAGE_SIZE - size;
+ }
+
+-static struct debug_buffer *alloc_buffer(struct device *dev,
++static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
+ ssize_t (*fill_func)(struct debug_buffer *))
+ {
+ struct debug_buffer *buf;
+@@ -718,7 +708,7 @@
+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+ if (buf) {
+- buf->dev = dev;
++ buf->ohci = ohci;
+ buf->fill_func = fill_func;
+ mutex_init(&buf->mutex);
+ }
+@@ -810,26 +800,25 @@
+ static inline void create_debug_files (struct ohci_hcd *ohci)
+ {
+ struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
+- struct device *dev = bus->dev;
+
+ ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
+ if (!ohci->debug_dir)
+ goto dir_error;
+
+ ohci->debug_async = debugfs_create_file("async", S_IRUGO,
+- ohci->debug_dir, dev,
++ ohci->debug_dir, ohci,
+ &debug_async_fops);
+ if (!ohci->debug_async)
+ goto async_error;
+
+ ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+- ohci->debug_dir, dev,
++ ohci->debug_dir, ohci,
+ &debug_periodic_fops);
+ if (!ohci->debug_periodic)
+ goto periodic_error;
+
+ ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+- ohci->debug_dir, dev,
++ ohci->debug_dir, ohci,
+ &debug_registers_fops);
+ if (!ohci->debug_registers)
+ goto registers_error;
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci.h linux-2.6.32.27/drivers/usb/host/ohci.h
+--- linux-2.6.30.9/drivers/usb/host/ohci.h 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci.h 2010-12-09 23:29:45.000000000 +0200
+@@ -402,6 +402,7 @@
+ #define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
+ #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
+ #define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
++#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
+ // there are also chip quirks/bugs in init logic
+
+ struct work_struct nec_work; /* Worker for NEC quirk */
+@@ -433,6 +434,10 @@
+ {
+ return ohci->flags & OHCI_QUIRK_AMD_ISO;
+ }
++static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
++{
++ return ohci->flags & OHCI_QUIRK_AMD_PREFETCH;
++}
+ #else
+ static inline int quirk_nec(struct ohci_hcd *ohci)
+ {
+@@ -446,6 +451,10 @@
+ {
+ return 0;
+ }
++static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
++{
++ return 0;
++}
+ #endif
+
+ /* convert between an hcd pointer and the corresponding ohci_hcd */
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci-hcd.c linux-2.6.32.27/drivers/usb/host/ohci-hcd.c
+--- linux-2.6.30.9/drivers/usb/host/ohci-hcd.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci-hcd.c 2010-12-09 23:29:45.000000000 +0200
+@@ -34,7 +34,6 @@
+ #include <linux/usb/otg.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+-#include <linux/reboot.h>
+ #include <linux/workqueue.h>
+ #include <linux/debugfs.h>
+
+@@ -88,6 +87,7 @@
+ #ifdef CONFIG_PCI
+ static void quirk_amd_pll(int state);
+ static void amd_iso_dev_put(void);
++static void sb800_prefetch(struct ohci_hcd *ohci, int on);
+ #else
+ static inline void quirk_amd_pll(int state)
+ {
+@@ -97,6 +97,10 @@
+ {
+ return;
+ }
++static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
++{
++ return;
++}
+ #endif
+
+
+@@ -571,7 +575,7 @@
+ */
+ static int ohci_run (struct ohci_hcd *ohci)
+ {
+- u32 mask, temp;
++ u32 mask, val;
+ int first = ohci->fminterval == 0;
+ struct usb_hcd *hcd = ohci_to_hcd(ohci);
+
+@@ -580,8 +584,8 @@
+ /* boot firmware should have set this up (5.1.1.3.1) */
+ if (first) {
+
+- temp = ohci_readl (ohci, &ohci->regs->fminterval);
+- ohci->fminterval = temp & 0x3fff;
++ val = ohci_readl (ohci, &ohci->regs->fminterval);
++ ohci->fminterval = val & 0x3fff;
+ if (ohci->fminterval != FI)
+ ohci_dbg (ohci, "fminterval delta %d\n",
+ ohci->fminterval - FI);
+@@ -600,25 +604,25 @@
+
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+- temp = 0;
++ val = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ ohci->hc_control &= OHCI_CTRL_RWC;
+ ohci->hc_control |= OHCI_USB_RESUME;
+- temp = 10 /* msec wait */;
++ val = 10 /* msec wait */;
+ break;
+ // case OHCI_USB_RESET:
+ default:
+ ohci->hc_control &= OHCI_CTRL_RWC;
+ ohci->hc_control |= OHCI_USB_RESET;
+- temp = 50 /* msec wait */;
++ val = 50 /* msec wait */;
+ break;
+ }
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ // flush the writes
+ (void) ohci_readl (ohci, &ohci->regs->control);
+- msleep(temp);
++ msleep(val);
+
+ memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+
+@@ -628,9 +632,9 @@
+ retry:
+ /* HC Reset requires max 10 us delay */
+ ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus);
+- temp = 30; /* ... allow extra time */
++ val = 30; /* ... allow extra time */
+ while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+- if (--temp == 0) {
++ if (--val == 0) {
+ spin_unlock_irq (&ohci->lock);
+ ohci_err (ohci, "USB HC reset timed out!\n");
+ return -1;
+@@ -699,23 +703,23 @@
+ ohci_writel (ohci, mask, &ohci->regs->intrenable);
+
+ /* handle root hub init quirks ... */
+- temp = roothub_a (ohci);
+- temp &= ~(RH_A_PSM | RH_A_OCPM);
++ val = roothub_a (ohci);
++ val &= ~(RH_A_PSM | RH_A_OCPM);
+ if (ohci->flags & OHCI_QUIRK_SUPERIO) {
+ /* NSC 87560 and maybe others */
+- temp |= RH_A_NOCP;
+- temp &= ~(RH_A_POTPGT | RH_A_NPS);
+- ohci_writel (ohci, temp, &ohci->regs->roothub.a);
++ val |= RH_A_NOCP;
++ val &= ~(RH_A_POTPGT | RH_A_NPS);
++ ohci_writel (ohci, val, &ohci->regs->roothub.a);
+ } else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
+ (ohci->flags & OHCI_QUIRK_HUB_POWER)) {
+ /* hub power always on; required for AMD-756 and some
+ * Mac platforms. ganged overcurrent reporting, if any.
+ */
+- temp |= RH_A_NPS;
+- ohci_writel (ohci, temp, &ohci->regs->roothub.a);
++ val |= RH_A_NPS;
++ ohci_writel (ohci, val, &ohci->regs->roothub.a);
+ }
+ ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
+- ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
++ ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
+ &ohci->regs->roothub.b);
+ // flush those writes
+ (void) ohci_readl (ohci, &ohci->regs->control);
+@@ -724,7 +728,7 @@
+ spin_unlock_irq (&ohci->lock);
+
+ // POTPGT delay is bits 24-31, in 2 ms units.
+- mdelay ((temp >> 23) & 0x1fe);
++ mdelay ((val >> 23) & 0x1fe);
+ hcd->state = HC_STATE_RUNNING;
+
+ if (quirk_zfmicro(ohci)) {
+@@ -1105,7 +1109,7 @@
+ set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
+
+ #ifdef DEBUG
+- ohci_debug_root = debugfs_create_dir("ohci", NULL);
++ ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
+ if (!ohci_debug_root) {
+ retval = -ENOENT;
+ goto error_debug;
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci-hub.c linux-2.6.32.27/drivers/usb/host/ohci-hub.c
+--- linux-2.6.30.9/drivers/usb/host/ohci-hub.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci-hub.c 2010-12-09 23:29:45.000000000 +0200
+@@ -697,7 +697,7 @@
+ u16 wLength
+ ) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+- int ports = hcd_to_bus (hcd)->root_hub->maxchild;
++ int ports = ohci->num_ports;
+ u32 temp;
+ int retval = 0;
+
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci-pci.c linux-2.6.32.27/drivers/usb/host/ohci-pci.c
+--- linux-2.6.30.9/drivers/usb/host/ohci-pci.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci-pci.c 2010-12-09 23:29:45.000000000 +0200
+@@ -177,6 +177,13 @@
+ return 0;
+
+ pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
++
++ /* SB800 needs pre-fetch fix */
++ if ((rev >= 0x40) && (rev <= 0x4f)) {
++ ohci->flags |= OHCI_QUIRK_AMD_PREFETCH;
++ ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
++ }
++
+ if ((rev > 0x3b) || (rev < 0x30)) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+@@ -262,6 +269,19 @@
+
+ }
+
++static void sb800_prefetch(struct ohci_hcd *ohci, int on)
++{
++ struct pci_dev *pdev;
++ u16 misc;
++
++ pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller);
++ pci_read_config_word(pdev, 0x50, &misc);
++ if (on == 0)
++ pci_write_config_word(pdev, 0x50, misc & 0xfcff);
++ else
++ pci_write_config_word(pdev, 0x50, misc | 0x0300);
++}
++
+ /* List of quirks for OHCI */
+ static const struct pci_device_id ohci_pci_quirks[] = {
+ {
+@@ -372,7 +392,7 @@
+
+ #ifdef CONFIG_PM
+
+-static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
++static int ohci_pci_suspend(struct usb_hcd *hcd)
+ {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ unsigned long flags;
+@@ -394,10 +414,6 @@
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ (void)ohci_readl(ohci, &ohci->regs->intrdisable);
+
+- /* make sure snapshot being resumed re-enumerates everything */
+- if (message.event == PM_EVENT_PRETHAW)
+- ohci_usb_reset(ohci);
+-
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ohci->lock, flags);
+@@ -406,9 +422,14 @@
+ }
+
+
+-static int ohci_pci_resume (struct usb_hcd *hcd)
++static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
+ {
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++
++ /* Make sure resume from hibernation re-enumerates everything */
++ if (hibernated)
++ ohci_usb_reset(hcd_to_ohci(hcd));
++
+ ohci_finish_controller_resume(hcd);
+ return 0;
+ }
+@@ -484,12 +505,11 @@
+
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
++ .shutdown = usb_hcd_pci_shutdown,
+
+-#ifdef CONFIG_PM
+- .suspend = usb_hcd_pci_suspend,
+- .resume = usb_hcd_pci_resume,
++#ifdef CONFIG_PM_SLEEP
++ .driver = {
++ .pm = &usb_hcd_pci_pm_ops
++ },
+ #endif
+-
+- .shutdown = usb_hcd_pci_shutdown,
+ };
+-
+diff -ur linux-2.6.30.9/drivers/usb/host/ohci-q.c linux-2.6.32.27/drivers/usb/host/ohci-q.c
+--- linux-2.6.30.9/drivers/usb/host/ohci-q.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/ohci-q.c 2010-12-09 23:29:45.000000000 +0200
+@@ -49,9 +49,12 @@
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
+- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+- && quirk_amdiso(ohci))
+- quirk_amd_pll(1);
++ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
++ if (quirk_amdiso(ohci))
++ quirk_amd_pll(1);
++ if (quirk_amdprefetch(ohci))
++ sb800_prefetch(ohci, 0);
++ }
+ break;
+ case PIPE_INTERRUPT:
+ ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
+@@ -418,7 +421,7 @@
+ is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN);
+
+ /* FIXME usbcore changes dev->devnum before SET_ADDRESS
+- * suceeds ... otherwise we wouldn't need "pipe".
++ * succeeds ... otherwise we wouldn't need "pipe".
+ */
+ info = usb_pipedevice (pipe);
+ ed->type = usb_pipetype(pipe);
+@@ -680,9 +683,12 @@
+ data + urb->iso_frame_desc [cnt].offset,
+ urb->iso_frame_desc [cnt].length, urb, cnt);
+ }
+- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+- && quirk_amdiso(ohci))
+- quirk_amd_pll(0);
++ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
++ if (quirk_amdiso(ohci))
++ quirk_amd_pll(0);
++ if (quirk_amdprefetch(ohci))
++ sb800_prefetch(ohci, 1);
++ }
+ periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
+ && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
+ break;
+diff -ur linux-2.6.30.9/drivers/usb/host/pci-quirks.c linux-2.6.32.27/drivers/usb/host/pci-quirks.c
+--- linux-2.6.30.9/drivers/usb/host/pci-quirks.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/pci-quirks.c 2010-12-09 23:29:45.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/delay.h>
+ #include <linux/acpi.h>
+ #include "pci-quirks.h"
++#include "xhci-ext-caps.h"
+
+
+ #define UHCI_USBLEGSUP 0xc0 /* legacy support */
+@@ -341,7 +342,127 @@
+ return;
+ }
+
++/*
++ * handshake - spin reading a register until handshake completes
++ * @ptr: address of hc register to be read
++ * @mask: bits to look at in result of read
++ * @done: value of those bits when handshake succeeds
++ * @wait_usec: timeout in microseconds
++ * @delay_usec: delay in microseconds to wait between polling
++ *
++ * Polls a register every delay_usec microseconds.
++ * Returns 0 when the mask bits have the value done.
++ * Returns -ETIMEDOUT if this condition is not true after
++ * wait_usec microseconds have passed.
++ */
++static int handshake(void __iomem *ptr, u32 mask, u32 done,
++ int wait_usec, int delay_usec)
++{
++ u32 result;
++
++ do {
++ result = readl(ptr);
++ result &= mask;
++ if (result == done)
++ return 0;
++ udelay(delay_usec);
++ wait_usec -= delay_usec;
++ } while (wait_usec > 0);
++ return -ETIMEDOUT;
++}
++
++/**
++ * PCI Quirks for xHCI.
++ *
++ * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
++ * It signals to the BIOS that the OS wants control of the host controller,
++ * and then waits 5 seconds for the BIOS to hand over control.
++ * If we timeout, assume the BIOS is broken and take control anyway.
++ */
++static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
++{
++ void __iomem *base;
++ int ext_cap_offset;
++ void __iomem *op_reg_base;
++ u32 val;
++ int timeout;
++
++ if (!mmio_resource_enabled(pdev, 0))
++ return;
++
++ base = ioremap_nocache(pci_resource_start(pdev, 0),
++ pci_resource_len(pdev, 0));
++ if (base == NULL)
++ return;
+
++ /*
++ * Find the Legacy Support Capability register -
++ * this is optional for xHCI host controllers.
++ */
++ ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
++ do {
++ if (!ext_cap_offset)
++ /* We've reached the end of the extended capabilities */
++ goto hc_init;
++ val = readl(base + ext_cap_offset);
++ if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
++ break;
++ ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
++ } while (1);
++
++ /* If the BIOS owns the HC, signal that the OS wants it, and wait */
++ if (val & XHCI_HC_BIOS_OWNED) {
++ writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
++
++ /* Wait for 5 seconds with 10 microsecond polling interval */
++ timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
++ 0, 5000, 10);
++
++ /* Assume a buggy BIOS and take HC ownership anyway */
++ if (timeout) {
++ dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
++ " (BIOS bug ?) %08x\n", val);
++ writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
++ }
++ }
++
++ /* Disable any BIOS SMIs */
++ writel(XHCI_LEGACY_DISABLE_SMI,
++ base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
++
++hc_init:
++ op_reg_base = base + XHCI_HC_LENGTH(readl(base));
++
++ /* Wait for the host controller to be ready before writing any
++ * operational or runtime registers. Wait 5 seconds and no more.
++ */
++ timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
++ 5000, 10);
++ /* Assume a buggy HC and start HC initialization anyway */
++ if (timeout) {
++ val = readl(op_reg_base + XHCI_STS_OFFSET);
++ dev_warn(&pdev->dev,
++ "xHCI HW not ready after 5 sec (HC bug?) "
++ "status = 0x%x\n", val);
++ }
++
++ /* Send the halt and disable interrupts command */
++ val = readl(op_reg_base + XHCI_CMD_OFFSET);
++ val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
++ writel(val, op_reg_base + XHCI_CMD_OFFSET);
++
++ /* Wait for the HC to halt - poll every 125 usec (one microframe). */
++ timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
++ XHCI_MAX_HALT_USEC, 125);
++ if (timeout) {
++ val = readl(op_reg_base + XHCI_STS_OFFSET);
++ dev_warn(&pdev->dev,
++ "xHCI HW did not halt within %d usec "
++ "status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
++ }
++
++ iounmap(base);
++}
+
+ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
+ {
+@@ -351,5 +472,7 @@
+ quirk_usb_handoff_ohci(pdev);
+ else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
+ quirk_usb_disable_ehci(pdev);
++ else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
++ quirk_usb_handoff_xhci(pdev);
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+diff -ur linux-2.6.30.9/drivers/usb/host/uhci-hcd.c linux-2.6.32.27/drivers/usb/host/uhci-hcd.c
+--- linux-2.6.30.9/drivers/usb/host/uhci-hcd.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/uhci-hcd.c 2010-12-09 23:29:45.000000000 +0200
+@@ -67,7 +67,7 @@
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URBs except for stalls
+ * debug = 2, dump all failed URBs (including stalls)
+- * show all queues in /debug/uhci/[pci_addr]
++ * show all queues in /sys/kernel/debug/uhci/[pci_addr]
+ * debug = 3, show all TDs in URBs when dumping
+ */
+ #ifdef DEBUG
+@@ -735,6 +735,7 @@
+ uhci_hc_died(uhci);
+ uhci_scan_schedule(uhci);
+ spin_unlock_irq(&uhci->lock);
++ synchronize_irq(hcd->irq);
+
+ del_timer_sync(&uhci->fsbr_timer);
+ release_uhci(uhci);
+@@ -749,7 +750,20 @@
+ spin_lock_irq(&uhci->lock);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ rc = -ESHUTDOWN;
+- else if (!uhci->dead)
++ else if (uhci->dead)
++ ; /* Dead controllers tell no tales */
++
++ /* Once the controller is stopped, port resumes that are already
++ * in progress won't complete. Hence if remote wakeup is enabled
++ * for the root hub and any ports are in the middle of a resume or
++ * remote wakeup, we must fail the suspend.
++ */
++ else if (hcd->self.root_hub->do_remote_wakeup &&
++ uhci->resuming_ports) {
++ dev_dbg(uhci_dev(uhci), "suspend failed because a port "
++ "is resuming\n");
++ rc = -EBUSY;
++ } else
+ suspend_rh(uhci, UHCI_RH_SUSPENDED);
+ spin_unlock_irq(&uhci->lock);
+ return rc;
+@@ -769,7 +783,7 @@
+ return rc;
+ }
+
+-static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
++static int uhci_pci_suspend(struct usb_hcd *hcd)
+ {
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ int rc = 0;
+@@ -795,10 +809,6 @@
+
+ /* FIXME: Enable non-PME# remote wakeup? */
+
+- /* make sure snapshot being resumed re-enumerates everything */
+- if (message.event == PM_EVENT_PRETHAW)
+- uhci_hc_died(uhci);
+-
+ done_okay:
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ done:
+@@ -806,7 +816,7 @@
+ return rc;
+ }
+
+-static int uhci_pci_resume(struct usb_hcd *hcd)
++static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
+ {
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+@@ -820,6 +830,10 @@
+
+ spin_lock_irq(&uhci->lock);
+
++ /* Make sure resume from hibernation re-enumerates everything */
++ if (hibernated)
++ uhci_hc_died(uhci);
++
+ /* FIXME: Disable non-PME# remote wakeup? */
+
+ /* The firmware or a boot kernel may have changed the controller
+@@ -940,10 +954,11 @@
+ .remove = usb_hcd_pci_remove,
+ .shutdown = uhci_shutdown,
+
+-#ifdef CONFIG_PM
+- .suspend = usb_hcd_pci_suspend,
+- .resume = usb_hcd_pci_resume,
+-#endif /* PM */
++#ifdef CONFIG_PM_SLEEP
++ .driver = {
++ .pm = &usb_hcd_pci_pm_ops
++ },
++#endif
+ };
+
+ static int __init uhci_hcd_init(void)
+@@ -961,7 +976,7 @@
+ errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+ if (!errbuf)
+ goto errbuf_failed;
+- uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
++ uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root);
+ if (!uhci_debugfs_root)
+ goto debug_failed;
+ }
+diff -ur linux-2.6.30.9/drivers/usb/host/uhci-hub.c linux-2.6.32.27/drivers/usb/host/uhci-hub.c
+--- linux-2.6.30.9/drivers/usb/host/uhci-hub.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/uhci-hub.c 2010-12-09 23:29:45.000000000 +0200
+@@ -167,7 +167,7 @@
+ /* Port received a wakeup request */
+ set_bit(port, &uhci->resuming_ports);
+ uhci->ports_timeout = jiffies +
+- msecs_to_jiffies(20);
++ msecs_to_jiffies(25);
+
+ /* Make sure we see the port again
+ * after the resuming period is over. */
+diff -ur linux-2.6.30.9/drivers/usb/host/uhci-q.c linux-2.6.32.27/drivers/usb/host/uhci-q.c
+--- linux-2.6.30.9/drivers/usb/host/uhci-q.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/uhci-q.c 2010-12-09 23:29:45.000000000 +0200
+@@ -260,7 +260,7 @@
+ INIT_LIST_HEAD(&qh->node);
+
+ if (udev) { /* Normal QH */
+- qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++ qh->type = usb_endpoint_type(&hep->desc);
+ if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+ qh->dummy_td = uhci_alloc_td(uhci);
+ if (!qh->dummy_td) {
+@@ -1422,7 +1422,6 @@
+ goto err_submit_failed;
+
+ /* Add this URB to the QH */
+- urbp->qh = qh;
+ list_add_tail(&urbp->node, &qh->queue);
+
+ /* If the new URB is the first and only one on this QH then either
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/asl.c linux-2.6.32.27/drivers/usb/host/whci/asl.c
+--- linux-2.6.30.9/drivers/usb/host/whci/asl.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/asl.c 2010-12-09 23:29:45.000000000 +0200
+@@ -115,6 +115,10 @@
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
++ /* A halted qTD always triggers an update
++ because the qset was either removed or
++ reactivated. */
++ update |= WHC_UPDATE_UPDATED;
+ goto done;
+ }
+
+@@ -227,11 +231,21 @@
+ /*
+ * Now that the ASL is updated, complete the removal of any
+ * removed qsets.
++ *
++ * If the qset was to be reset, do so and reinsert it into the
++ * ASL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
++ if (qset->reset) {
++ qset_reset(whc, qset);
++ if (!list_empty(&qset->stds)) {
++ asl_qset_insert_begin(whc, qset);
++ queue_work(whc->workqueue, &whc->async_work);
++ }
++ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+@@ -267,7 +281,7 @@
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+- if (!qset->in_sw_list)
++ if (!qset->in_sw_list && !qset->remove)
+ asl_qset_insert_begin(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+@@ -295,6 +309,7 @@
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
++ bool has_qtd = false;
+ int ret;
+ unsigned long flags;
+
+@@ -305,17 +320,21 @@
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+- if (std->urb == urb)
++ if (std->urb == urb) {
++ if (std->qtd)
++ has_qtd = true;
+ qset_free_std(whc, std);
+- else
++ } else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+- asl_qset_remove(whc, qset);
+- wurb->status = status;
+- wurb->is_async = true;
+- queue_work(whc->workqueue, &wurb->dequeue_work);
+-
++ if (has_qtd) {
++ asl_qset_remove(whc, qset);
++ wurb->status = status;
++ wurb->is_async = true;
++ queue_work(whc->workqueue, &wurb->dequeue_work);
++ } else
++ qset_remove_urb(whc, qset, urb, status);
+ out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/debug.c linux-2.6.32.27/drivers/usb/host/whci/debug.c
+--- linux-2.6.30.9/drivers/usb/host/whci/debug.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/debug.c 2010-12-09 23:29:45.000000000 +0200
+@@ -134,7 +134,7 @@
+ return single_open(file, pzl_print, inode->i_private);
+ }
+
+-static struct file_operations di_fops = {
++static const struct file_operations di_fops = {
+ .open = di_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -142,7 +142,7 @@
+ .owner = THIS_MODULE,
+ };
+
+-static struct file_operations asl_fops = {
++static const struct file_operations asl_fops = {
+ .open = asl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+@@ -150,7 +150,7 @@
+ .owner = THIS_MODULE,
+ };
+
+-static struct file_operations pzl_fops = {
++static const struct file_operations pzl_fops = {
+ .open = pzl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/hcd.c linux-2.6.32.27/drivers/usb/host/whci/hcd.c
+--- linux-2.6.30.9/drivers/usb/host/whci/hcd.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/hcd.c 2010-12-09 23:29:45.000000000 +0200
+@@ -192,19 +192,23 @@
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct whc_qset *qset;
++ unsigned long flags;
++
++ spin_lock_irqsave(&whc->lock, flags);
+
+ qset = ep->hcpriv;
+ if (qset) {
+ qset->remove = 1;
++ qset->reset = 1;
+
+ if (usb_endpoint_xfer_bulk(&ep->desc)
+ || usb_endpoint_xfer_control(&ep->desc))
+ queue_work(whc->workqueue, &whc->async_work);
+ else
+ queue_work(whc->workqueue, &whc->periodic_work);
+-
+- qset_reset(whc, qset);
+ }
++
++ spin_unlock_irqrestore(&whc->lock, flags);
+ }
+
+
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/pzl.c linux-2.6.32.27/drivers/usb/host/whci/pzl.c
+--- linux-2.6.30.9/drivers/usb/host/whci/pzl.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/pzl.c 2010-12-09 23:29:45.000000000 +0200
+@@ -121,6 +121,10 @@
+ if (status & QTD_STS_HALTED) {
+ /* Ug, an error. */
+ process_halted_qtd(whc, qset, td);
++ /* A halted qTD always triggers an update
++ because the qset was either removed or
++ reactivated. */
++ update |= WHC_UPDATE_UPDATED;
+ goto done;
+ }
+
+@@ -255,11 +259,21 @@
+ /*
+ * Now that the PZL is updated, complete the removal of any
+ * removed qsets.
++ *
++ * If the qset was to be reset, do so and reinsert it into the
++ * PZL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
++ if (qset->reset) {
++ qset_reset(whc, qset);
++ if (!list_empty(&qset->stds)) {
++ qset_insert_in_sw_list(whc, qset);
++ queue_work(whc->workqueue, &whc->periodic_work);
++ }
++ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+@@ -295,7 +309,7 @@
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+- if (!qset->in_sw_list)
++ if (!qset->in_sw_list && !qset->remove)
+ qset_insert_in_sw_list(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+@@ -323,6 +337,7 @@
+ struct whc_urb *wurb = urb->hcpriv;
+ struct whc_qset *qset = wurb->qset;
+ struct whc_std *std, *t;
++ bool has_qtd = false;
+ int ret;
+ unsigned long flags;
+
+@@ -333,17 +348,22 @@
+ goto out;
+
+ list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+- if (std->urb == urb)
++ if (std->urb == urb) {
++ if (std->qtd)
++ has_qtd = true;
+ qset_free_std(whc, std);
+- else
++ } else
+ std->qtd = NULL; /* so this std is re-added when the qset is */
+ }
+
+- pzl_qset_remove(whc, qset);
+- wurb->status = status;
+- wurb->is_async = false;
+- queue_work(whc->workqueue, &wurb->dequeue_work);
+-
++ if (has_qtd) {
++ pzl_qset_remove(whc, qset);
++ update_pzl_hw_view(whc);
++ wurb->status = status;
++ wurb->is_async = false;
++ queue_work(whc->workqueue, &wurb->dequeue_work);
++ } else
++ qset_remove_urb(whc, qset, urb, status);
+ out:
+ spin_unlock_irqrestore(&whc->lock, flags);
+
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/qset.c linux-2.6.32.27/drivers/usb/host/whci/qset.c
+--- linux-2.6.30.9/drivers/usb/host/whci/qset.c 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/qset.c 2010-12-09 23:29:45.000000000 +0200
+@@ -103,7 +103,6 @@
+ void qset_clear(struct whc *whc, struct whc_qset *qset)
+ {
+ qset->td_start = qset->td_end = qset->ntds = 0;
+- qset->remove = 0;
+
+ qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
+ qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
+@@ -125,7 +124,7 @@
+ */
+ void qset_reset(struct whc *whc, struct whc_qset *qset)
+ {
+- wait_for_completion(&qset->remove_complete);
++ qset->reset = 0;
+
+ qset->qh.status &= ~QH_STATUS_SEQ_MASK;
+ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+@@ -156,6 +155,7 @@
+
+ void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
+ {
++ qset->remove = 0;
+ list_del_init(&qset->list_node);
+ complete(&qset->remove_complete);
+ }
+diff -ur linux-2.6.30.9/drivers/usb/host/whci/whci-hc.h linux-2.6.32.27/drivers/usb/host/whci/whci-hc.h
+--- linux-2.6.30.9/drivers/usb/host/whci/whci-hc.h 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/drivers/usb/host/whci/whci-hc.h 2010-12-09 23:29:45.000000000 +0200
+@@ -264,6 +264,7 @@
+ unsigned in_sw_list:1;
+ unsigned in_hw_list:1;
+ unsigned remove:1;
++ unsigned reset:1;
+ struct urb *pause_after_urb;
+ struct completion remove_complete;
+ int max_burst;
+--- linux-2.6.30.9/include/linux/usb/ehci_def.h 2009-10-05 18:38:08.000000000 +0300
++++ linux-2.6.32.27/include/linux/usb/ehci_def.h 2010-12-09 23:29:45.000000000 +0200
+@@ -105,6 +105,7 @@
+ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+ #define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+ /* 19:16 for port testing */
++#define PORT_TEST_PKT (0x4<<16) /* Port Test Control - packet test */
+ #define PORT_LED_OFF (0<<14)
+ #define PORT_LED_AMBER (1<<14)
+ #define PORT_LED_GREEN (2<<14)
+@@ -132,6 +133,19 @@
+ #define USBMODE_CM_HC (3<<0) /* host controller mode */
+ #define USBMODE_CM_IDLE (0<<0) /* idle state */
+
++/* Moorestown has some non-standard registers, partially due to the fact that
++ * its EHCI controller has both TT and LPM support. HOSTPCx are extentions to
++ * PORTSCx
++ */
++#define HOSTPC0 0x84 /* HOSTPC extension */
++#define HOSTPC_PHCD (1<<22) /* Phy clock disable */
++#define HOSTPC_PSPD (3<<25) /* Port speed detection */
++#define USBMODE_EX 0xc8 /* USB Device mode extension */
++#define USBMODE_EX_VBPS (1<<5) /* VBus Power Select On */
++#define USBMODE_EX_HC (3<<0) /* host controller mode */
++#define TXFILLTUNING 0x24 /* TX FIFO Tuning register */
++#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
++
+ /* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+@@ -157,4 +171,25 @@
+ #define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+ } __attribute__ ((packed));
+
++#ifdef CONFIG_EARLY_PRINTK_DBGP
++#include <linux/init.h>
++extern int __init early_dbgp_init(char *s);
++extern struct console early_dbgp_console;
++#endif /* CONFIG_EARLY_PRINTK_DBGP */
++
++#ifdef CONFIG_EARLY_PRINTK_DBGP
++/* Call backs from ehci host driver to ehci debug driver */
++extern int dbgp_external_startup(void);
++extern int dbgp_reset_prep(void);
++#else
++static inline int dbgp_reset_prep(void)
++{
++ return 1;
++}
++static inline int dbgp_external_startup(void)
++{
++ return -1;
++}
++#endif
++
+ #endif /* __LINUX_USB_EHCI_DEF_H */
diff --git a/target/linux/realtek/patches-2.6.30/300-dont-ask-for-usb-serial-option-define.patch b/target/linux/realtek/patches-2.6.30/300-dont-ask-for-usb-serial-option-define.patch
deleted file mode 100644
index 30047fd6a..000000000
--- a/target/linux/realtek/patches-2.6.30/300-dont-ask-for-usb-serial-option-define.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- a/drivers/usb/serial/usb-serial.c 2012-10-08 07:02:14.450118292 +0300
-+++ a/drivers/usb/serial/usb-serial.c 2012-10-08 07:02:24.720154214 +0300
-@@ -35,9 +35,7 @@
- #include <linux/usb/serial.h>
- #include "pl2303.h"
-
--#if CONFIG_USB_SERIAL_OPTION
- #include <linux/smp_lock.h> /* brucehou, 2010/05/21, for lock_kernel & unlock_kernel */
--#endif
-
- /*
- * Version Information
diff --git a/target/linux/realtek/patches-2.6.30/9995-net-rtl819x-include-paths.patch b/target/linux/realtek/patches-2.6.30/9995-net-rtl819x-include-paths.patch
index 2710b56cc..239686707 100644
--- a/target/linux/realtek/patches-2.6.30/9995-net-rtl819x-include-paths.patch
+++ b/target/linux/realtek/patches-2.6.30/9995-net-rtl819x-include-paths.patch
@@ -370,17 +370,6 @@
#endif
#ifdef CONFIG_RTL_PROC_DEBUG
---- a/drivers/usb/host/usb-rtl8652.h 2012-12-03 00:13:21.000000000 +0200
-+++ b/drivers/usb/host/usb-rtl8652.h 2013-02-06 02:05:03.071754444 +0200
-@@ -15,7 +15,7 @@
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
--#include <bsp/bspchip.h>
-+#include "../../../arch/rlx/bsp/bspchip.h"
- #ifndef _USB_RTL8652_H
- #define _USB_RTL8652_H
- #define PADDR(addr) ((addr) & 0x1FFFFFFF)
--- a/net/rtl/fastpath/fastpath_common.c 2013-02-04 03:15:32.875227255 +0200
+++ b/net/rtl/fastpath/fastpath_common.c 2013-02-06 02:09:07.638365005 +0200
@@ -6,7 +6,7 @@