--- /dev/null
+/*
+ * PROJECT: ReactOS USB Hub Driver
+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: USBHub power handling functions
+ * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
+ */
+
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_POWER
+#include "dbg_uhub.h"
+
+VOID
+NTAPI
+USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN NTSTATUS NtStatus)
+{
+ DPRINT("USBH_CompletePowerIrp: HubExtension - %p, Irp - %p, NtStatus - %lX\n",
+ HubExtension,
+ Irp,
+ NtStatus);
+
+ Irp->IoStatus.Status = NtStatus;
+
+ PoStartNextPowerIrp(Irp);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ DPRINT("USBH_HubCancelWakeIrp: HubExtension - %p, Irp - %p\n",
+ HubExtension,
+ Irp);
+
+ IoCancelIrp(Irp);
+
+ if (InterlockedExchange((PLONG)&HubExtension->FdoWaitWakeLock, 1))
+ {
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+}
+
+VOID
+NTAPI
+USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ DPRINT("USBH_HubESDRecoverySetD3Completion ... \n");
+
+ KeSetEvent((PRKEVENT)Context,
+ EVENT_INCREMENT,
+ FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSBHUB_FDO_EXTENSION RootHubDevExt;
+ NTSTATUS Status;
+ KEVENT Event;
+ POWER_STATE PowerState;
+
+ DPRINT("USBH_HubSetD0: HubExtension - %p\n", HubExtension);
+
+ RootHubDevExt = USBH_GetRootHubExtension(HubExtension);
+
+ if (RootHubDevExt->SystemPowerState.SystemState != PowerSystemWorking)
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ return Status;
+ }
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+ {
+ DPRINT("USBH_HubSetD0: HubFlags - %lX\n", HubExtension->HubFlags);
+
+ KeWaitForSingleObject(&HubExtension->IdleEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ PowerState.DeviceState = PowerDeviceD0;
+
+ Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ PowerState,
+ USBH_HubESDRecoverySetD3Completion,
+ &Event,
+ NULL);
+
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ while (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAKEUP_START)
+ {
+ USBH_Wait(10);
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_IDLE_PORT_CANCEL_CONTEXT WorkItemIdlePower;
+ PIRP Irp;
+
+ DPRINT("USBH_IdleCancelPowerHubWorker: ... \n");
+
+ WorkItemIdlePower = Context;
+
+ if (HubExtension &&
+ HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubSetD0(HubExtension);
+ }
+
+ Irp = WorkItemIdlePower->Irp;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY ListIrps)
+{
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ USHORT NumPorts;
+ USHORT Port;
+ PIRP WakeIrp;
+ KIRQL OldIrql;
+
+ DPRINT("USBH_HubQueuePortWakeIrps ... \n");
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ InitializeListHead(ListIrps);
+
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ for (Port = 0; Port < NumPorts; ++Port)
+ {
+ PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+ if (PortDevice)
+ {
+ PortExtension = PortDevice->DeviceExtension;
+
+ WakeIrp = PortExtension->PdoWaitWakeIrp;
+ PortExtension->PdoWaitWakeIrp = NULL;
+
+ if (WakeIrp)
+ {
+ DPRINT1("USBH_HubQueuePortWakeIrps: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+ }
+ }
+
+ IoReleaseCancelSpinLock(OldIrql);
+}
+
+VOID
+NTAPI
+USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY ListIrps,
+ IN NTSTATUS NtStatus)
+{
+ DPRINT("USBH_HubCompleteQueuedPortWakeIrps ... \n");
+
+ while (!IsListEmpty(ListIrps))
+ {
+ DPRINT1("USBH_HubCompleteQueuedPortWakeIrps: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+}
+
+VOID
+NTAPI
+USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN NTSTATUS NtStatus)
+{
+ LIST_ENTRY ListIrps;
+
+ DPRINT("USBH_HubCompletePortWakeIrps: NtStatus - %x\n", NtStatus);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubQueuePortWakeIrps(HubExtension, &ListIrps);
+
+ USBH_HubCompleteQueuedPortWakeIrps(HubExtension,
+ &ListIrps,
+ NtStatus);
+ }
+}
+
+VOID
+NTAPI
+USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+
+ DPRINT("USBH_FdoPoRequestD0Completion ... \n");
+
+ HubExtension = Context;
+
+ USBH_HubCompletePortWakeIrps(HubExtension, STATUS_SUCCESS);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAKEUP_START;
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+}
+
+VOID
+NTAPI
+USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ DPRINT1("USBH_CompletePortWakeIrpsWorker: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ NTSTATUS Status;
+ KIRQL OldIrql;
+ POWER_STATE PowerState;
+ PIRP WakeIrp;
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ HubExtension = Context;
+
+ Status = Irp->IoStatus.Status;
+
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+ WakeIrp = InterlockedExchangePointer((PVOID *)&HubExtension->PendingWakeIrp,
+ NULL);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ IoReleaseCancelSpinLock(OldIrql);
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_FdoWWIrpIoCompletion: DbgBreakPoint() \n");
+ DbgBreakPoint();
+ }
+ else
+ {
+ PowerState.DeviceState = PowerDeviceD0;
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAKEUP_START;
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ Status = STATUS_SUCCESS;
+
+ PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ PowerState,
+ USBH_FdoPoRequestD0Completion,
+ (PVOID)HubExtension,
+ NULL);
+ }
+
+ if (!WakeIrp)
+ {
+ if (!InterlockedExchange(&HubExtension->FdoWaitWakeLock, 1))
+ {
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ }
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PoStartNextPowerIrp(Irp);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PIO_STACK_LOCATION IoStack;
+ DEVICE_POWER_STATE OldDeviceState;
+ NTSTATUS Status;
+ POWER_STATE PowerState;
+
+ DPRINT("USBH_PowerIrpCompletion: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ HubExtension = Context;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ PowerState = IoStack->Parameters.Power.State;
+
+ Status = Irp->IoStatus.Status;
+ DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (PowerState.DeviceState == PowerDeviceD0)
+ {
+ PoStartNextPowerIrp(Irp);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+ }
+ }
+ else if (PowerState.DeviceState == PowerDeviceD0)
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+
+ OldDeviceState = HubExtension->CurrentPowerState.DeviceState;
+ HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+ DPRINT("USBH_PowerIrpCompletion: OldDeviceState - %x\n", OldDeviceState);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_HIBERNATE_STATE)
+ {
+ DPRINT1("USBH_PowerIrpCompletion: USBHUB_FDO_FLAG_HIBERNATE_STATE. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HIBERNATE_STATE;
+
+ if (OldDeviceState == PowerDeviceD3)
+ {
+ DPRINT1("USBH_PowerIrpCompletion: PowerDeviceD3. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)
+ {
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+ }
+
+ DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PoStartNextPowerIrp(Irp);
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ PUSBHUB_FDO_EXTENSION Extension;
+ PUSBHUB_FDO_EXTENSION HubExtension = NULL;
+ PIRP PowerIrp;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT("USBH_FdoDeferPoRequestCompletion ... \n");
+
+ Extension = Context;
+
+ PowerIrp = Extension->PowerIrp;
+
+ if (Extension->Common.ExtensionType == USBH_EXTENSION_TYPE_HUB)
+ {
+ HubExtension = Context;
+ }
+
+ IoStack = IoGetCurrentIrpStackLocation(PowerIrp);
+
+ if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking &&
+ HubExtension && HubExtension->LowerPDO == HubExtension->RootHubPdo)
+ {
+ HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
+ USBH_CheckIdleDeferred(HubExtension);
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(PowerIrp);
+ PoStartNextPowerIrp(PowerIrp);
+ PoCallDriver(Extension->LowerDevice, PowerIrp);
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ POWER_STATE PowerState;
+ POWER_STATE DevicePwrState;
+ BOOLEAN IsAllPortsD3;
+ PUSBHUB_PORT_DATA PortData;
+ PDEVICE_OBJECT PdoDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ ULONG Port;
+
+ DPRINT_PWR("USBH_FdoPower: HubExtension - %p, Irp - %p, Minor - %X\n",
+ HubExtension,
+ Irp,
+ Minor);
+
+ switch (Minor)
+ {
+ case IRP_MN_WAIT_WAKE:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_WAIT_WAKE\n");
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_FdoWWIrpIoCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+
+ case IRP_MN_POWER_SEQUENCE:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_POWER_SEQUENCE\n");
+ break;
+
+ case IRP_MN_SET_POWER:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER\n");
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER/DevicePowerState\n");
+ PowerState = IoStack->Parameters.Power.State;
+
+ if (IoStack->Parameters.Power.Type == DevicePowerState)
+ {
+ DPRINT_PWR("USBH_FdoPower: PowerState - %x\n",
+ PowerState.DeviceState);
+
+ if (HubExtension->CurrentPowerState.DeviceState == PowerState.DeviceState)
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+ }
+
+ switch (PowerState.DeviceState)
+ {
+ case PowerDeviceD0:
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_SET_D0_STATE))
+ {
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_SET_D0_STATE;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_PowerIrpCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+ }
+ else
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ }
+
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+ return STATUS_PENDING;
+
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3:
+ if (HubExtension->ResetRequestCount)
+ {
+ IoCancelIrp(HubExtension->ResetPortIrp);
+
+ KeWaitForSingleObject(&HubExtension->ResetEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ HubExtension->HubFlags |= (USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ IoCancelIrp(HubExtension->SCEIrp);
+
+ KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ HubExtension->CurrentPowerState.DeviceState = PowerState.DeviceState;
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE &&
+ USBH_CheckIdleAbort(HubExtension, TRUE, TRUE) == TRUE)
+ {
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+
+ PoStartNextPowerIrp(Irp);
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+ KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_PowerIrpCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE)
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+ KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+ }
+
+ return STATUS_PENDING;
+
+ default:
+ DPRINT1("USBH_FdoPower: Unsupported PowerState.DeviceState\n");
+ DbgBreakPoint();
+ break;
+ }
+ }
+ else
+ {
+ if (PowerState.SystemState != PowerSystemWorking)
+ {
+ USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState =
+ PowerState.SystemState;
+ }
+
+ if (PowerState.SystemState == PowerSystemHibernate)
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_HIBERNATE_STATE;
+ }
+
+ PortData = HubExtension->PortData;
+
+ IsAllPortsD3 = TRUE;
+
+ if (PortData && HubExtension->HubDescriptor)
+ {
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ PdoDevice = PortData[Port].DeviceObject;
+
+ if (PdoDevice)
+ {
+ PortExtension = PdoDevice->DeviceExtension;
+
+ if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD3)
+ {
+ IsAllPortsD3 = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (PowerState.SystemState == PowerSystemWorking)
+ {
+ DevicePwrState.DeviceState = PowerDeviceD0;
+ }
+ else if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP ||
+ !IsAllPortsD3)
+ {
+ DevicePwrState.DeviceState = HubExtension->DeviceState[PowerState.SystemState];
+
+ if (DevicePwrState.DeviceState == PowerDeviceUnspecified)
+ {
+ goto Exit;
+ }
+ }
+ else
+ {
+ DevicePwrState.DeviceState = PowerDeviceD3;
+ }
+
+ if (DevicePwrState.DeviceState != HubExtension->CurrentPowerState.DeviceState &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ HubExtension->PowerIrp = Irp;
+
+ IoMarkIrpPending(Irp);
+
+ if (PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ DevicePwrState,
+ USBH_FdoDeferPoRequestCompletion,
+ (PVOID)HubExtension,
+ NULL) == STATUS_PENDING)
+ {
+ return STATUS_PENDING;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+ }
+
+ Exit:
+
+ HubExtension->SystemPowerState.SystemState = PowerState.SystemState;
+
+ if (PowerState.SystemState == PowerSystemWorking)
+ {
+ USBH_CheckIdleDeferred(HubExtension);
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+
+ return PoCallDriver(HubExtension->LowerDevice, Irp);
+ }
+
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_QUERY_POWER\n");
+ break;
+
+ default:
+ DPRINT1("USBH_FdoPower: unknown IRP_MN_POWER!\n");
+ break;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ Status = PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor)
+{
+ NTSTATUS Status = Irp->IoStatus.Status;
+
+ DPRINT_PWR("USBH_FdoPower: PortExtension - %p, Irp - %p, Minor - %X\n",
+ PortExtension,
+ Irp,
+ Minor);
+
+ switch (Minor)
+ {
+ case IRP_MN_WAIT_WAKE:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_WAIT_WAKE\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_POWER_SEQUENCE:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_POWER_SEQUENCE\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_SET_POWER:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_SET_POWER\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_QUERY_POWER\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ default:
+ DPRINT1("USBHUB_PdoPower: unknown IRP_MN_POWER!\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}