[USBEHCI]
[reactos.git] / drivers / usb / usbehci_new / hardware.cpp
index 99dd9fe..9ae3e9f 100644 (file)
@@ -80,6 +80,13 @@ public:
 
     KIRQL AcquireDeviceLock(void);
     VOID ReleaseDeviceLock(KIRQL OldLevel);
+    // set command
+    VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
+
+    // get command
+    VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
+
+
     // local
     BOOLEAN InterruptService();
 
@@ -114,14 +121,10 @@ protected:
     HD_INIT_CALLBACK* m_SCECallBack;                                                   // status change callback routine
     PVOID m_SCEContext;                                                                // status change callback routine context
     BOOLEAN m_DoorBellRingInProgress;                                                  // door bell ring in progress
-    EHCI_PORT_STATUS m_PortStatus[16];                                                 // port status
     WORK_QUEUE_ITEM m_StatusChangeWorkItem;                                            // work item for status change callback
-
-    // set command
-    VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
-
-    // get command
-    VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
+    ULONG m_SyncFramePhysAddr;                                                         // periodic frame list physical address
+    BOOLEAN m_ResetInProgress[16];                                                     // set when a reset is in progress
+    BUS_INTERFACE_STANDARD m_BusInterface;                                             // pci bus interface
 
     // read register
     ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
@@ -156,7 +159,6 @@ CUSBHardwareDevice::Initialize(
     PDEVICE_OBJECT PhysicalDeviceObject,
     PDEVICE_OBJECT LowerDeviceObject)
 {
-    BUS_INTERFACE_STANDARD BusInterface;
     PCI_COMMON_CONFIG PciConfig;
     NTSTATUS Status;
     ULONG BytesRead;
@@ -204,14 +206,14 @@ CUSBHardwareDevice::Initialize(
     m_VendorID = 0;
     m_DeviceID = 0;
 
-    Status = GetBusInterface(PhysicalDeviceObject, &BusInterface);
+    Status = GetBusInterface(PhysicalDeviceObject, &m_BusInterface);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to get BusInteface!\n");
         return Status;
     }
 
-    BytesRead = (*BusInterface.GetBusData)(BusInterface.Context,
+    BytesRead = (*m_BusInterface.GetBusData)(m_BusInterface.Context,
                                            PCI_WHICHSPACE_CONFIG,
                                            &PciConfig,
                                            0,
@@ -223,14 +225,42 @@ CUSBHardwareDevice::Initialize(
         return STATUS_SUCCESS;
     }
 
-    if (!(PciConfig.Command & PCI_ENABLE_BUS_MASTER))
+    m_VendorID = PciConfig.VendorID;
+    m_DeviceID = PciConfig.DeviceID;
+
+
+    if (PciConfig.Command & PCI_ENABLE_BUS_MASTER)
     {
-        DPRINT1("PCI Configuration shows this as a non Bus Mastering device!\n");
+        //
+        // master is enabled
+        //
+        return STATUS_SUCCESS;
     }
 
-    m_VendorID = PciConfig.VendorID;
-    m_DeviceID = PciConfig.DeviceID;
+     DPRINT1("PCI Configuration shows this as a non Bus Mastering device! Enabling...\n");
+
+     PciConfig.Command |= PCI_ENABLE_BUS_MASTER;
+     m_BusInterface.SetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
+
+     BytesRead = (*m_BusInterface.GetBusData)(m_BusInterface.Context,
+                                            PCI_WHICHSPACE_CONFIG,
+                                            &PciConfig,
+                                            0,
+                                            PCI_COMMON_HDR_LENGTH);
+
+    if (BytesRead != PCI_COMMON_HDR_LENGTH)
+    {
+        DPRINT1("Failed to get pci config information!\n");
+        ASSERT(FALSE);
+        return STATUS_SUCCESS;
+    }
 
+    if (!(PciConfig.Command & PCI_ENABLE_BUS_MASTER))
+    {
+        PciConfig.Command |= PCI_ENABLE_BUS_MASTER;
+        DPRINT1("Failed to enable master\n");
+        return STATUS_UNSUCCESSFUL;
+    }
     return STATUS_SUCCESS;
 }
 
@@ -273,6 +303,8 @@ CUSBHardwareDevice::PnpStart(
     PHYSICAL_ADDRESS AsyncPhysicalAddress;
     PVOID ResourceBase;
     NTSTATUS Status;
+    UCHAR Value;
+    UCHAR PortCount;
 
     DPRINT1("CUSBHardwareDevice::PnpStart\n");
     for(Index = 0; Index < TranslatedResources->List[0].PartialResourceList.Count; Index++)
@@ -330,19 +362,35 @@ CUSBHardwareDevice::PnpStart(
                 //
                 // Get controllers capabilities 
                 //
-                m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase);
-                m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + 2));
-                m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 4));
-                m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8));
+                m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase + EHCI_CAPLENGTH);
+                m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + EHCI_HCIVERSION));
+                m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + EHCI_HCSPARAMS));
+                m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + EHCI_HCCPARAMS));
 
+                DPRINT1("Controller has %d Length\n", m_Capabilities.Length);
                 DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
                 DPRINT1("Controller EHCI Version %x\n", m_Capabilities.HCIVersion);
+                DPRINT1("Controler EHCI Caps HCSParamsLong %x\n", m_Capabilities.HCSParamsLong);
+                DPRINT1("Controler EHCI Caps HCCParamsLong %x\n", m_Capabilities.HCCParamsLong);
+                DPRINT1("Controler EHCI Caps PowerControl %x\n", m_Capabilities.HCSParams.PortPowerControl);
+
                 if (m_Capabilities.HCSParams.PortRouteRules)
                 {
-                    for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
+                    Count = 0;
+                    PortCount = max(m_Capabilities.HCSParams.PortCount/2, (m_Capabilities.HCSParams.PortCount+1)/2);
+                    do
                     {
-                        m_Capabilities.PortRoute[Count] = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + 12 + Count);
-                    }
+                        //
+                        // each entry is a 4 bit field EHCI 2.2.5
+                        //
+                        Value = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + EHCI_HCSP_PORTROUTE + Count);
+                        m_Capabilities.PortRoute[Count*2] = (Value & 0xF0);
+
+                        if ((Count*2) + 1 < m_Capabilities.HCSParams.PortCount)
+                            m_Capabilities.PortRoute[(Count*2)+1] = (Value & 0x0F);
+
+                        Count++;
+                    }while(Count < PortCount);
                 }
 
                 //
@@ -437,7 +485,7 @@ CUSBHardwareDevice::PnpStart(
     //
     // Initialize the UsbQueue now that we have an AdapterObject.
     //
-    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL);
+    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, &m_Lock);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to Initialize the UsbQueue\n");
@@ -514,73 +562,179 @@ NTSTATUS
 CUSBHardwareDevice::StartController(void)
 {
     EHCI_USBCMD_CONTENT UsbCmd;
-    ULONG UsbSts, FailSafe;
+    ULONG UsbSts, FailSafe, ExtendedCapsSupport, Caps, Index;
+    UCHAR Value;
+    LARGE_INTEGER Timeout;
 
+    //
+    // check caps
+    //
+    if (m_Capabilities.HCCParams.CurAddrBits)
+    {
+        //
+        // disable 64-bit addressing
+        //
+        EHCI_WRITE_REGISTER_ULONG(EHCI_CTRLDSSEGMENT, 0x0);
+    }
+
+    //
+    // are extended caps supported
+    //
+    ExtendedCapsSupport = (m_Capabilities.HCCParamsLong >> EHCI_ECP_SHIFT) & EHCI_ECP_MASK;
+    if (ExtendedCapsSupport)
+    {
+        DPRINT1("[EHCI] Extended Caps Support detected!\n");
+
+        //
+        // sanity check
+        //
+        ASSERT(ExtendedCapsSupport >= PCI_COMMON_HDR_LENGTH);
+        m_BusInterface.GetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Caps, ExtendedCapsSupport, sizeof(ULONG));
+
+        //
+        // OS Handoff Synchronization support capability. EHCI 5.1
+        //
+        if ((Caps & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID)
+        {
+            //
+            // is it bios owned
+            //
+            if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+            {
+                DPRINT1("[EHCI] Controller is BIOS owned, acquring control\n");
+
+                //
+                // acquire ownership
+                //
+                Value = 1;
+                m_BusInterface.SetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Value, ExtendedCapsSupport+3, sizeof(UCHAR));
+
+                for(Index = 0; Index < 20; Index++)
+                {
+                    //
+                    // get status
+                    //
+                    m_BusInterface.GetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Caps, ExtendedCapsSupport, sizeof(ULONG));
+                    if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+                    {
+                        //
+                        // lets wait a bit
+                        //
+                        Timeout.QuadPart = 50;
+                        DPRINT1("Waiting %d milliseconds for port reset\n", Timeout.LowPart);
+
+                        //
+                        // convert to 100 ns units (absolute)
+                        //
+                        Timeout.QuadPart *= -10000;
+
+                        //
+                        // perform the wait
+                        //
+                        KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+                    }
+                }
+                if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+                {
+                    //
+                    // failed to aquire ownership
+                    //
+                    DPRINT1("[EHCI] failed to acquire ownership\n");
+                }
+                else if ((Caps & EHCI_LEGSUP_OSOWNED))
+                {
+                    //
+                    // HC OS Owned Semaphore EHCI 2.1.8
+                    //
+                    DPRINT1("[EHCI] acquired ownership\n");
+                }
+            }
+        }
+    }
+
+
+
+#if 1
     //
     // Stop the controller if its running
     //
     UsbSts = EHCI_READ_REGISTER_ULONG(EHCI_USBSTS);
     if (!(UsbSts & EHCI_STS_HALT))
+    {
+        DPRINT1("Stopping Controller %x\n", UsbSts);
         StopController();
+    }
+#endif
 
     //
-    // Reset the device. Bit is set to 0 on completion.
+    // Enable Interrupts and start execution
     //
-    GetCommandRegister(&UsbCmd);
-    UsbCmd.HCReset = TRUE;
+    ULONG Mask = EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR | EHCI_USBINTR_PC;
+    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, Mask);
+
+    KeStallExecutionProcessor(10);
+
+    ULONG Status = EHCI_READ_REGISTER_ULONG(EHCI_USBINTR);
+
+    DPRINT1("Interrupt Mask %x\n", Status);
+    ASSERT((Status & Mask) == Mask);
+
+
+    //
+    // Assign the SyncList Register
+    //
+    EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, m_SyncFramePhysAddr);
+
+    //
+    // Set Schedules to Enable and Interrupt Threshold to 1ms.
+    //
+    RtlZeroMemory(&UsbCmd, sizeof(EHCI_USBCMD_CONTENT));
+
+    UsbCmd.PeriodicEnable = TRUE;
+    UsbCmd.IntThreshold = 0x8; //1ms
+    UsbCmd.Run = TRUE;
+    UsbCmd.FrameListSize = 0x0; //1024
     SetCommandRegister(&UsbCmd);
 
     //
-    // Check that the controller reset
+    // Wait for execution to start
     //
     for (FailSafe = 100; FailSafe > 1; FailSafe--)
     {
         KeStallExecutionProcessor(10);
-        GetCommandRegister(&UsbCmd);
-        if (!UsbCmd.HCReset)
+        UsbSts = EHCI_READ_REGISTER_ULONG(EHCI_USBSTS);
+
+        if (!(UsbSts & EHCI_STS_HALT))
         {
             break;
         }
     }
 
-    //
-    // If the controller did not reset then fail
-    //
-    if (UsbCmd.HCReset)
+
+    if (UsbSts & EHCI_STS_HALT)
     {
-        DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n");
+        DPRINT1("Could not start execution on the controller\n");
         return STATUS_UNSUCCESSFUL;
     }
 
-    //
-    // Disable Interrupts and clear status
-    //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0);
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f);
-
     //
     // Assign the AsyncList Register
     //
     EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, AsyncQueueHead->PhysicalAddr);
 
     //
-    // Set Schedules to Enable and Interrupt Threshold to 1ms.
+    // get command register
     //
     GetCommandRegister(&UsbCmd);
-    UsbCmd.PeriodicEnable = FALSE;
-    UsbCmd.AsyncEnable = TRUE;  //FIXME: Need USB Memory Manager
-
-    UsbCmd.IntThreshold = 1;
-    // FIXME: Set framelistsize when periodic is implemented.
-    SetCommandRegister(&UsbCmd);
 
     //
-    // Enable Interrupts and start execution
+    // preserve bits
     //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
-        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
+    UsbCmd.AsyncEnable = TRUE;
 
-    UsbCmd.Run = TRUE;
+    //
+    // enable async
+    //
     SetCommandRegister(&UsbCmd);
 
     //
@@ -591,18 +745,28 @@ CUSBHardwareDevice::StartController(void)
         KeStallExecutionProcessor(10);
         UsbSts = EHCI_READ_REGISTER_ULONG(EHCI_USBSTS);
 
-        if (!(UsbSts & EHCI_STS_HALT))
+        if ((UsbSts & EHCI_STS_ASS))
         {
             break;
         }
     }
 
-    if (UsbSts & EHCI_STS_HALT)
+    if (!(UsbSts & EHCI_STS_ASS))
     {
-        DPRINT1("Could not start execution on the controller\n");
+        DPRINT1("Failed to enable async schedule UsbSts %x\n", UsbSts);
+        ASSERT(FALSE);
         return STATUS_UNSUCCESSFUL;
     }
 
+    DPRINT1("UsbSts %x\n", UsbSts);
+    GetCommandRegister(&UsbCmd);
+
+    DPRINT1("UsbCmd.PeriodicEnable %x\n", UsbCmd.PeriodicEnable);
+    DPRINT1("UsbCmd.AsyncEnable %x\n", UsbCmd.AsyncEnable);
+    DPRINT1("UsbCmd.IntThreshold %x\n", UsbCmd.IntThreshold);
+    DPRINT1("UsbCmd.Run %x\n", UsbCmd.Run);
+    DPRINT1("UsbCmd.FrameListSize %x\n", UsbCmd.FrameListSize);
+
     //
     // Set port routing to EHCI controller
     //
@@ -658,11 +822,15 @@ CUSBHardwareDevice::ResetPort(
     IN ULONG PortIndex)
 {
     ULONG PortStatus;
+    LARGE_INTEGER Timeout;
 
     if (PortIndex > m_Capabilities.HCSParams.PortCount)
         return STATUS_UNSUCCESSFUL;
 
     PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
+    //
+    // check slow speed line before reset
+    //
     if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
     {
         DPRINT1("Non HighSpeed device. Releasing Ownership\n");
@@ -670,6 +838,8 @@ CUSBHardwareDevice::ResetPort(
         return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    ASSERT(PortStatus & EHCI_PRT_CONNECTED);
+
     //
     // Reset and clean enable
     //
@@ -677,7 +847,21 @@ CUSBHardwareDevice::ResetPort(
     PortStatus &= ~EHCI_PRT_ENABLED;
     EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
 
-    KeStallExecutionProcessor(100);
+    //
+    // delay is 20 ms for port reset as per USB 2.0 spec
+    //
+    Timeout.QuadPart = 20;
+    DPRINT1("Waiting %d milliseconds for port reset\n", Timeout.LowPart);
+
+    //
+    // convert to 100 ns units (absolute)
+    //
+    Timeout.QuadPart *= -10000;
+
+    //
+    // perform the wait
+    //
+    KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
 
     //
     // Clear reset
@@ -686,18 +870,53 @@ CUSBHardwareDevice::ResetPort(
     PortStatus &= ~EHCI_PRT_RESET;
     EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
 
-    KeStallExecutionProcessor(100);
+    do
+    {
+        //
+        // wait
+        //
+        KeStallExecutionProcessor(100);
+
+        //
+        // Check that the port reset
+        //
+        PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
+        if (!(PortStatus & EHCI_PRT_RESET))
+            break;
+    } while (TRUE);
+
+    //
+    // delay is 10 ms
+    //
+    Timeout.QuadPart = 10;
+    DPRINT1("Waiting %d milliseconds for port to recover after reset\n", Timeout.LowPart);
 
     //
-    // Check that the port reset
+    // convert to 100 ns units (absolute)
+    //
+    Timeout.QuadPart *= -10000;
+
+    //
+    // perform the wait
+    //
+    KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+
+    //
+    // check slow speed line after reset
     //
     PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
-    if (PortStatus & EHCI_PRT_RESET)
+    if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
     {
-        DPRINT1("Port did not reset\n");
-        return STATUS_RETRY;
+        DPRINT1("Non HighSpeed device. Releasing Ownership\n");
+        EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), EHCI_PRT_RELEASEOWNERSHIP);
+        return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    //
+    // this must be enabled now
+    //
+    ASSERT(PortStatus & EHCI_PRT_ENABLED);
+
     return STATUS_SUCCESS;
 }
 
@@ -707,13 +926,12 @@ CUSBHardwareDevice::GetPortStatus(
     OUT USHORT *PortStatus,
     OUT USHORT *PortChange)
 {
-#if 0
     ULONG Value;
     USHORT Status = 0, Change = 0;
 
     if (PortId > m_Capabilities.HCSParams.PortCount)
         return STATUS_UNSUCCESSFUL;
-    
+
     //
     // Get the value of the Port Status and Control Register
     //
@@ -734,16 +952,18 @@ CUSBHardwareDevice::GetPortStatus(
         }
     }
 
-    // Get Speed. If SlowSpeedLine flag is there then its a slow speed device
-    if (Value & EHCI_PRT_SLOWSPEEDLINE)
-        Status |= USB_PORT_STATUS_LOW_SPEED;
-    else
-        Status |= USB_PORT_STATUS_HIGH_SPEED;
-
     // Get Connected Status
     if (Value & EHCI_PRT_CONNECTED)
+    {
         Status |= USB_PORT_STATUS_CONNECT;
 
+        // Get Speed. If SlowSpeedLine flag is there then its a slow speed device
+        if (Value & EHCI_PRT_SLOWSPEEDLINE)
+            Status |= USB_PORT_STATUS_LOW_SPEED;
+        else
+            Status |= USB_PORT_STATUS_HIGH_SPEED;
+    }
+
     // Get Enabled Status
     if (Value & EHCI_PRT_ENABLED)
         Status |= USB_PORT_STATUS_ENABLE;
@@ -757,8 +977,11 @@ CUSBHardwareDevice::GetPortStatus(
         Status |= USB_PORT_STATUS_OVER_CURRENT;
 
     // In a reset state?
-    if (Value & EHCI_PRT_RESET)
+    if ((Value & EHCI_PRT_RESET) || m_ResetInProgress[PortId])
+    {
         Status |= USB_PORT_STATUS_RESET;
+        Change |= USB_PORT_STATUS_RESET;
+    }
 
     //
     // FIXME: Is the Change here correct?
@@ -771,10 +994,7 @@ CUSBHardwareDevice::GetPortStatus(
 
     *PortStatus = Status;
     *PortChange = Change;
-#else
-    *PortStatus = m_PortStatus[PortId].PortStatus;
-    *PortChange = m_PortStatus[PortId].PortChange;
-#endif
+
     return STATUS_SUCCESS;
 }
 
@@ -790,32 +1010,40 @@ CUSBHardwareDevice::ClearPortStatus(
     if (PortId > m_Capabilities.HCSParams.PortCount)
         return STATUS_UNSUCCESSFUL;
 
-    Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
-
     if (Status == C_PORT_RESET)
     {
-        if (Value & EHCI_PRT_RESET)
-        {
-            Value &= ~EHCI_PRT_RESET;
-            EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
-            KeStallExecutionProcessor(100);
-
-            //
-            // update port status
-            //
-            m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_RESET;
-            m_PortStatus[PortId].PortStatus |= USB_PORT_STATUS_ENABLE;
-        }
+        //
+        // update port status
+        //
+        m_ResetInProgress[PortId] = FALSE;
     }
 
     if (Status == C_PORT_CONNECTION)
     {
-        // FIXME: Make sure its the Connection and Enable Change status.
-        Value |= EHCI_PRT_CONNECTSTATUSCHANGE;
-        Value |= EHCI_PRT_ENABLEDSTATUSCHANGE;
+        LARGE_INTEGER Timeout;
+
+        //
+        // reset status change bits
+        //
+        Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
+        Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE;
         EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
 
-        m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_CONNECT;
+        //
+        // delay is 100 ms
+        //
+        Timeout.QuadPart = 100;
+        DPRINT1("Waiting %d milliseconds for port to stabilize after connection\n", Timeout.LowPart);
+
+        //
+        // convert to 100 ns units (absolute)
+        //
+        Timeout.QuadPart *= -10000;
+
+        //
+        // perform the wait
+        //
+        KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
     }
 
     return STATUS_SUCCESS;
@@ -843,21 +1071,15 @@ CUSBHardwareDevice::SetPortFeature(
         //
         DPRINT1("PORT_ENABLE not supported for EHCI\n");
     }
-    
+
     if (Feature == PORT_RESET)
     {
-        if (Value & EHCI_PRT_SLOWSPEEDLINE)
-        {
-            DPRINT1("Non HighSpeed device. Releasing Ownership\n");
-        }
-
         ResetPort(PortId);
 
         //
         // update cached settings
         //
-        m_PortStatus[PortId].PortChange |= USB_PORT_STATUS_RESET;
-        m_PortStatus[PortId].PortStatus &= ~USB_PORT_STATUS_ENABLE;
+        m_ResetInProgress[PortId] = TRUE;
 
         //
         // is there a status change callback
@@ -870,10 +1092,37 @@ CUSBHardwareDevice::SetPortFeature(
             m_SCECallBack(m_SCEContext);
         }
     }
-    
+
     if (Feature == PORT_POWER)
-        DPRINT1("PORT_POWER Not implemented\n");
+    {
+        if (m_Capabilities.HCSParams.PortPowerControl)
+        {
+            ULONG Value;
+            LARGE_INTEGER Timeout;
 
+            //
+            // enable port power
+            //
+            Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)) | EHCI_PRT_POWER;
+            EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC, Value);
+
+            //
+            // delay is 20 ms
+            //
+            Timeout.QuadPart = 20;
+            DPRINT1("Waiting %d milliseconds for port power up\n", Timeout.LowPart);
+
+            //
+            // convert to 100 ns units (absolute)
+            //
+            Timeout.QuadPart *= -10000;
+
+            //
+            // perform the wait
+            //
+            KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+        }
+    }
     return STATUS_SUCCESS;
 }
 
@@ -888,7 +1137,10 @@ VOID
 CUSBHardwareDevice::SetPeriodicListRegister(
     ULONG PhysicalAddress)
 {
-    EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, PhysicalAddress);
+    //
+    // store physical address
+    //
+    m_SyncFramePhysAddr = PhysicalAddress;
 }
 
 struct _QUEUE_HEAD *
@@ -997,6 +1249,7 @@ EhciDefferedRoutine(
     This = (CUSBHardwareDevice*) SystemArgument1;
     CStatus = (ULONG) SystemArgument2;
 
+       DPRINT("CStatus %x\n", CStatus);
 
     //
     // check for completion of async schedule
@@ -1013,8 +1266,10 @@ EhciDefferedRoutine(
                 //
                 // controller reported error
                 //
+                DPRINT1("CStatus %x\n", CStatus);
                 Status = STATUS_UNSUCCESSFUL;
                 PC_ASSERT(FALSE);
+                return;
             }
 
             //
@@ -1083,11 +1338,6 @@ EhciDefferedRoutine(
             //
             if (PortStatus & EHCI_PRT_CONNECTSTATUSCHANGE)
             {
-                //
-                // Clear the port change status
-                //
-                //This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_CONNECTSTATUSCHANGE);
-
                 if (PortStatus & EHCI_PRT_CONNECTED)
                 {
                     DPRINT1("Device connected on port %d\n", i);
@@ -1109,30 +1359,23 @@ EhciDefferedRoutine(
                             continue;
                         }
                     }
-
-                    //
-                    // update port status flags
-                    //
-                    This->m_PortStatus[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
-                    This->m_PortStatus[i].PortStatus |= USB_PORT_STATUS_CONNECT;
-                    This->m_PortStatus[i].PortChange |= USB_PORT_STATUS_CONNECT;
-
-                    //
-                    // is there a status change callback
-                    //
-                    if (This->m_SCECallBack != NULL)
-                    {
-                        //
-                        // queue work item for processing
-                        //
-                        ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
-                    }
                 }
                 else
                 {
                     DPRINT1("Device disconnected on port %d\n", i);
                 }
 
+                //
+                // is there a status change callback
+                //
+                if (This->m_SCECallBack != NULL)
+                {
+                    //
+                    // queue work item for processing
+                    //
+                    ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
+                }
+
                 //
                 // FIXME: This needs to be saved somewhere
                 //