mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
825 lines
23 KiB
825 lines
23 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: power.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pciidex.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PciIdeIssueSetPowerState)
|
|
|
|
#pragma alloc_text(NONPAGE, PciIdePowerCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, PciIdeSetPdoPowerState)
|
|
#pragma alloc_text(NONPAGE, PciIdeSetFdoPowerState)
|
|
#pragma alloc_text(NONPAGE, FdoContingentPowerCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, FdoPowerCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, FdoChildReportPowerDown)
|
|
#pragma alloc_text(NONPAGE, FdoChildRequestPowerUp)
|
|
#pragma alloc_text(NONPAGE, FdoChildRequestPowerUpCompletionRoutine)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
NTSTATUS
|
|
PciIdeIssueSetPowerState (
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN POWER_STATE_TYPE Type,
|
|
IN POWER_STATE State,
|
|
IN BOOLEAN Sync
|
|
)
|
|
{
|
|
PIRP irp = NULL;
|
|
PIO_STACK_LOCATION irpStack;
|
|
SET_POWER_STATE_CONTEXT context;
|
|
NTSTATUS status;
|
|
CCHAR stackSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Sync) {
|
|
|
|
KeInitializeEvent(
|
|
&context.Event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
stackSize = (CCHAR) (FdoExtension->DeviceObject->StackSize + 1);
|
|
|
|
irp = IoAllocateIrp(
|
|
stackSize,
|
|
FALSE
|
|
);
|
|
|
|
if (irp == NULL) {
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto GetOut;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
irpStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpStack->MajorFunction = IRP_MJ_POWER;
|
|
irpStack->MinorFunction = IRP_MN_SET_POWER;
|
|
|
|
irpStack->Parameters.Power.SystemContext = 0;
|
|
irpStack->Parameters.Power.Type = Type;
|
|
irpStack->Parameters.Power.State = State;
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
PciIdePowerCompletionRoutine,
|
|
Sync ? &context : NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = PoCallDriver(FdoExtension->DeviceObject, irp);
|
|
|
|
|
|
//
|
|
//Wait for the completion routine. It will be called anyway.
|
|
//
|
|
// if ((status == STATUS_PENDING) && (Sync)) {
|
|
if (Sync) {
|
|
|
|
KeWaitForSingleObject(&context.Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
status = context.Status;
|
|
}
|
|
|
|
GetOut:
|
|
|
|
return status;
|
|
} // PciIdeIssueSetPowerState
|
|
|
|
NTSTATUS
|
|
PciIdePowerCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PSET_POWER_STATE_CONTEXT context = Context;
|
|
|
|
if (context) {
|
|
|
|
context->Status = Irp->IoStatus.Status;
|
|
|
|
KeSetEvent(
|
|
&context->Event,
|
|
EVENT_INCREMENT,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
IoFreeIrp (Irp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
} // PciIdePowerCompletionRoutine
|
|
|
|
|
|
NTSTATUS
|
|
PciIdeXQueryPowerState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION_HEADER deviceExtensionHeader;
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
deviceExtensionHeader = DeviceObject->DeviceExtension;
|
|
|
|
#if defined (DONT_POWER_DOWN_PAGING_DEVICE)
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (!deviceExtensionHeader->CrashDumpPathCount ||
|
|
((irpStack->Parameters.Power.Type == SystemPowerState) &&
|
|
(irpStack->Parameters.Power.State.SystemState == PowerSystemWorking)) ||
|
|
((irpStack->Parameters.Power.Type == DevicePowerState) &&
|
|
(irpStack->Parameters.Power.State.SystemState == PowerDeviceD0))) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = STATUS_DEVICE_POWER_FAILURE;
|
|
}
|
|
#else
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
#endif // DONT_POWER_DOWN_PAGING_DEVICE
|
|
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
|
|
if (deviceExtensionHeader->AttacheeDeviceObject != NULL) {
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
status = PoCallDriver (deviceExtensionHeader->AttacheeDeviceObject, Irp);
|
|
}
|
|
else {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PciIdeSetPdoPowerState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PCHANPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
|
|
pdoExtension = ChannelGetPdoExtension(DeviceObject);
|
|
if (pdoExtension == NULL) {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
} else {
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
status = STATUS_SUCCESS;
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
if (pdoExtension->SystemPowerState != irpStack->Parameters.Power.State.SystemState) {
|
|
|
|
POWER_STATE powerState;
|
|
|
|
pdoExtension->SystemPowerState = irpStack->Parameters.Power.State.SystemState;
|
|
|
|
DebugPrint ((1, "PciIdeX: New Pdo 0x%x system power state 0x%x\n", pdoExtension->ChannelNumber, irpStack->Parameters.Power.State.SystemState));
|
|
}
|
|
|
|
} else if (irpStack->Parameters.Power.Type == DevicePowerState) {
|
|
|
|
if (pdoExtension->DevicePowerState != irpStack->Parameters.Power.State.DeviceState) {
|
|
|
|
//
|
|
// checking old device state
|
|
//
|
|
if (pdoExtension->DevicePowerState == PowerDeviceD3) {
|
|
|
|
//
|
|
// waking up
|
|
//
|
|
IoMarkIrpPending(Irp);
|
|
Irp->IoStatus.Information = irpStack->Parameters.Power.State.DeviceState;
|
|
status = FdoChildRequestPowerUp (
|
|
pdoExtension->ParentDeviceExtension,
|
|
pdoExtension,
|
|
Irp
|
|
);
|
|
ASSERT (NT_SUCCESS(status));
|
|
status = STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
if (pdoExtension->DevicePowerState == PowerDeviceD0) {
|
|
|
|
//
|
|
// getting out of D0 state, better call PoSetPowerState now
|
|
//
|
|
PoSetPowerState (
|
|
DeviceObject,
|
|
DevicePowerState,
|
|
irpStack->Parameters.Power.State
|
|
);
|
|
}
|
|
|
|
DebugPrint ((1, "PciIdeX: New Pdo 0x%x device power state 0x%x\n", pdoExtension->ChannelNumber, irpStack->Parameters.Power.State.DeviceState));
|
|
|
|
pdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState;
|
|
|
|
if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) {
|
|
|
|
//
|
|
// tell parent that we just fell to sleep
|
|
//
|
|
FdoChildReportPowerDown (
|
|
pdoExtension->ParentDeviceExtension,
|
|
pdoExtension
|
|
);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
ASSERT (FALSE);
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
if (status != STATUS_PENDING) {
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Information = irpStack->Parameters.Power.State.SystemState;
|
|
}
|
|
Irp->IoStatus.Status = status;
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status;
|
|
} // PciIdeSetPdoPowerState
|
|
|
|
NTSTATUS
|
|
PciIdeSetFdoPowerState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PFDO_POWER_CONTEXT context;
|
|
BOOLEAN noCompletionRoutine;
|
|
BOOLEAN systemPowerContext = FALSE;
|
|
BOOLEAN devicePowerContext = FALSE;
|
|
|
|
fdoExtension = DeviceObject->DeviceExtension;
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
//context = ExAllocatePool (NonPagedPool, sizeof(FDO_POWER_CONTEXT));
|
|
|
|
//
|
|
// We need two pre-alloced context structures. This is because a system power irp
|
|
// would result in a device power irp to be issued before the former is completed.
|
|
//
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 1, 0) == 0);
|
|
context = &(fdoExtension->FdoPowerContext[0]);
|
|
systemPowerContext = TRUE;
|
|
|
|
} else {
|
|
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 1, 0) == 0);
|
|
context = &(fdoExtension->FdoPowerContext[1]);
|
|
devicePowerContext = TRUE;
|
|
|
|
}
|
|
|
|
if (context == NULL) {
|
|
|
|
ASSERT(context);
|
|
status = STATUS_NO_MEMORY;
|
|
} else {
|
|
|
|
RtlZeroMemory (context, sizeof(FDO_POWER_CONTEXT));
|
|
|
|
//irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
context->OriginalPowerIrp = Irp;
|
|
context->newPowerType = irpStack->Parameters.Power.Type;
|
|
context->newPowerState = irpStack->Parameters.Power.State;
|
|
|
|
noCompletionRoutine = FALSE;
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
if (fdoExtension->SystemPowerState != irpStack->Parameters.Power.State.SystemState) {
|
|
|
|
POWER_STATE powerState;
|
|
BOOLEAN requestPowerState = FALSE;
|
|
|
|
if ((irpStack->Parameters.Power.State.SystemState == PowerSystemShutdown) &&
|
|
(irpStack->Parameters.Power.ShutdownType == PowerActionShutdownReset)) {
|
|
|
|
//
|
|
// spin up for BIOS POST
|
|
//
|
|
requestPowerState = TRUE;
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
|
|
} else if (fdoExtension->SystemPowerState == PowerSystemWorking) {
|
|
|
|
//
|
|
// we are getting out of working state...power down
|
|
//
|
|
requestPowerState = TRUE;
|
|
powerState.DeviceState = PowerDeviceD3;
|
|
}
|
|
|
|
if (requestPowerState) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
PoRequestPowerIrp (
|
|
fdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
FdoContingentPowerCompletionRoutine,
|
|
context,
|
|
NULL
|
|
);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// We are already in the given state
|
|
//
|
|
noCompletionRoutine = TRUE;
|
|
}
|
|
|
|
} else if (irpStack->Parameters.Power.Type == DevicePowerState) {
|
|
|
|
if (fdoExtension->DevicePowerState != irpStack->Parameters.Power.State.DeviceState) {
|
|
|
|
if (fdoExtension->DevicePowerState == PowerDeviceD0) {
|
|
|
|
//
|
|
// getting out of D0 state, better call PoSetPowerState now
|
|
//
|
|
PoSetPowerState (
|
|
DeviceObject,
|
|
DevicePowerState,
|
|
irpStack->Parameters.Power.State
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We are already in the given state
|
|
//
|
|
noCompletionRoutine = TRUE;
|
|
}
|
|
} else {
|
|
|
|
ASSERT (FALSE);
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
IoMarkIrpPending (Irp);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
if (!noCompletionRoutine) {
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
FdoPowerCompletionRoutine,
|
|
context,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
} else {
|
|
|
|
if (context) {
|
|
//ExFreePool (context);
|
|
if (systemPowerContext) {
|
|
ASSERT(devicePowerContext == FALSE);
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1);
|
|
|
|
}
|
|
|
|
if (devicePowerContext) {
|
|
ASSERT(systemPowerContext == FALSE);
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1);
|
|
}
|
|
}
|
|
PoStartNextPowerIrp (Irp);
|
|
}
|
|
|
|
PoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
return STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = status;
|
|
|
|
if (context) {
|
|
//ExFreePool (context);
|
|
if (systemPowerContext) {
|
|
ASSERT(devicePowerContext == FALSE);
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1);
|
|
|
|
}
|
|
|
|
if (devicePowerContext) {
|
|
ASSERT(systemPowerContext == FALSE);
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1);
|
|
}
|
|
}
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
} // PciIdeSetFdoPowerState
|
|
|
|
NTSTATUS
|
|
FdoContingentPowerCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PFDO_POWER_CONTEXT context = Context;
|
|
PIRP irp;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
|
|
fdoExtension = DeviceObject->DeviceExtension;
|
|
|
|
irp = context->OriginalPowerIrp;
|
|
|
|
if (NT_SUCCESS(IoStatus->Status)) {
|
|
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (irp);
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
FdoPowerCompletionRoutine,
|
|
context,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
PoCallDriver (fdoExtension->AttacheeDeviceObject, irp);
|
|
|
|
} else {
|
|
|
|
irp->IoStatus.Information = 0;
|
|
irp->IoStatus.Status = IoStatus->Status;
|
|
//ExFreePool (context);
|
|
ASSERT(context->newPowerType == SystemPowerState);
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1);
|
|
|
|
PoStartNextPowerIrp (irp);
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return IoStatus->Status;
|
|
} // FdoContingentPowerCompletionRoutine
|
|
|
|
|
|
NTSTATUS
|
|
FdoPowerCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PFDO_POWER_CONTEXT context = Context;
|
|
BOOLEAN callPoSetPowerState = FALSE;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
POWER_STATE newPowerState;
|
|
POWER_STATE_TYPE newPowerType;
|
|
BOOLEAN unlocked = FALSE;
|
|
BOOLEAN moreProcessingRequired = FALSE;
|
|
NTSTATUS status;
|
|
|
|
fdoExtension = DeviceObject->DeviceExtension;
|
|
newPowerType = context->newPowerType;
|
|
newPowerState = context->newPowerState;
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
callPoSetPowerState = TRUE;
|
|
|
|
if (context->newPowerType == SystemPowerState) {
|
|
|
|
fdoExtension->SystemPowerState = context->newPowerState.SystemState;
|
|
|
|
if (fdoExtension->SystemPowerState == PowerSystemWorking) {
|
|
|
|
POWER_STATE powerState;
|
|
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1);
|
|
unlocked = TRUE;
|
|
|
|
moreProcessingRequired = TRUE;
|
|
|
|
//
|
|
// initiate a D0 here to cause a re-enumuration
|
|
//
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
status = PoRequestPowerIrp (
|
|
fdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
FdoSystemPowerUpCompletionRoutine,
|
|
Irp,
|
|
NULL
|
|
);
|
|
|
|
ASSERT(status == STATUS_PENDING);
|
|
|
|
}
|
|
|
|
DebugPrint ((1, "PciIdeX: New Fdo system power state 0x%x\n", fdoExtension->SystemPowerState));
|
|
|
|
|
|
} else if (context->newPowerType == DevicePowerState) {
|
|
|
|
if (fdoExtension->DevicePowerState == PowerDeviceD0) {
|
|
|
|
//
|
|
// PoSetPowerState is called before we get out of D0
|
|
//
|
|
callPoSetPowerState = FALSE;
|
|
}
|
|
|
|
fdoExtension->DevicePowerState = context->newPowerState.DeviceState;
|
|
|
|
if (fdoExtension->DevicePowerState == PowerDeviceD0) {
|
|
|
|
//
|
|
// Re-enumerate the devices on the channel
|
|
//
|
|
EnablePCIBusMastering (fdoExtension);
|
|
|
|
IoInvalidateDeviceRelations (
|
|
fdoExtension->AttacheePdo,
|
|
BusRelations
|
|
);
|
|
}
|
|
|
|
DebugPrint ((1, "PciIdeX: New Fdo device power state 0x%x\n", fdoExtension->DevicePowerState));
|
|
}
|
|
|
|
if (callPoSetPowerState) {
|
|
|
|
PoSetPowerState (
|
|
DeviceObject,
|
|
newPowerType,
|
|
newPowerState
|
|
);
|
|
}
|
|
}
|
|
|
|
//ExFreePool (Context);
|
|
if (!unlocked) {
|
|
|
|
if (context->newPowerType == SystemPowerState) {
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1);
|
|
} else {
|
|
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// wait for the device irp to complete
|
|
//
|
|
if (moreProcessingRequired) {
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//
|
|
// If pending has be returned for this irp then mark the current stack as
|
|
// pending.
|
|
//
|
|
// if (Irp->PendingReturned) {
|
|
// IoMarkIrpPending(Irp);
|
|
//}
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
return Irp->IoStatus.Status;
|
|
} // FdoPowerCompletionRoutine
|
|
|
|
|
|
VOID
|
|
FdoChildReportPowerDown (
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN PCHANPDO_EXTENSION PdoExtension
|
|
)
|
|
{
|
|
POWER_STATE powerState;
|
|
ULONG numChildrenPowerUp;
|
|
|
|
ASSERT(FdoExtension->NumberOfChildrenPowerUp > 0);
|
|
numChildrenPowerUp = InterlockedDecrement(&FdoExtension->NumberOfChildrenPowerUp);
|
|
|
|
if (numChildrenPowerUp == 0) {
|
|
|
|
DebugPrint ((1, "PciIdeX FdoChildReportPowerDown: sleep fdo 0x%x\n", FdoExtension));
|
|
|
|
//
|
|
// All the children are powered down, we can now power down
|
|
// the parent (the controller)
|
|
//
|
|
powerState.DeviceState = PowerDeviceD3;
|
|
PoRequestPowerIrp (
|
|
FdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
// else if (numChildrenPowerUp < 0) {
|
|
|
|
//
|
|
// should never happen. If it did, pretend it didn't
|
|
//
|
|
// ASSERT (FALSE);
|
|
// InterlockedExchange(&FdoExtension->NumberOfChildrenPowerUp, 0);
|
|
//}
|
|
|
|
return;
|
|
} // FdoChildReportPowerDown
|
|
|
|
|
|
NTSTATUS
|
|
FdoChildRequestPowerUp (
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN PCHANPDO_EXTENSION PdoExtension,
|
|
IN PIRP ChildPowerIrp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
POWER_STATE powerState;
|
|
ULONG numberOfChildrenPowerUp;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
numberOfChildrenPowerUp = InterlockedExchange (
|
|
&FdoExtension->NumberOfChildrenPowerUp,
|
|
FdoExtension->NumberOfChildrenPowerUp
|
|
);
|
|
|
|
if (numberOfChildrenPowerUp == 0) {
|
|
|
|
DebugPrint ((1, "PciIdeX FdoChildRequestPowerUp: wake up fdo 0x%x\n", FdoExtension));
|
|
|
|
//
|
|
// One of the children is coming out of sleep,
|
|
// we need to power up the parent (the controller)
|
|
//
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
status = PoRequestPowerIrp (
|
|
FdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
FdoChildRequestPowerUpCompletionRoutine,
|
|
ChildPowerIrp,
|
|
NULL
|
|
);
|
|
|
|
ASSERT (NT_SUCCESS(status));
|
|
status = STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
IoStatus.Information = PowerDeviceD0;
|
|
IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
FdoChildRequestPowerUpCompletionRoutine (
|
|
FdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
ChildPowerIrp,
|
|
&IoStatus
|
|
);
|
|
|
|
status = STATUS_PENDING;
|
|
}
|
|
|
|
return status;
|
|
} // FdoChildRequestPowerUp
|
|
|
|
NTSTATUS
|
|
FdoChildRequestPowerUpCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PIRP childPowerIrp = Context;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PCHANPDO_EXTENSION pdoExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
fdoExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (NT_SUCCESS(IoStatus->Status)) {
|
|
|
|
ULONG numberOfChildrenPowerUp;
|
|
|
|
numberOfChildrenPowerUp = InterlockedIncrement (&fdoExtension->NumberOfChildrenPowerUp);
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation (childPowerIrp);
|
|
pdoExtension = irpStack->DeviceObject->DeviceExtension;
|
|
pdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState;
|
|
|
|
if (numberOfChildrenPowerUp > fdoExtension->NumberOfChildren) {
|
|
|
|
//
|
|
// should never happen. If it did, pretend it didn't
|
|
//
|
|
ASSERT (FALSE);
|
|
fdoExtension->NumberOfChildrenPowerUp = fdoExtension->NumberOfChildren;
|
|
}
|
|
|
|
}
|
|
|
|
childPowerIrp->IoStatus.Status = IoStatus->Status;
|
|
PoStartNextPowerIrp (childPowerIrp);
|
|
IoCompleteRequest(childPowerIrp, IO_NO_INCREMENT);
|
|
|
|
return IoStatus->Status;
|
|
} // FdoChildRequestPowerUpCompletionRoutine
|
|
|
|
|
|
NTSTATUS
|
|
FdoSystemPowerUpCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PIRP irp = Context;
|
|
|
|
//
|
|
// start the next system power irp
|
|
//
|
|
PoStartNextPowerIrp (irp);
|
|
|
|
if (!NT_SUCCESS(IoStatus->Status)) {
|
|
irp->IoStatus.Status = IoStatus->Status;
|
|
}
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|