--- /dev/null
+/*
+ * 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);
+}