[USB] Update the names of new USB drivers
[reactos.git] / drivers / usb / usbehci / roothub.c
diff --git a/drivers/usb/usbehci/roothub.c b/drivers/usb/usbehci/roothub.c
new file mode 100644 (file)
index 0000000..67b39bf
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * PROJECT:     ReactOS USB EHCI Miniport Driver
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     USBEHCI root hub functions
+ * COPYRIGHT:   Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
+ */
+
+#include "usbehci.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_EHCI_ROOT_HUB
+#include "dbg_ehci.h"
+
+MPSTATUS
+NTAPI
+EHCI_RH_ChirpRootPort(IN PVOID ehciExtension,
+                      IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+    ULONG PortBit;
+    ULONG ix;
+
+    DPRINT_RH("EHCI_RH_ChirpRootPort: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+    DPRINT_RH("EHCI_RH_ChirpRootPort: PortSC - %X\n", PortSC.AsULONG);
+
+    PortBit = 1 << (Port - 1);
+
+    if (PortBit & EhciExtension->ResetPortBits)
+    {
+        DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port);
+        return MP_STATUS_SUCCESS;
+    }
+
+    if (PortSC.PortPower == 0)
+    {
+        DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port);
+        return MP_STATUS_SUCCESS;
+    }
+
+    if (PortSC.CurrentConnectStatus == 0 ||
+        PortSC.PortEnabledDisabled == 1 ||
+        PortSC.PortOwner == EHCI_PORT_OWNER_COMPANION_CONTROLLER)
+    {
+        DPRINT_RH("EHCI_RH_ChirpRootPort: No port - %x\n", Port);
+        return MP_STATUS_SUCCESS;
+    }
+
+    if (PortSC.LineStatus == EHCI_LINE_STATUS_K_STATE_LOW_SPEED &&
+        PortSC.Suspend == 0 &&
+        PortSC.CurrentConnectStatus == 1)
+    {
+        /* Attached device is not a high-speed device.
+           Release ownership of the port to a selected HC.
+           Companion HC owns and controls the port. Section 4.2 */
+        PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+        DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port);
+        return MP_STATUS_SUCCESS;
+    }
+
+    DPRINT("EHCI_RH_ChirpRootPort: EhciExtension - %p, Port - %x\n",
+           EhciExtension,
+           Port);
+
+    PortSC.PortEnabledDisabled = 0;
+    PortSC.PortReset = 1;
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    RegPacket.UsbPortWait(EhciExtension, 10);
+
+    do
+    {
+        PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+        PortSC.ConnectStatusChange = 0;
+        PortSC.PortEnableDisableChange = 0;
+        PortSC.OverCurrentChange = 0;
+        PortSC.PortReset = 0;
+
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+        for (ix = 0; ix <= 500; ix += 20)
+        {
+             KeStallExecutionProcessor(20);
+             PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+             DPRINT_RH("EHCI_RH_ChirpRootPort: Reset port - %x\n", Port);
+
+             if (PortSC.PortReset == 0)
+                 break;
+        }
+    }
+    while (PortSC.PortReset == 1);
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    if (PortSC.PortEnabledDisabled == 1)
+    {
+        PortSC.ConnectStatusChange = 0;
+        PortSC.PortEnabledDisabled = 0;
+        PortSC.PortEnableDisableChange = 0;
+        PortSC.OverCurrentChange = 0;
+
+        RegPacket.UsbPortWait(EhciExtension, 10);
+
+        EhciExtension->ResetPortBits |= PortBit;
+
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+        DPRINT_RH("EHCI_RH_ChirpRootPort: Disable port - %x\n", Port);
+    }
+    else
+    {
+        PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+        DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port);
+    }
+
+    return MP_STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+EHCI_RH_GetRootHubData(IN PVOID ehciExtension,
+                       IN PVOID rootHubData)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PUSBPORT_ROOT_HUB_DATA RootHubData;
+    USBPORT_HUB_20_CHARACTERISTICS HubCharacteristics;
+
+    DPRINT_RH("EHCI_RH_GetRootHubData: EhciExtension - %p, rootHubData - %p\n",
+              EhciExtension,
+              rootHubData);
+
+    RootHubData = rootHubData;
+
+    RootHubData->NumberOfPorts = EhciExtension->NumberOfPorts;
+
+    HubCharacteristics.AsUSHORT = 0;
+
+    /* Logical Power Switching Mode */
+    if (EhciExtension->PortPowerControl == 1)
+    {
+        /* Individual port power switching */
+        HubCharacteristics.PowerControlMode = 1;
+    }
+    else
+    {
+        /* Ganged power switching (all ports\92 power at once) */
+        HubCharacteristics.PowerControlMode = 0;
+    }
+
+    HubCharacteristics.NoPowerSwitching = 0;
+
+    /* EHCI RH is not part of a compound device */
+    HubCharacteristics.PartOfCompoundDevice = 0;
+
+    /* Global Over-current Protection */
+    HubCharacteristics.OverCurrentProtectionMode = 0;
+
+    RootHubData->HubCharacteristics.Usb20HubCharacteristics = HubCharacteristics;
+
+    RootHubData->PowerOnToPowerGood = 2; // Time (in 2 ms intervals)
+    RootHubData->HubControlCurrent = 0;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_GetStatus(IN PVOID ehciExtension,
+                  IN PUSHORT Status)
+{
+    DPRINT_RH("EHCI_RH_GetStatus: ... \n");
+    *Status = USB_GETSTATUS_SELF_POWERED;
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_GetPortStatus(IN PVOID ehciExtension,
+                      IN USHORT Port,
+                      IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+    USB_PORT_STATUS_AND_CHANGE status;
+    ULONG PortMaskBits;
+
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    if (PortSC.CurrentConnectStatus)
+    {
+        DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, PortSC.AsULONG - %X\n",
+                  Port,
+                  PortSC.AsULONG);
+    }
+
+    PortStatus->AsUlong32 = 0;
+
+    if (PortSC.LineStatus == EHCI_LINE_STATUS_K_STATE_LOW_SPEED &&
+        PortSC.PortOwner != EHCI_PORT_OWNER_COMPANION_CONTROLLER &&
+        (PortSC.PortEnabledDisabled | PortSC.Suspend) && // Enable or Suspend
+        PortSC.CurrentConnectStatus == 1) // Device is present
+    {
+        DPRINT("EHCI_RH_GetPortStatus: LowSpeed device detected\n");
+        PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER; // release ownership
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+        return MP_STATUS_SUCCESS;
+    }
+
+    status.AsUlong32 = 0;
+
+    status.PortStatus.Usb20PortStatus.CurrentConnectStatus = PortSC.CurrentConnectStatus;
+    status.PortStatus.Usb20PortStatus.PortEnabledDisabled = PortSC.PortEnabledDisabled;
+    status.PortStatus.Usb20PortStatus.Suspend = PortSC.Suspend;
+    status.PortStatus.Usb20PortStatus.OverCurrent = PortSC.OverCurrentActive;
+    status.PortStatus.Usb20PortStatus.Reset = PortSC.PortReset;
+    status.PortStatus.Usb20PortStatus.PortPower = PortSC.PortPower;
+    if (PortSC.PortOwner == EHCI_PORT_OWNER_COMPANION_CONTROLLER)
+        status.PortStatus.Usb20PortStatus.Reserved1 = USB20_PORT_STATUS_RESERVED1_OWNED_BY_COMPANION;
+
+    status.PortChange.Usb20PortChange.PortEnableDisableChange = PortSC.PortEnableDisableChange;
+    status.PortChange.Usb20PortChange.OverCurrentIndicatorChange = PortSC.OverCurrentChange;
+
+    PortMaskBits = 1 << (Port - 1);
+
+    if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus)
+        status.PortStatus.Usb20PortStatus.LowSpeedDeviceAttached = 0;
+
+    status.PortStatus.Usb20PortStatus.HighSpeedDeviceAttached = 1;
+
+    if (PortSC.ConnectStatusChange)
+        EhciExtension->ConnectPortBits |= PortMaskBits;
+
+    if (EhciExtension->FinishResetPortBits & PortMaskBits)
+        status.PortChange.Usb20PortChange.ResetChange = 1;
+
+    if (EhciExtension->ConnectPortBits & PortMaskBits)
+        status.PortChange.Usb20PortChange.ConnectStatusChange = 1;
+
+    if (EhciExtension->SuspendPortBits & PortMaskBits)
+        status.PortChange.Usb20PortChange.SuspendChange = 1;
+
+    *PortStatus = status;
+
+    if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus)
+    {
+        DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, status.AsULONG - %X\n",
+                  Port,
+                  status.AsUlong32);
+    }
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_GetHubStatus(IN PVOID ehciExtension,
+                     IN PUSB_HUB_STATUS_AND_CHANGE HubStatus)
+{
+    DPRINT_RH("EHCI_RH_GetHubStatus: ... \n");
+    HubStatus->AsUlong32 = 0;
+    return MP_STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+EHCI_RH_FinishReset(IN PVOID ehciExtension,
+                    IN PVOID Context)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+    PUSHORT Port = Context;
+
+    DPRINT("EHCI_RH_FinishReset: *Port - %x\n", *Port);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    if (PortSC.AsULONG != -1)
+    {
+        if (!PortSC.CurrentConnectStatus)
+            DPRINT("EHCI_RH_FinishReset: PortSC.AsULONG - %X\n", PortSC.AsULONG);
+
+        if (PortSC.PortEnabledDisabled ||
+            !PortSC.CurrentConnectStatus ||
+            PortSC.ConnectStatusChange)
+        {
+            EhciExtension->FinishResetPortBits |= (1 << (*Port - 1));
+            RegPacket.UsbPortInvalidateRootHub(EhciExtension);
+        }
+        else
+        {
+            PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+            PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
+            WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+            EhciExtension->FinishResetPortBits |= (1 << (*Port - 1));
+        }
+
+        EhciExtension->ResetPortBits &= ~(1 << (*Port - 1));
+    }
+}
+
+VOID
+NTAPI
+EHCI_RH_PortResetComplete(IN PVOID ehciExtension,
+                          IN PVOID Context)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+    ULONG ix;
+    PUSHORT Port = Context;
+
+    DPRINT("EHCI_RH_PortResetComplete: *Port - %x\n", *Port);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
+
+    do
+    {
+        PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+        PortSC.ConnectStatusChange = 0;
+        PortSC.PortEnableDisableChange = 0;
+        PortSC.OverCurrentChange = 0;
+        PortSC.PortReset = 0;
+
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+        for (ix = 0; ix <= 500; ix += 20)
+        {
+             KeStallExecutionProcessor(20);
+             PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+             DPRINT("EHCI_RH_PortResetComplete: Reset port - %x\n", Port);
+
+             if (PortSC.PortReset == 0)
+                 break;
+        }
+    }
+    while (PortSC.PortReset == 1 && (PortSC.AsULONG != -1));
+
+    RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
+                                          50, // TimerValue
+                                          Port,
+                                          sizeof(Port),
+                                          EHCI_RH_FinishReset);
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_SetFeaturePortReset(IN PVOID ehciExtension,
+                            IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_SetFeaturePortReset: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    EhciExtension->ResetPortBits |= 1 << (Port - 1);
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnabledDisabled = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 0;
+    PortSC.PortReset = 1;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
+                                          50, // TimerValue
+                                          &Port,
+                                          sizeof(Port),
+                                          EHCI_RH_PortResetComplete);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_SetFeaturePortPower(IN PVOID ehciExtension,
+                            IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT_RH("EHCI_RH_SetFeaturePortPower: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 0;
+    PortSC.PortPower = 1;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_SetFeaturePortEnable(IN PVOID ehciExtension,
+                             IN USHORT Port)
+{
+    DPRINT_RH("EHCI_RH_SetFeaturePortEnable: Not supported\n");
+    ASSERT(Port != 0);
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_SetFeaturePortSuspend(IN PVOID ehciExtension,
+                              IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_SetFeaturePortSuspend: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 0;
+    PortSC.Suspend = 1;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+    KeStallExecutionProcessor(125);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortEnable(IN PVOID ehciExtension,
+                               IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_ClearFeaturePortEnable: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnabledDisabled = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 0;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortPower(IN PVOID ehciExtension,
+                              IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_ClearFeaturePortPower: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+    PortSC.PortPower = 0;
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    return MP_STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+EHCI_RH_PortResumeComplete(IN PVOID ehciExtension,
+                           IN PVOID Context)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+    PUSHORT Port = Context;
+
+    DPRINT("EHCI_RH_PortResumeComplete: *Port - %x\n", *Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 0;
+    PortSC.ForcePortResume = 0;
+    PortSC.Suspend = 0;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+    READ_REGISTER_ULONG(PortStatusReg);
+
+    EhciExtension->SuspendPortBits |= 1 << (*Port - 1);
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortSuspend(IN PVOID ehciExtension,
+                                IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_ClearFeaturePortSuspend: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+    EhciExtension->ResetPortBits |= 1 << (Port - 1);
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+    PortSC.ForcePortResume = 1;
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
+                                          50, // TimerValue
+                                          &Port,
+                                          sizeof(Port),
+                                          EHCI_RH_PortResumeComplete);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortEnableChange(IN PVOID ehciExtension,
+                                     IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT("EHCI_RH_ClearFeaturePortEnableChange: Port - %p\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.OverCurrentChange = 0;
+    PortSC.PortEnableDisableChange = 1;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortConnectChange(IN PVOID ehciExtension,
+                                      IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT_RH("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    if (PortSC.ConnectStatusChange)
+    {
+        PortSC.ConnectStatusChange = 1;
+        PortSC.PortEnableDisableChange = 0;
+        PortSC.OverCurrentChange = 0;
+
+        WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+    }
+
+    EhciExtension->ConnectPortBits &= ~(1 << (Port - 1));
+
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortResetChange(IN PVOID ehciExtension,
+                                    IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+
+    DPRINT("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    EhciExtension->FinishResetPortBits &= ~(1 << (Port - 1));
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ehciExtension,
+                                      IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+
+    DPRINT("EHCI_RH_ClearFeaturePortSuspendChange: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    EhciExtension->SuspendPortBits &= ~(1 << (Port - 1));
+    return MP_STATUS_SUCCESS;
+}
+
+MPSTATUS
+NTAPI
+EHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ehciExtension,
+                                          IN USHORT Port)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG PortStatusReg;
+    EHCI_PORT_STATUS_CONTROL PortSC;
+
+    DPRINT_RH("EHCI_RH_ClearFeaturePortOvercurrentChange: Port - %x\n", Port);
+    ASSERT(Port != 0);
+
+    PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
+
+    PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
+
+    PortSC.ConnectStatusChange = 0;
+    PortSC.PortEnableDisableChange = 0;
+    PortSC.OverCurrentChange = 1;
+
+    WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
+
+    return MP_STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+EHCI_RH_DisableIrq(IN PVOID ehciExtension)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG IntrStsReg;
+    EHCI_INTERRUPT_ENABLE IntrSts;
+
+    DPRINT_RH("EHCI_RH_DisableIrq: ... \n");
+
+    IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG;
+    IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg);
+
+    EhciExtension->InterruptMask.PortChangeInterrupt = 0;
+    IntrSts.PortChangeInterrupt = 0;
+
+    if (IntrSts.Interrupt)
+        WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG);
+}
+
+VOID
+NTAPI
+EHCI_RH_EnableIrq(IN PVOID ehciExtension)
+{
+    PEHCI_EXTENSION EhciExtension = ehciExtension;
+    PULONG IntrStsReg;
+    EHCI_INTERRUPT_ENABLE IntrSts;
+
+    DPRINT_RH("EHCI_RH_EnableIrq: ... \n");
+
+    IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG;
+    IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg);
+
+    EhciExtension->InterruptMask.PortChangeInterrupt = 1;
+    IntrSts.PortChangeInterrupt = 1;
+
+    if (IntrSts.Interrupt)
+        WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG);
+}