755 lines
19 KiB
C
755 lines
19 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Suspend/Hibernate system
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Ken Reneris (kenr) 19-July-1994
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "pop.h"
|
|||
|
#include "zwapi.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInvalidDeviceRequest (
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#define NUMPASSES 4
|
|||
|
|
|||
|
//
|
|||
|
// Pass 1 - other
|
|||
|
// Pass 2 - disk & direct_io type drivers
|
|||
|
// Pass 3 - video type drivers
|
|||
|
// Pass 4 - ?
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
typedef struct _BROADCAST_Link {
|
|||
|
PDEVOBJ_EXTENSION DeviceObjectExt;
|
|||
|
LIST_ENTRY NotifyLink;
|
|||
|
LIST_ENTRY FailedLink;
|
|||
|
} BROADCAST_LINK, *PBROADCAST_LINK;
|
|||
|
|
|||
|
|
|||
|
typedef struct _BROADCAST_PASS {
|
|||
|
LIST_ENTRY NotifyList[1];
|
|||
|
} BROADCAST_PASS, *PBROADCAST_PASS;
|
|||
|
|
|||
|
typedef struct _BROADCAST_ORDER {
|
|||
|
ULONG NumPasses;
|
|||
|
ULONG NumLevels;
|
|||
|
PBROADCAST_PASS Pass[NUMPASSES];
|
|||
|
} BROADCAST_ORDER, *PBROADCAST_ORDER;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGEPO, NtSetSystemPowerState)
|
|||
|
#pragma alloc_text(PAGEPO, PopGetBroadcastOrder)
|
|||
|
#pragma alloc_text(PAGEPO, PopBroadcastSetPower)
|
|||
|
#pragma alloc_text(PAGEPO, PopReleaseBroadcast)
|
|||
|
#pragma alloc_text(PAGEPO, PoSystemResume)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NtSetSystemPowerState(
|
|||
|
IN POWER_STATE SystemPowerState,
|
|||
|
IN BOOLEAN NoResumeAlarm,
|
|||
|
IN BOOLEAN ForcePowerDown
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is invoked to suspend or hibernate the system. If the system
|
|||
|
can not currently support a suspend or hibernate then an error is returned.
|
|||
|
Suspend/Hibernate support requires that all currently loaded driver have
|
|||
|
power management support.
|
|||
|
|
|||
|
This call requires system Shutdown access.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NoResumeAlarm - If TRUE, then the system will be suspended or hibernated
|
|||
|
without setting any resume alarm. This should be used in the case
|
|||
|
of a critical low battery.
|
|||
|
|
|||
|
ForcePowerDown - If FALSE , then the devices are first sent a
|
|||
|
SET_POWER-Query. If all power off queries succeed then devices are
|
|||
|
sent a SET_POWER to suspend or hibernate; otherwise an error is
|
|||
|
returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Success - System was hibernated and has been resumed
|
|||
|
|
|||
|
error - Neither suspend nor hibernate did not occur due to the reported
|
|||
|
error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PVOID CodeLockHandle;
|
|||
|
NTSTATUS Status, Status2;
|
|||
|
LONGLONG Interval;
|
|||
|
PTIME_FIELDS ResumeTime;
|
|||
|
TIME_FIELDS TimeFields;
|
|||
|
LARGE_INTEGER LocalTime, SystemTime;
|
|||
|
PVOID BroadcastOrder;
|
|||
|
LIST_ENTRY FailedHead;
|
|||
|
PLIST_ENTRY Link;
|
|||
|
PBROADCAST_LINK BroadcastLink;
|
|||
|
PDEVICE_OBJECT FailedDeviceObject;
|
|||
|
POBJECT_NAME_INFORMATION ObjectName;
|
|||
|
BOOLEAN DeviceName;
|
|||
|
|
|||
|
|
|||
|
#ifndef _PNP_POWER_
|
|||
|
|
|||
|
return STATUS_NOT_IMPLEMENTED;
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
//
|
|||
|
// Verify PO system is fully initilaized
|
|||
|
//
|
|||
|
|
|||
|
if (!PoEnabled || !PoPowerSequence) {
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify caller has shutdown privilege
|
|||
|
//
|
|||
|
#if 0
|
|||
|
// BUGBUG: add this
|
|||
|
if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, KeGetPreviousMode())) {
|
|||
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG:
|
|||
|
// For now only support suspend
|
|||
|
//
|
|||
|
|
|||
|
if (SystemPowerState != PowerSuspend) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUGs:
|
|||
|
// Need to flush some/all dirty cache manager data
|
|||
|
//
|
|||
|
|
|||
|
BroadcastOrder = NULL;
|
|||
|
InitializeListHead (&FailedHead);
|
|||
|
|
|||
|
//
|
|||
|
// Entry critical region
|
|||
|
//
|
|||
|
|
|||
|
KeEnterCriticalRegion ();
|
|||
|
|
|||
|
//
|
|||
|
// About to attempt a system suspend / hibernate
|
|||
|
//
|
|||
|
|
|||
|
ExNotifyCallback (ExCbSuspendHibernateSystem, 0, 0);
|
|||
|
|
|||
|
//
|
|||
|
// Page in and Lock suspend/hibernate code in place
|
|||
|
// Obtain lock for DeviceObject list
|
|||
|
//
|
|||
|
|
|||
|
CodeLockHandle = MmLockPagableCodeSection (&NtSetSystemPowerState);
|
|||
|
PopLockDeviceList (TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Determine broadcasting order for all current device objects
|
|||
|
//
|
|||
|
|
|||
|
BroadcastOrder = PopGetBroadcastOrder ();
|
|||
|
if (!BroadcastOrder) {
|
|||
|
Status = STATUS_NO_MEMORY;
|
|||
|
goto CleanUp;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If not force power down, attempt to put all devices into
|
|||
|
// the queried powered down state
|
|||
|
//
|
|||
|
|
|||
|
if (!ForcePowerDown) {
|
|||
|
Status = PopBroadcastSetPower (
|
|||
|
BroadcastOrder,
|
|||
|
PowerQuery,
|
|||
|
&FailedHead
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
goto CleanUp;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query was sucessfull, release suspending flags so we
|
|||
|
// can flush the cache
|
|||
|
//
|
|||
|
|
|||
|
PopReleaseBroadcast (BroadcastOrder);
|
|||
|
|
|||
|
// BUGBUG: Flush some/all dirty cache manager data
|
|||
|
|
|||
|
//
|
|||
|
// Put devices back into the powered-down query state
|
|||
|
//
|
|||
|
|
|||
|
Status = PopBroadcastSetPower (
|
|||
|
BroadcastOrder,
|
|||
|
PowerQuery,
|
|||
|
&FailedHead
|
|||
|
) ;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
// Ohps, query failed this time around
|
|||
|
goto CleanUp;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Put devices into PowerDown-Suspend or PowerDown-Hibernate state
|
|||
|
//
|
|||
|
|
|||
|
Status = PopBroadcastSetPower (
|
|||
|
BroadcastOrder,
|
|||
|
SystemPowerState,
|
|||
|
&FailedHead
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
goto CleanUp;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine systems resume time
|
|||
|
//
|
|||
|
|
|||
|
ResumeTime = NULL;
|
|||
|
Interval = 0;
|
|||
|
NoResumeAlarm = FALSE; // BUGBUG
|
|||
|
|
|||
|
if (!NoResumeAlarm) {
|
|||
|
|
|||
|
// fill in Interval and TimeFields
|
|||
|
|
|||
|
if (Interval < 150000000) {
|
|||
|
PoDbgPrint (PODIAG1, "PO: Suspend aborted due to critical resume\n");
|
|||
|
goto CleanUp;
|
|||
|
}
|
|||
|
|
|||
|
ResumeTime = &TimeFields;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Suspend or PowerOff the box
|
|||
|
//
|
|||
|
|
|||
|
Status = KeSuspendHibernateSystem (
|
|||
|
ResumeTime,
|
|||
|
NULL /* bugbug hibernate */
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If machine was successfully suspended/hibernated then resumed,
|
|||
|
// reset the time
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) &&
|
|||
|
HalQueryRealTimeClock(&TimeFields) &&
|
|||
|
RtlTimeFieldsToTime(&TimeFields, &LocalTime) ) {
|
|||
|
|
|||
|
ExLocalTimeToSystemTime(&LocalTime,&SystemTime);
|
|||
|
ZwSetSystemTime(&SystemTime,NULL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
CleanUp:
|
|||
|
ExNotifyCallback (ExCbSuspendHibernateSystem, (PVOID) 1, (PVOID) Status);
|
|||
|
|
|||
|
//
|
|||
|
// Release suspending flags and allow drivers to powerup if they want.
|
|||
|
// But, don't free the BroadcastOrder memory yet
|
|||
|
//
|
|||
|
|
|||
|
if (BroadcastOrder) {
|
|||
|
PopReleaseBroadcast (BroadcastOrder);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release DeviceObject list
|
|||
|
// Release suspend/hibernate code
|
|||
|
//
|
|||
|
|
|||
|
PopUnlockDeviceList ();
|
|||
|
MmUnlockPagableImageSection (CodeLockHandle);
|
|||
|
|
|||
|
//
|
|||
|
// If there was a failure
|
|||
|
//
|
|||
|
|
|||
|
if (!IsListEmpty(&FailedHead)) {
|
|||
|
|
|||
|
//
|
|||
|
// Failure due to some device - capture it's name and generate
|
|||
|
// a popup
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If there's a failing device object, capture it's name
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
for (Link=FailedHead.Flink; Link != &FailedHead; Link = Link->Flink) {
|
|||
|
BroadcastLink = CONTAINING_RECORD (Link,
|
|||
|
BROADCAST_LINK,
|
|||
|
FailedLink );
|
|||
|
|
|||
|
FailedDeviceObject = BroadcastLink->DeviceObjectExt->DeviceObject;
|
|||
|
|
|||
|
ObjectName = PopGetDeviceName (FailedDeviceObject);
|
|||
|
if (ObjectName) {
|
|||
|
#if DBG
|
|||
|
DbgPrint ("PO: Device %08x '%Z' failed system suspend\n",
|
|||
|
FailedDeviceObject, &ObjectName->Name);
|
|||
|
#endif
|
|||
|
|
|||
|
ExFreePool (ObjectName);
|
|||
|
}
|
|||
|
ObDereferenceObject (FailedDeviceObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (BroadcastOrder) {
|
|||
|
ExFreePool (BroadcastOrder);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Leave critial region
|
|||
|
//
|
|||
|
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
return Status;
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
|
|||
|
PVOID
|
|||
|
PopGetBroadcastOrder (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Builds information on how to notify current drivers of a
|
|||
|
PowerDown due to a suspend or hibernate request
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY Link;
|
|||
|
PDEVOBJ_EXTENSION DeviceObjectExt;
|
|||
|
PDRIVER_OBJECT DriverObject;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
ULONG MaxStackSize;
|
|||
|
ULONG NumObjects;
|
|||
|
ULONG Size1, Size2;
|
|||
|
ULONG p, l;
|
|||
|
PVOID LastLoc;
|
|||
|
PBROADCAST_ORDER BroadcastOrder;
|
|||
|
PBROADCAST_PASS BroadcastPass;
|
|||
|
PBROADCAST_LINK BroadcastLink;
|
|||
|
|
|||
|
//
|
|||
|
// Run all DeviceObjects are determine the largest StackSize
|
|||
|
//
|
|||
|
|
|||
|
MaxStackSize = 0;
|
|||
|
NumObjects = 0;
|
|||
|
for (Link = PopDeviceList.Flink; Link != &PopDeviceList; Link = Link->Flink) {
|
|||
|
DeviceObjectExt = CONTAINING_RECORD(Link, DEVOBJ_EXTENSION, AllDeviceObjects);
|
|||
|
|
|||
|
NumObjects++;
|
|||
|
if ((ULONG) DeviceObjectExt->DeviceObject->StackSize > MaxStackSize) {
|
|||
|
MaxStackSize = DeviceObjectExt->DeviceObject->StackSize;
|
|||
|
ASSERT (MaxStackSize < 50);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory to track ordering
|
|||
|
//
|
|||
|
|
|||
|
Size1 = sizeof(BROADCAST_PASS) * NUMPASSES * (MaxStackSize+2) +
|
|||
|
sizeof(BROADCAST_ORDER);
|
|||
|
Size2 = sizeof(BROADCAST_LINK) * (NumObjects+2);
|
|||
|
|
|||
|
BroadcastOrder = ExAllocatePoolWithTag ( NonPagedPool, Size1+Size2, 'psuS');
|
|||
|
LastLoc = ((PUCHAR) BroadcastOrder) + Size1 + Size2;
|
|||
|
if (!BroadcastOrder) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize structure
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory (BroadcastOrder, Size1+Size2);
|
|||
|
BroadcastOrder->NumPasses = NUMPASSES;
|
|||
|
BroadcastOrder->NumLevels = MaxStackSize;
|
|||
|
BroadcastPass = (PBROADCAST_PASS) (((PUCHAR) BroadcastOrder) +
|
|||
|
sizeof (BROADCAST_ORDER));
|
|||
|
|
|||
|
for (p=0; p < NUMPASSES; p++) {
|
|||
|
BroadcastOrder->Pass[p] = BroadcastPass;
|
|||
|
for (l=0; l <= MaxStackSize; l++) {
|
|||
|
InitializeListHead (&BroadcastPass->NotifyList[l]);
|
|||
|
}
|
|||
|
|
|||
|
BroadcastPass += MaxStackSize + 1;
|
|||
|
ASSERT ((PVOID) BroadcastPass < LastLoc);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Run drivers and put each driver on appropiate list
|
|||
|
//
|
|||
|
|
|||
|
BroadcastLink = (PBROADCAST_LINK) BroadcastPass;
|
|||
|
for (Link = PopDeviceList.Flink; Link != &PopDeviceList; Link = Link->Flink) {
|
|||
|
DeviceObjectExt = CONTAINING_RECORD(Link, DEVOBJ_EXTENSION, AllDeviceObjects);
|
|||
|
DeviceObject = DeviceObjectExt->DeviceObject;
|
|||
|
DriverObject = DeviceObject->DriverObject;
|
|||
|
|
|||
|
//
|
|||
|
// Pick pass DeviceType
|
|||
|
//
|
|||
|
|
|||
|
switch (DeviceObject->DeviceType) {
|
|||
|
case FILE_DEVICE_DISK: p = 1; break;
|
|||
|
case FILE_DEVICE_CD_ROM: p = 1; break;
|
|||
|
case FILE_DEVICE_VIRTUAL_DISK: p = 1; break;
|
|||
|
case FILE_DEVICE_VIDEO: p = 2; break;
|
|||
|
default: p = 0; break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (p < 1 && DeviceObject->Flags & DO_DIRECT_IO) {
|
|||
|
// Some type of disk device, should be at least in 2nd pass
|
|||
|
p = 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Insert into queue
|
|||
|
//
|
|||
|
|
|||
|
BroadcastLink->DeviceObjectExt = DeviceObjectExt;
|
|||
|
InsertTailList (
|
|||
|
&BroadcastOrder->Pass[p]->NotifyList[DeviceObject->StackSize],
|
|||
|
&BroadcastLink->NotifyLink
|
|||
|
);
|
|||
|
|
|||
|
BroadcastLink += 1;
|
|||
|
ASSERT ((PVOID) BroadcastLink < LastLoc);
|
|||
|
}
|
|||
|
|
|||
|
return BroadcastOrder;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PopBroadcastSetPower (
|
|||
|
IN PVOID pBroadcastOrder,
|
|||
|
IN POWER_STATE PowerState,
|
|||
|
OUT PLIST_ENTRY FailedHead
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine attempts to set every device into the power state of
|
|||
|
PowerState. In addition the devices will stay in the requested
|
|||
|
state until released. (ie, any requested power on will be blocked).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BroadcastOrder - Value returned from PopGetBroadcastOrder
|
|||
|
PowerState - System suspend or hibernate state to put every device in
|
|||
|
FailedHead - If not successful the first device object encounted
|
|||
|
which the requested state failed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Success - All devices have been put into the requested state
|
|||
|
|
|||
|
error - All devices were not set into the requested state (some may
|
|||
|
have been).
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG p;
|
|||
|
LONG l;
|
|||
|
PLIST_ENTRY ListHead, Link;
|
|||
|
KIRQL OldIrql;
|
|||
|
NTSTATUS Status;
|
|||
|
LARGE_INTEGER Timeout;
|
|||
|
PBROADCAST_ORDER BroadcastOrder;
|
|||
|
PBROADCAST_LINK BroadcastLink;
|
|||
|
PDEVOBJ_EXTENSION DeviceObjectExt;
|
|||
|
POBJECT_NAME_INFORMATION ObjectName;
|
|||
|
POWER_STATE NewState;
|
|||
|
|
|||
|
ASSERT (IsListEmpty (FailedHead));
|
|||
|
|
|||
|
//
|
|||
|
// Notify all drivers
|
|||
|
//
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
BroadcastOrder = (PBROADCAST_ORDER) pBroadcastOrder;
|
|||
|
for (p=0; NT_SUCCESS(Status) && p < BroadcastOrder->NumPasses; p++) {
|
|||
|
|
|||
|
//
|
|||
|
// Start at high levels and work down
|
|||
|
//
|
|||
|
|
|||
|
for (l=BroadcastOrder->NumLevels; NT_SUCCESS(Status) && l >=0; l--) {
|
|||
|
|
|||
|
ListHead = &BroadcastOrder->Pass[p]->NotifyList[l];
|
|||
|
|
|||
|
//
|
|||
|
// Lock database & notify this run of drivers
|
|||
|
//
|
|||
|
|
|||
|
PopLockStateDatabase (&OldIrql);
|
|||
|
for (Link=ListHead->Flink; Link != ListHead; Link = Link->Flink) {
|
|||
|
BroadcastLink = CONTAINING_RECORD (Link,
|
|||
|
BROADCAST_LINK,
|
|||
|
NotifyLink );
|
|||
|
|
|||
|
//
|
|||
|
// Don't let device power back on
|
|||
|
//
|
|||
|
|
|||
|
BroadcastLink->DeviceObjectExt->Suspending = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Request device to Power down
|
|||
|
//
|
|||
|
|
|||
|
PopRequestPowerChange (
|
|||
|
BroadcastLink->DeviceObjectExt,
|
|||
|
PowerState,
|
|||
|
0
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Wait for all current power irps to complete
|
|||
|
//
|
|||
|
|
|||
|
if (!PopIsStateDatabaseIdle()) {
|
|||
|
KeClearEvent (&PopStateDatabaseIdle);
|
|||
|
|
|||
|
PopUnlockStateDatabase (OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG: need some deadlock detection here
|
|||
|
//
|
|||
|
|
|||
|
Status = KeWaitForSingleObject (
|
|||
|
&PopStateDatabaseIdle,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
PopLockStateDatabase (&OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify all devices sucessfully set their power settings
|
|||
|
//
|
|||
|
|
|||
|
for (Link=ListHead->Flink; Link != ListHead; Link = Link->Flink) {
|
|||
|
BroadcastLink = CONTAINING_RECORD (Link,
|
|||
|
BROADCAST_LINK,
|
|||
|
NotifyLink );
|
|||
|
|
|||
|
DeviceObjectExt = BroadcastLink->DeviceObjectExt;
|
|||
|
|
|||
|
NewState = DeviceObjectExt->CurrentPowerState;
|
|||
|
if (NewState != PowerState) {
|
|||
|
|
|||
|
//
|
|||
|
// The device's state does not match the target state.
|
|||
|
// Check to see if the combination of newstate to targetstate
|
|||
|
// is the current device's state.
|
|||
|
//
|
|||
|
|
|||
|
if (NewState != PopNewPendingState[NewState][PowerState]) {
|
|||
|
|
|||
|
//
|
|||
|
// Device is not in an acceptable state
|
|||
|
//
|
|||
|
|
|||
|
ObReferenceObjectByPointer (
|
|||
|
DeviceObjectExt->DeviceObject,
|
|||
|
(ACCESS_MASK) NULL,
|
|||
|
IoDeviceObjectType,
|
|||
|
KernelMode
|
|||
|
);
|
|||
|
|
|||
|
InsertTailList (FailedHead, &BroadcastLink->FailedLink);
|
|||
|
|
|||
|
// BUGBUG: for now let it pass...
|
|||
|
// BUGBUG: return STATUS_SUSPEND_FAILED;
|
|||
|
Status = STATUS_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PopUnlockStateDatabase (OldIrql);
|
|||
|
} // next level
|
|||
|
} // next pass
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PopReleaseBroadcast (
|
|||
|
IN PVOID BroadcastOrder
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine releases the suspend lock on any devices power state such
|
|||
|
that the device can power on if it requests too.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BroadcastOrder - Value returned from PopGetBroadcastOrder
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrql;
|
|||
|
PLIST_ENTRY Link;
|
|||
|
PDEVOBJ_EXTENSION DeviceObjectExt;
|
|||
|
|
|||
|
PopLockStateDatabase (&OldIrql);
|
|||
|
|
|||
|
for (Link = PopDeviceList.Flink; Link != &PopDeviceList; Link = Link->Flink) {
|
|||
|
DeviceObjectExt = CONTAINING_RECORD(Link, DEVOBJ_EXTENSION, AllDeviceObjects);
|
|||
|
|
|||
|
//
|
|||
|
// Request to set to pending state
|
|||
|
//
|
|||
|
|
|||
|
if (DeviceObjectExt->Suspending) {
|
|||
|
|
|||
|
//
|
|||
|
// Let device go
|
|||
|
//
|
|||
|
|
|||
|
DeviceObjectExt->Suspending = FALSE;
|
|||
|
PopRequestPowerChange (DeviceObjectExt, 0, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PopUnlockStateDatabase (OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PoSystemResume (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by the kernel as the machine is resuming from
|
|||
|
a successful system suspend or hibernate.
|
|||
|
|
|||
|
WARNING: This function is called at HIGH_LEVEL while all processors
|
|||
|
(expect the calling processor) are still frozen.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY Link;
|
|||
|
PDEVOBJ_EXTENSION DeviceObjectExt;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PDRIVER_OBJECT DriverObject;
|
|||
|
PDRIVER_DISPATCH MajorFunction;
|
|||
|
|
|||
|
//
|
|||
|
// Increase PowerSequnce
|
|||
|
//
|
|||
|
|
|||
|
PoPowerSequence += 1;
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Notify all driver's PowerNotify routines
|
|||
|
//
|
|||
|
|
|||
|
for (Link = PopDeviceList.Flink; Link != &PopDeviceList; Link = Link->Flink) {
|
|||
|
DeviceObjectExt = CONTAINING_RECORD(Link, DEVOBJ_EXTENSION, AllDeviceObjects);
|
|||
|
DeviceObject = DeviceObjectExt->DeviceObject;
|
|||
|
DriverObject = DeviceObject->DriverObject;
|
|||
|
|
|||
|
//
|
|||
|
// Notify device's PowerNotify routine
|
|||
|
//
|
|||
|
|
|||
|
MajorFunction = DriverObject->MajorFunction[IRP_MJ_POWER_NOTIFY];
|
|||
|
if (MajorFunction != IopInvalidDeviceRequest) {
|
|||
|
MajorFunction (DeviceObject, (PIRP) 0);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#endif // _PNP_POWER_
|