mirror of
https://github.com/reactos/reactos.git
synced 2024-11-19 05:22:59 +00:00
801 lines
24 KiB
C
801 lines
24 KiB
C
/*
|
|
* 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;
|
|
}
|