2607 lines
68 KiB
C
2607 lines
68 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
pinfo.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the generic power policy information interfaces
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Ken Reneris (kenr) 17-Jan-1997
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "pop.h"
|
|||
|
|
|||
|
//
|
|||
|
// Internal prototypes
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyPowerPolicy (
|
|||
|
IN BOOLEAN Ac,
|
|||
|
IN PSYSTEM_POWER_POLICY InputPolicy,
|
|||
|
OUT PSYSTEM_POWER_POLICY PowerPolicy
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyProcessorPowerPolicy (
|
|||
|
IN BOOLEAN Ac,
|
|||
|
IN PPROCESSOR_POWER_POLICY InputPolicy,
|
|||
|
OUT PPROCESSOR_POWER_POLICY PowerPolicy
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyThrottle (
|
|||
|
IN PUCHAR Throttle,
|
|||
|
IN UCHAR Min
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PopApplyPolicy (
|
|||
|
IN BOOLEAN UpdateRegistry,
|
|||
|
IN BOOLEAN AcPolicy,
|
|||
|
IN PSYSTEM_POWER_POLICY NewPolicy,
|
|||
|
IN ULONG PolicyLength
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PopApplyProcessorPolicy (
|
|||
|
IN BOOLEAN UpdateRegistry,
|
|||
|
IN BOOLEAN AcPolicy,
|
|||
|
IN PPROCESSOR_POWER_POLICY NewPolicy,
|
|||
|
IN ULONG PolicyLength
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PopFilterCapabilities(
|
|||
|
IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
|
|||
|
OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PopUserIsAdmin(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, NtPowerInformation)
|
|||
|
#pragma alloc_text(PAGE, PopApplyAdminPolicy)
|
|||
|
#pragma alloc_text(PAGE, PopApplyPolicy)
|
|||
|
#pragma alloc_text(PAGE, PopVerifyPowerPolicy)
|
|||
|
#pragma alloc_text(PAGE, PopVerifyPowerActionPolicy)
|
|||
|
#pragma alloc_text(PAGE, PopVerifySystemPowerState)
|
|||
|
#pragma alloc_text(PAGE, PopAdvanceSystemPowerState)
|
|||
|
#pragma alloc_text(PAGE, PopResetCurrentPolicies)
|
|||
|
#pragma alloc_text(PAGE, PopNotifyPolicyDevice)
|
|||
|
#pragma alloc_text(PAGE, PopConnectToPolicyDevice)
|
|||
|
#pragma alloc_text(PAGE, PopFilterCapabilities)
|
|||
|
#pragma alloc_text(PAGE, PopUserIsAdmin)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NtPowerInformation (
|
|||
|
IN POWER_INFORMATION_LEVEL InformationLevel,
|
|||
|
IN PVOID InputBuffer OPTIONAL,
|
|||
|
IN ULONG InputBufferLength,
|
|||
|
OUT PVOID OutputBuffer OPTIONAL,
|
|||
|
IN ULONG OutputBufferLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function optional sets, and gets current power policy information
|
|||
|
based on the InformationLevel.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InputBuffer - Input to set InformationLevel information.
|
|||
|
|
|||
|
InputBufferLength - Size, in bytes, of InputBuffer
|
|||
|
|
|||
|
OutputBuffer - Buffer to return InformationLevel information.
|
|||
|
|
|||
|
OutputBufferLength - Size, in bytes, of OutputBuffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PVOID ReturnBuffer;
|
|||
|
ULONG ReturnBufferLength;
|
|||
|
KPROCESSOR_MODE PreviousMode;
|
|||
|
PPOWER_STATE_HANDLER PowerHandler;
|
|||
|
PBOOLEAN CapFlag;
|
|||
|
PVOID CapBuffer;
|
|||
|
BOOLEAN Enable;
|
|||
|
ULONG HandlerType;
|
|||
|
SYSTEM_POWER_STATE RtcWake;
|
|||
|
BOOLEAN CheckForWork = InputBuffer ? TRUE : FALSE;
|
|||
|
union {
|
|||
|
PROCESSOR_POWER_POLICY ProcessorPolicy;
|
|||
|
SYSTEM_POWER_POLICY PowerPolicy;
|
|||
|
SYSTEM_BATTERY_STATE PowerState;
|
|||
|
SYSTEM_POWER_INFORMATION SysInfo;
|
|||
|
PROCESSOR_POWER_INFORMATION ProcInfo[MAXIMUM_PROCESSORS];
|
|||
|
SYSTEM_POWER_CAPABILITIES PowerCapabilities;
|
|||
|
EXECUTION_STATE SystemExecutionState;
|
|||
|
} Buf;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
ReturnBuffer = NULL;
|
|||
|
ReturnBufferLength = 0;
|
|||
|
CapBuffer = NULL;
|
|||
|
PreviousMode = KeGetPreviousMode();
|
|||
|
|
|||
|
PopAcquirePolicyLock ();
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// If caller is user mode make some verifications
|
|||
|
//
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
|
|||
|
//
|
|||
|
// Is caller attempting to set anything?
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
if (InformationLevel != VerifySystemPolicyAc &&
|
|||
|
InformationLevel != VerifySystemPolicyDc &&
|
|||
|
InformationLevel != VerifyProcessorPowerPolicyAc &&
|
|||
|
InformationLevel != VerifyProcessorPowerPolicyDc) {
|
|||
|
|
|||
|
//
|
|||
|
// Make access check
|
|||
|
//
|
|||
|
if (InformationLevel == SystemReserveHiberFile) {
|
|||
|
|
|||
|
//
|
|||
|
// Only allow callers that have create pagefile privilege
|
|||
|
// to enable/disable the hibernate file
|
|||
|
//
|
|||
|
if (!SeSinglePrivilegeCheck(SeCreatePagefilePrivilege,PreviousMode)) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_PRIVILEGE_NOT_HELD);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_PRIVILEGE_NOT_HELD);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify input addresses
|
|||
|
//
|
|||
|
ProbeForRead (
|
|||
|
InputBuffer,
|
|||
|
InputBufferLength,
|
|||
|
InputBufferLength >= sizeof (ULONG) ? sizeof(ULONG) : sizeof(UCHAR)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify output addresses
|
|||
|
//
|
|||
|
if (OutputBuffer) {
|
|||
|
|
|||
|
ProbeForWrite (OutputBuffer, OutputBufferLength, sizeof(ULONG));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Handle request
|
|||
|
//
|
|||
|
switch (InformationLevel) {
|
|||
|
case SystemPowerPolicyAc:
|
|||
|
|
|||
|
//
|
|||
|
// We can be asked to set the AC policy through this mechanism
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
PopApplyPolicy (
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
(PSYSTEM_POWER_POLICY) InputBuffer,
|
|||
|
InputBufferLength
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current AC policy
|
|||
|
//
|
|||
|
ReturnBuffer = &PopAcPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopAcPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerPolicyDc:
|
|||
|
|
|||
|
//
|
|||
|
// We can be asked to set the DC policy through this mechanism
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
PopApplyPolicy (
|
|||
|
TRUE,
|
|||
|
FALSE,
|
|||
|
(PSYSTEM_POWER_POLICY) InputBuffer,
|
|||
|
InputBufferLength
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current DC policy
|
|||
|
//
|
|||
|
ReturnBuffer = &PopDcPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopDcPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case ProcessorPowerPolicyAc:
|
|||
|
|
|||
|
//
|
|||
|
// We can be asked to set the AC processor policy
|
|||
|
// through this mechanism
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
PopApplyProcessorPolicy(
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
(PPROCESSOR_POWER_POLICY) InputBuffer,
|
|||
|
InputBufferLength
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current AC processor policy
|
|||
|
//
|
|||
|
ReturnBuffer = &PopAcProcessorPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopAcProcessorPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case ProcessorPowerPolicyDc:
|
|||
|
|
|||
|
//
|
|||
|
// We can be asked to set the DC processor policy
|
|||
|
// through this mechanism
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
PopApplyProcessorPolicy(
|
|||
|
TRUE,
|
|||
|
FALSE,
|
|||
|
(PPROCESSOR_POWER_POLICY) InputBuffer,
|
|||
|
InputBufferLength
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current DC processor policy
|
|||
|
//
|
|||
|
ReturnBuffer = &PopDcProcessorPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopDcProcessorPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case AdministratorPowerPolicy:
|
|||
|
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
if (PopUserIsAdmin()) {
|
|||
|
|
|||
|
PopApplyAdminPolicy(
|
|||
|
TRUE,
|
|||
|
(PADMINISTRATOR_POWER_POLICY) InputBuffer,
|
|||
|
InputBufferLength
|
|||
|
);
|
|||
|
PopResetCurrentPolicies ();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return administrator policy
|
|||
|
//
|
|||
|
ReturnBuffer = &PopAdminPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopAdminPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case VerifySystemPolicyAc:
|
|||
|
|
|||
|
if (InputBuffer && OutputBuffer) {
|
|||
|
|
|||
|
if (InputBufferLength >= sizeof (SYSTEM_POWER_POLICY)) {
|
|||
|
|
|||
|
PopVerifyPowerPolicy (TRUE, InputBuffer, &Buf.PowerPolicy);
|
|||
|
ReturnBuffer = &Buf.PowerPolicy;
|
|||
|
ReturnBufferLength = sizeof(Buf.PowerPolicy);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case VerifySystemPolicyDc:
|
|||
|
|
|||
|
if (InputBuffer && OutputBuffer) {
|
|||
|
|
|||
|
if (InputBufferLength >= sizeof (SYSTEM_POWER_POLICY)) {
|
|||
|
|
|||
|
PopVerifyPowerPolicy (FALSE, InputBuffer, &Buf.PowerPolicy);
|
|||
|
ReturnBuffer = &Buf.PowerPolicy;
|
|||
|
ReturnBufferLength = sizeof(Buf.PowerPolicy);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case VerifyProcessorPowerPolicyAc:
|
|||
|
|
|||
|
if (InputBuffer && OutputBuffer) {
|
|||
|
|
|||
|
if (InputBufferLength >= sizeof (PROCESSOR_POWER_POLICY)) {
|
|||
|
|
|||
|
PopVerifyProcessorPowerPolicy(
|
|||
|
TRUE,
|
|||
|
InputBuffer,
|
|||
|
&Buf.ProcessorPolicy
|
|||
|
);
|
|||
|
ReturnBuffer = &Buf.ProcessorPolicy;
|
|||
|
ReturnBufferLength = sizeof(Buf.ProcessorPolicy);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case VerifyProcessorPowerPolicyDc:
|
|||
|
|
|||
|
if (InputBuffer && OutputBuffer) {
|
|||
|
|
|||
|
if (InputBufferLength >= sizeof (PROCESSOR_POWER_POLICY)) {
|
|||
|
|
|||
|
PopVerifyProcessorPowerPolicy(
|
|||
|
FALSE,
|
|||
|
InputBuffer,
|
|||
|
&Buf.ProcessorPolicy
|
|||
|
);
|
|||
|
ReturnBuffer = &Buf.ProcessorPolicy;
|
|||
|
ReturnBufferLength = sizeof(Buf.ProcessorPolicy);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerPolicyCurrent:
|
|||
|
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current policy
|
|||
|
//
|
|||
|
ReturnBuffer = PopPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopAcPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case ProcessorPowerPolicyCurrent:
|
|||
|
|
|||
|
if (InputBuffer) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return current policy
|
|||
|
//
|
|||
|
ReturnBuffer = PopProcessorPolicy;
|
|||
|
ReturnBufferLength = sizeof(PopAcProcessorPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerCapabilities:
|
|||
|
|
|||
|
// if we allow the simulation of capabilities (for testing), then
|
|||
|
// let it through
|
|||
|
|
|||
|
if (InputBuffer) {
|
|||
|
if ((PopSimulate & POP_SIM_CAPABILITIES) && InputBufferLength == sizeof(PopCapabilities)) {
|
|||
|
memcpy (&PopCapabilities, InputBuffer, InputBufferLength);
|
|||
|
PopResetCurrentPolicies ();
|
|||
|
PopSetNotificationWork (PO_NOTIFY_CAPABILITIES);
|
|||
|
} else {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PopCapabilities.FullWake = (PopFullWake & PO_FULL_WAKE_STATUS) ? TRUE : FALSE;
|
|||
|
PopCapabilities.DiskSpinDown =
|
|||
|
PopAttributes[POP_DISK_SPINDOWN_ATTRIBUTE].Count ? TRUE : FALSE;
|
|||
|
|
|||
|
PopFilterCapabilities(&PopCapabilities, &Buf.PowerCapabilities);
|
|||
|
|
|||
|
ReturnBuffer = &Buf.PowerCapabilities;
|
|||
|
ReturnBufferLength = sizeof(PopCapabilities);
|
|||
|
break;
|
|||
|
|
|||
|
case SystemBatteryState:
|
|||
|
PopCurrentPowerState (&Buf.PowerState);
|
|||
|
ReturnBuffer = &Buf.PowerState;
|
|||
|
ReturnBufferLength = sizeof(Buf.PowerState);
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerStateHandler:
|
|||
|
//
|
|||
|
// Caller must be kernel mode with the proper parameters
|
|||
|
//
|
|||
|
|
|||
|
if (PreviousMode != KernelMode || OutputBuffer || !InputBuffer) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Handler can only be registered once
|
|||
|
//
|
|||
|
|
|||
|
PowerHandler = (PPOWER_STATE_HANDLER) InputBuffer;
|
|||
|
HandlerType = PowerHandler->Type;
|
|||
|
if (HandlerType >= PowerStateMaximum) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// He can only be registered once UNLESS it's the
|
|||
|
// PowerStateShutdownOff handler. That's because
|
|||
|
// we've set a default shutdown handler and would
|
|||
|
// sure welcome someone else (e.g. hal) to come along
|
|||
|
// and overwrite our default.
|
|||
|
//
|
|||
|
if( (PopPowerStateHandlers[HandlerType].Handler) ) {
|
|||
|
|
|||
|
//
|
|||
|
// There's already a handler here. The only way
|
|||
|
// we're going to let this request through is if
|
|||
|
// they're setting the PowerStateShutdownOff
|
|||
|
// handler *AND* the current handler is pointing
|
|||
|
// to PopShutdownHandler().
|
|||
|
//
|
|||
|
if( !((HandlerType == PowerStateShutdownOff) &&
|
|||
|
(PopPowerStateHandlers[HandlerType].Handler == PopShutdownHandler)) ) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set new handler
|
|||
|
//
|
|||
|
|
|||
|
PopPowerStateHandlers[HandlerType] = *PowerHandler;
|
|||
|
PopPowerStateHandlers[HandlerType].Spare[0] = 0;
|
|||
|
PopPowerStateHandlers[HandlerType].Spare[1] = 0;
|
|||
|
PopPowerStateHandlers[HandlerType].Spare[2] = 0;
|
|||
|
|
|||
|
CapFlag = NULL;
|
|||
|
RtcWake = PowerSystemUnspecified;
|
|||
|
switch (HandlerType) {
|
|||
|
case PowerStateSleeping1:
|
|||
|
if (!(PopSimulate & POP_IGNORE_S1)) {
|
|||
|
CapFlag = &PopCapabilities.SystemS1;
|
|||
|
}
|
|||
|
RtcWake = PowerSystemSleeping1;
|
|||
|
break;
|
|||
|
|
|||
|
case PowerStateSleeping2:
|
|||
|
if (!(PopSimulate & POP_IGNORE_S2)) {
|
|||
|
CapFlag = &PopCapabilities.SystemS2;
|
|||
|
}
|
|||
|
RtcWake = PowerSystemSleeping2;
|
|||
|
break;
|
|||
|
|
|||
|
case PowerStateSleeping3:
|
|||
|
if (!(PopSimulate & POP_IGNORE_S3)) {
|
|||
|
CapFlag = &PopCapabilities.SystemS3;
|
|||
|
}
|
|||
|
RtcWake = PowerSystemSleeping3;
|
|||
|
break;
|
|||
|
|
|||
|
case PowerStateSleeping4:
|
|||
|
if (!(PopSimulate & POP_IGNORE_S4)) {
|
|||
|
CapFlag = &PopCapabilities.SystemS4;
|
|||
|
}
|
|||
|
RtcWake = PowerSystemHibernate;
|
|||
|
break;
|
|||
|
|
|||
|
case PowerStateShutdownOff:
|
|||
|
CapFlag = &PopCapabilities.SystemS5;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (!PopPowerStateHandlers[HandlerType].RtcWake) {
|
|||
|
RtcWake = PowerSystemUnspecified;
|
|||
|
}
|
|||
|
|
|||
|
if (RtcWake > PopCapabilities.RtcWake) {
|
|||
|
PopCapabilities.RtcWake = RtcWake;
|
|||
|
}
|
|||
|
|
|||
|
if (CapFlag) {
|
|||
|
PopSetCapability (CapFlag);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerStateNotifyHandler:
|
|||
|
//
|
|||
|
// Caller must be kernel mode with the proper parameters
|
|||
|
//
|
|||
|
|
|||
|
if (PreviousMode != KernelMode || OutputBuffer) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Notify handler can only be registered once.
|
|||
|
//
|
|||
|
|
|||
|
if (PopPowerStateNotifyHandler.Handler &&
|
|||
|
((PPOWER_STATE_NOTIFY_HANDLER)InputBuffer)->Handler) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set new handler
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(InputBufferLength == sizeof(POWER_STATE_NOTIFY_HANDLER));
|
|||
|
|
|||
|
RtlCopyMemory(&PopPowerStateNotifyHandler,
|
|||
|
InputBuffer,
|
|||
|
sizeof(POWER_STATE_NOTIFY_HANDLER));
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ProcessorStateHandler:
|
|||
|
case ProcessorStateHandler2:
|
|||
|
//
|
|||
|
// Caller must be kernel mode with the proper parameters
|
|||
|
//
|
|||
|
|
|||
|
if (PreviousMode != KernelMode || OutputBuffer || !InputBuffer) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Install handlers
|
|||
|
//
|
|||
|
|
|||
|
try {
|
|||
|
if (InformationLevel == ProcessorStateHandler2) {
|
|||
|
PopInitProcessorStateHandlers2 ((PPROCESSOR_STATE_HANDLER2) InputBuffer);
|
|||
|
} else {
|
|||
|
PopInitProcessorStateHandlers ((PPROCESSOR_STATE_HANDLER) InputBuffer);
|
|||
|
}
|
|||
|
} except (PopExceptionFilter(GetExceptionInformation(), FALSE)) {
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reset policies as capabilities may have changed
|
|||
|
//
|
|||
|
|
|||
|
PopResetCurrentPolicies ();
|
|||
|
break;
|
|||
|
|
|||
|
case SystemReserveHiberFile:
|
|||
|
//
|
|||
|
// If previous mode isn't kernel mode, change it
|
|||
|
//
|
|||
|
|
|||
|
if (InputBufferLength != sizeof(BOOLEAN)) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
Enable = *((PBOOLEAN) InputBuffer);
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
PopReleasePolicyLock (FALSE);
|
|||
|
Status = ZwPowerInformation(SystemReserveHiberFile,
|
|||
|
&Enable,
|
|||
|
sizeof (Enable),
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
PopAcquirePolicyLock ();
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
Status = PopEnableHiberFile (Enable);
|
|||
|
} except (PopExceptionFilter(GetExceptionInformation(), FALSE)) {
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case SystemPowerInformation:
|
|||
|
Buf.SysInfo.MaxIdlenessAllowed = PopSIdle.Sensitivity;
|
|||
|
Buf.SysInfo.Idleness = PopSIdle.Idleness;
|
|||
|
Buf.SysInfo.TimeRemaining = (PopSIdle.Timeout - PopSIdle.Time) * SYS_IDLE_WORKER;
|
|||
|
Buf.SysInfo.CoolingMode = (UCHAR) PopCoolingMode;
|
|||
|
ReturnBuffer = &Buf.SysInfo;
|
|||
|
ReturnBufferLength = sizeof(Buf.SysInfo);
|
|||
|
break;
|
|||
|
|
|||
|
case ProcessorInformation:
|
|||
|
{
|
|||
|
ULONG length;
|
|||
|
|
|||
|
length = sizeof(PROCESSOR_POWER_INFORMATION) * MAXIMUM_PROCESSORS;
|
|||
|
if (length > OutputBufferLength) {
|
|||
|
|
|||
|
length = OutputBufferLength;
|
|||
|
|
|||
|
}
|
|||
|
PopProcessorInformation ( Buf.ProcInfo, length, &ReturnBufferLength );
|
|||
|
ReturnBuffer = &Buf.ProcInfo;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
case LastWakeTime:
|
|||
|
|
|||
|
//
|
|||
|
// This is output only
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
ReturnBuffer = &PopAction.WakeTime;
|
|||
|
ReturnBufferLength = sizeof(PopAction.WakeTime);
|
|||
|
break;
|
|||
|
|
|||
|
case LastSleepTime:
|
|||
|
|
|||
|
//
|
|||
|
// This is output only
|
|||
|
//
|
|||
|
// We don't check for work here as USER calls into here while in a power callout
|
|||
|
// and if we check for work at that point, promotion to hibernate doesn't work right.
|
|||
|
//
|
|||
|
CheckForWork = FALSE;
|
|||
|
if (InputBuffer) {
|
|||
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
ReturnBuffer = &PopAction.SleepTime;
|
|||
|
ReturnBufferLength = sizeof(PopAction.SleepTime);
|
|||
|
break;
|
|||
|
|
|||
|
case SystemExecutionState:
|
|||
|
|
|||
|
//
|
|||
|
// This is output only
|
|||
|
//
|
|||
|
if (InputBuffer) {
|
|||
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
Buf.SystemExecutionState = 0;
|
|||
|
ReturnBuffer = &Buf.SystemExecutionState;
|
|||
|
ReturnBufferLength = sizeof(Buf.SystemExecutionState);
|
|||
|
if (PopAttributes[POP_SYSTEM_ATTRIBUTE].Count) {
|
|||
|
Buf.SystemExecutionState |= ES_SYSTEM_REQUIRED;
|
|||
|
}
|
|||
|
if (PopAttributes[POP_DISPLAY_ATTRIBUTE].Count) {
|
|||
|
Buf.SystemExecutionState |= ES_DISPLAY_REQUIRED;
|
|||
|
}
|
|||
|
if (PopAttributes[POP_USER_ATTRIBUTE].Count) {
|
|||
|
Buf.SystemExecutionState |= ES_USER_PRESENT;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If there's a return buffer, return it
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && OutputBuffer && ReturnBuffer) {
|
|||
|
if (OutputBufferLength < ReturnBufferLength) {
|
|||
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
} else {
|
|||
|
memcpy (OutputBuffer, ReturnBuffer, ReturnBufferLength);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = GetExceptionCode();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Done. Release resources
|
|||
|
//
|
|||
|
|
|||
|
if (CapBuffer) {
|
|||
|
ExFreePool(CapBuffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PopReleasePolicyLock (CheckForWork);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopApplyAdminPolicy (
|
|||
|
IN BOOLEAN UpdateRegistry,
|
|||
|
IN PADMINISTRATOR_POWER_POLICY NewPolicy,
|
|||
|
IN ULONG PolicyLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
|||
|
as the current policy
|
|||
|
|
|||
|
NewPolicy - The policy to apply
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ADMINISTRATOR_POWER_POLICY Policy;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
HANDLE handle;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
if (PolicyLength < sizeof (ADMINISTRATOR_POWER_POLICY)) {
|
|||
|
ExRaiseStatus (STATUS_BUFFER_TOO_SMALL);
|
|||
|
}
|
|||
|
if (PolicyLength > sizeof (ADMINISTRATOR_POWER_POLICY)) {
|
|||
|
ExRaiseStatus (STATUS_BUFFER_OVERFLOW);
|
|||
|
}
|
|||
|
|
|||
|
memcpy (&Policy, NewPolicy, sizeof(Policy));
|
|||
|
|
|||
|
//
|
|||
|
// Verify values fall within proper range
|
|||
|
//
|
|||
|
|
|||
|
if (Policy.MinSleep < PowerSystemSleeping1 ||
|
|||
|
Policy.MinSleep > PowerSystemHibernate ||
|
|||
|
Policy.MinSleep < PowerSystemSleeping1 ||
|
|||
|
Policy.MaxSleep > PowerSystemHibernate ||
|
|||
|
Policy.MinSleep > Policy.MaxSleep ||
|
|||
|
Policy.MinVideoTimeout > Policy.MaxVideoTimeout ||
|
|||
|
Policy.MinSpindownTimeout > Policy.MaxSpindownTimeout) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the policy hasn't changed, return
|
|||
|
//
|
|||
|
|
|||
|
if (!memcmp (&Policy, &PopAdminPolicy, sizeof(Policy))) {
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Change it
|
|||
|
//
|
|||
|
|
|||
|
memcpy (&PopAdminPolicy, &Policy, sizeof(Policy));
|
|||
|
|
|||
|
//
|
|||
|
// Update registry copy of policy
|
|||
|
//
|
|||
|
|
|||
|
if (UpdateRegistry) {
|
|||
|
|
|||
|
Status = PopOpenPowerKey (&handle);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
RtlInitUnicodeString (&UnicodeString, PopAdminRegName);
|
|||
|
|
|||
|
ZwSetValueKey (
|
|||
|
handle,
|
|||
|
&UnicodeString,
|
|||
|
0L,
|
|||
|
REG_BINARY,
|
|||
|
&Policy,
|
|||
|
sizeof(ADMINISTRATOR_POWER_POLICY)
|
|||
|
);
|
|||
|
|
|||
|
ZwClose (handle);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopApplyPolicy (
|
|||
|
IN BOOLEAN UpdateRegistry,
|
|||
|
IN BOOLEAN AcPolicy,
|
|||
|
IN PSYSTEM_POWER_POLICY NewPolicy,
|
|||
|
IN ULONG PolicyLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Update Dest policy to be Source policy.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
|||
|
as the current policy
|
|||
|
|
|||
|
AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
|
|||
|
|
|||
|
NewPolicy - The policy to apply
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
BOOLEAN DischargeChanged;
|
|||
|
SYSTEM_POWER_POLICY OrigPolicy, Policy;
|
|||
|
PSYSTEM_POWER_POLICY SystemPolicy;
|
|||
|
PSYSTEM_POWER_LEVEL DPolicy, SPolicy;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
HANDLE handle;
|
|||
|
NTSTATUS Status;
|
|||
|
const WCHAR* RegName;
|
|||
|
|
|||
|
//
|
|||
|
// Setup for system policy change
|
|||
|
//
|
|||
|
|
|||
|
if (AcPolicy) {
|
|||
|
RegName = PopAcRegName;
|
|||
|
SystemPolicy = &PopAcPolicy;
|
|||
|
} else {
|
|||
|
RegName = PopDcRegName;
|
|||
|
SystemPolicy = &PopDcPolicy;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert policy to current system capabilities
|
|||
|
//
|
|||
|
|
|||
|
if (PolicyLength < sizeof (SYSTEM_POWER_POLICY)) {
|
|||
|
ExRaiseStatus (STATUS_BUFFER_TOO_SMALL);
|
|||
|
}
|
|||
|
if (PolicyLength > sizeof (SYSTEM_POWER_POLICY)) {
|
|||
|
ExRaiseStatus (STATUS_BUFFER_OVERFLOW);
|
|||
|
}
|
|||
|
|
|||
|
memcpy (&OrigPolicy, NewPolicy, sizeof (SYSTEM_POWER_POLICY));
|
|||
|
PopVerifyPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
|
|||
|
|
|||
|
//
|
|||
|
// If the policy hasn't changed, return
|
|||
|
//
|
|||
|
|
|||
|
if (!memcmp (&Policy, SystemPolicy, sizeof(SYSTEM_POWER_POLICY))) {
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if any discharge setting has changed
|
|||
|
//
|
|||
|
|
|||
|
DischargeChanged = FALSE;
|
|||
|
DPolicy = SystemPolicy->DischargePolicy;
|
|||
|
SPolicy = Policy.DischargePolicy;
|
|||
|
for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
|
|||
|
if (SPolicy[i].Enable != DPolicy[i].Enable) {
|
|||
|
DischargeChanged = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (SPolicy[i].Enable && memcmp (&SPolicy[i], &DPolicy[i], sizeof (SYSTEM_POWER_LEVEL))) {
|
|||
|
DischargeChanged = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Change it
|
|||
|
//
|
|||
|
|
|||
|
memcpy (SystemPolicy, &Policy, sizeof(SYSTEM_POWER_POLICY));
|
|||
|
|
|||
|
//
|
|||
|
// If this is the active policy, changes need to take effect now
|
|||
|
//
|
|||
|
|
|||
|
if (SystemPolicy == PopPolicy) {
|
|||
|
//
|
|||
|
// Changing the active policy
|
|||
|
//
|
|||
|
|
|||
|
PopSetNotificationWork (PO_NOTIFY_POLICY | PO_NOTIFY_POLICY_CALLBACK);
|
|||
|
|
|||
|
//
|
|||
|
// If any discharge policy has changed, reset the composite
|
|||
|
// battery triggers
|
|||
|
//
|
|||
|
|
|||
|
if (DischargeChanged) {
|
|||
|
PopResetCBTriggers (PO_TRG_SET | PO_TRG_SYSTEM | PO_TRG_USER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Recompute thermal throttle and cooling mode
|
|||
|
//
|
|||
|
|
|||
|
PopApplyThermalThrottle ();
|
|||
|
|
|||
|
//
|
|||
|
// Recompute system idle values
|
|||
|
//
|
|||
|
|
|||
|
PopInitSIdle ();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update registry copy of policy
|
|||
|
//
|
|||
|
|
|||
|
if (UpdateRegistry) {
|
|||
|
|
|||
|
Status = PopOpenPowerKey (&handle);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
RtlInitUnicodeString (&UnicodeString, RegName);
|
|||
|
|
|||
|
ZwSetValueKey (
|
|||
|
handle,
|
|||
|
&UnicodeString,
|
|||
|
0L,
|
|||
|
REG_BINARY,
|
|||
|
&OrigPolicy,
|
|||
|
sizeof (SYSTEM_POWER_POLICY)
|
|||
|
);
|
|||
|
|
|||
|
ZwClose (handle);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopApplyProcessorPolicy (
|
|||
|
IN BOOLEAN UpdateRegistry,
|
|||
|
IN BOOLEAN AcPolicy,
|
|||
|
IN PPROCESSOR_POWER_POLICY NewPolicy,
|
|||
|
IN ULONG PolicyLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Update Dest policy to be Source policy.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
|||
|
as the current policy
|
|||
|
|
|||
|
AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
|
|||
|
|
|||
|
NewPolicy - The policy to apply
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PROCESSOR_POWER_POLICY OrigPolicy;
|
|||
|
PROCESSOR_POWER_POLICY Policy;
|
|||
|
PPROCESSOR_POWER_POLICY SystemPolicy;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
HANDLE handle;
|
|||
|
NTSTATUS Status;
|
|||
|
const WCHAR* RegName;
|
|||
|
|
|||
|
//
|
|||
|
// Setup for system policy change
|
|||
|
//
|
|||
|
if (AcPolicy) {
|
|||
|
|
|||
|
RegName = PopAcProcessorRegName;
|
|||
|
SystemPolicy = &PopAcProcessorPolicy;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
RegName = PopDcProcessorRegName;
|
|||
|
SystemPolicy = &PopDcProcessorPolicy;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert policy to current system capabilities
|
|||
|
//
|
|||
|
if (PolicyLength < sizeof (PROCESSOR_POWER_POLICY)) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_BUFFER_TOO_SMALL);
|
|||
|
|
|||
|
}
|
|||
|
if (PolicyLength > sizeof (PROCESSOR_POWER_POLICY)) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_BUFFER_OVERFLOW);
|
|||
|
|
|||
|
}
|
|||
|
memcpy (&OrigPolicy, NewPolicy, sizeof (PROCESSOR_POWER_POLICY));
|
|||
|
PopVerifyProcessorPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
|
|||
|
|
|||
|
//
|
|||
|
// If the policy hasn't changed, return
|
|||
|
//
|
|||
|
if (!memcmp (&Policy, SystemPolicy, sizeof(PROCESSOR_POWER_POLICY))) {
|
|||
|
|
|||
|
return ;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Change it
|
|||
|
//
|
|||
|
memcpy (SystemPolicy, &Policy, sizeof(PROCESSOR_POWER_POLICY));
|
|||
|
|
|||
|
//
|
|||
|
// If this is the active policy, changes need to take effect now
|
|||
|
//
|
|||
|
if (SystemPolicy == PopProcessorPolicy) {
|
|||
|
|
|||
|
//
|
|||
|
// Changing the active policy
|
|||
|
//
|
|||
|
PopSetNotificationWork(
|
|||
|
PO_NOTIFY_PROCESSOR_POLICY | PO_NOTIFY_PROCESSOR_POLICY_CALLBACK
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Recompute current throttle policy....
|
|||
|
//
|
|||
|
PopUpdateAllThrottles();
|
|||
|
PopIdleUpdateIdleHandlers();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update registry copy of policy
|
|||
|
//
|
|||
|
if (UpdateRegistry) {
|
|||
|
|
|||
|
Status = PopOpenPowerKey (&handle);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
RtlInitUnicodeString (&UnicodeString, RegName);
|
|||
|
ZwSetValueKey (
|
|||
|
handle,
|
|||
|
&UnicodeString,
|
|||
|
0L,
|
|||
|
REG_BINARY,
|
|||
|
&OrigPolicy,
|
|||
|
sizeof (PROCESSOR_POWER_POLICY)
|
|||
|
);
|
|||
|
ZwClose (handle);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyPowerPolicy (
|
|||
|
IN BOOLEAN Ac,
|
|||
|
IN PSYSTEM_POWER_POLICY InputPolicy,
|
|||
|
OUT PSYSTEM_POWER_POLICY PowerPolicy
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function copies the InputPolicy to the output PowerPolicy and
|
|||
|
adjusts it to represent system capabilities and other requirements.
|
|||
|
If the input policy has some setting which can not be adjusted, an
|
|||
|
error status is raised.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Ac - Policy is to be adjusted as an AC or DC policy
|
|||
|
InputPolicy - The source policy to adjust
|
|||
|
PowerPolicy - The returned policy which can be used as is
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
PSYSTEM_POWER_LEVEL DPolicy;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Setup initial output structure
|
|||
|
//
|
|||
|
memcpy (PowerPolicy, InputPolicy, sizeof (SYSTEM_POWER_POLICY));
|
|||
|
|
|||
|
//
|
|||
|
// Only revision 1 currently supported
|
|||
|
//
|
|||
|
if (PowerPolicy->Revision != 1) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// some win9x upgrades or very old NT builds might have maxsleep set to S4. Fix that here.
|
|||
|
//
|
|||
|
if (PowerPolicy->MaxSleep > PowerSystemSleeping3) {
|
|||
|
PowerPolicy->MaxSleep = PowerSystemSleeping3;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Limit settings to administrator policy
|
|||
|
//
|
|||
|
if (PowerPolicy->MinSleep < PopAdminPolicy.MinSleep) {
|
|||
|
|
|||
|
PowerPolicy->MinSleep = PopAdminPolicy.MinSleep;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->MaxSleep > PopAdminPolicy.MaxSleep) {
|
|||
|
|
|||
|
PowerPolicy->MaxSleep = PopAdminPolicy.MaxSleep;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->VideoTimeout < PopAdminPolicy.MinVideoTimeout) {
|
|||
|
|
|||
|
PowerPolicy->VideoTimeout = PopAdminPolicy.MinVideoTimeout;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->VideoTimeout > PopAdminPolicy.MaxVideoTimeout) {
|
|||
|
|
|||
|
PowerPolicy->VideoTimeout = PopAdminPolicy.MaxVideoTimeout;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->SpindownTimeout < PopAdminPolicy.MinSpindownTimeout) {
|
|||
|
|
|||
|
PowerPolicy->SpindownTimeout = PopAdminPolicy.MinSpindownTimeout;
|
|||
|
|
|||
|
}
|
|||
|
if ((ULONG) PowerPolicy->SpindownTimeout > (ULONG) PopAdminPolicy.MaxSpindownTimeout) {
|
|||
|
|
|||
|
PowerPolicy->SpindownTimeout = PopAdminPolicy.MaxSpindownTimeout;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify all the power action policies, and adjust all system
|
|||
|
// states to match what is supported by this platform
|
|||
|
//
|
|||
|
PopVerifyPowerActionPolicy(&PowerPolicy->PowerButton);
|
|||
|
PopVerifyPowerActionPolicy(&PowerPolicy->SleepButton);
|
|||
|
PopVerifyPowerActionPolicy(&PowerPolicy->LidClose);
|
|||
|
PopVerifyPowerActionPolicy(&PowerPolicy->Idle);
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->LidOpenWake,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->MinSleep,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->MaxSleep,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->ReducedLatencySleep,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
for (i = 0; i < PO_NUM_POWER_LEVELS; i++) {
|
|||
|
|
|||
|
DPolicy = &PowerPolicy->DischargePolicy[i];
|
|||
|
if (DPolicy->Enable) {
|
|||
|
|
|||
|
PopVerifyPowerActionPolicy (
|
|||
|
&PowerPolicy->DischargePolicy[i].PowerPolicy
|
|||
|
);
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->DischargePolicy[i].MinSystemState,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If the action is standby, make sure the min state is S3 or lighter
|
|||
|
//
|
|||
|
if ((PowerPolicy->DischargePolicy[i].PowerPolicy.Action == PowerActionSleep) &&
|
|||
|
(PowerPolicy->DischargePolicy[i].MinSystemState > PowerSystemSleeping3)) {
|
|||
|
|
|||
|
PowerPolicy->DischargePolicy[i].MinSystemState = PowerSystemSleeping3;
|
|||
|
PopVerifySystemPowerState(
|
|||
|
&PowerPolicy->DischargePolicy[i].MinSystemState,
|
|||
|
SubstituteLightestOverallDownwardBounded
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
if (DPolicy->BatteryLevel > 100) {
|
|||
|
|
|||
|
DPolicy->BatteryLevel = 100;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
PopVerifyPowerActionPolicy(&PowerPolicy->OverThrottled);
|
|||
|
|
|||
|
//
|
|||
|
// Adjust other values based on capabilities
|
|||
|
//
|
|||
|
if (!PopCapabilities.ProcessorThrottle) {
|
|||
|
|
|||
|
PowerPolicy->OptimizeForPower = FALSE;
|
|||
|
PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
|
|||
|
PowerPolicy->ForcedThrottle = PO_NO_FORCED_THROTTLE;
|
|||
|
|
|||
|
}
|
|||
|
if (!PopCapabilities.ThermalControl) {
|
|||
|
|
|||
|
PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Sanity
|
|||
|
//
|
|||
|
if (!PowerPolicy->BroadcastCapacityResolution) {
|
|||
|
|
|||
|
PowerPolicy->BroadcastCapacityResolution = 100;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the system supports only S4 (legacy) there is no point in
|
|||
|
// idly hibernating the system as we can't turn it off anyway.
|
|||
|
//
|
|||
|
if ((PowerPolicy->Idle.Action == PowerActionHibernate) &&
|
|||
|
(!PopCapabilities.SystemS5)) {
|
|||
|
|
|||
|
PowerPolicy->Idle.Action = PowerActionNone;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->Idle.Action == PowerActionNone) {
|
|||
|
|
|||
|
PowerPolicy->IdleTimeout = 0;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->IdleTimeout &&
|
|||
|
PowerPolicy->IdleTimeout < PO_MIN_IDLE_TIMEOUT) {
|
|||
|
|
|||
|
PowerPolicy->IdleTimeout = PO_MIN_IDLE_TIMEOUT;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->IdleSensitivity > 100 - PO_MIN_IDLE_SENSITIVITY) {
|
|||
|
|
|||
|
PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
|
|||
|
|
|||
|
}
|
|||
|
if ((PowerPolicy->IdleTimeout > 0) &&
|
|||
|
(PowerPolicy->IdleSensitivity == 0)) {
|
|||
|
|
|||
|
//
|
|||
|
// This is basically saying "timeout when the system has been idle
|
|||
|
// for X minutes, but never declare the system idle" This makes no
|
|||
|
// sense, so we will set the idle sensitivity to the minimum.
|
|||
|
//
|
|||
|
PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->MaxSleep < PowerPolicy->MinSleep) {
|
|||
|
|
|||
|
PowerPolicy->MaxSleep = PowerPolicy->MinSleep;
|
|||
|
|
|||
|
}
|
|||
|
if (PowerPolicy->ReducedLatencySleep > PowerPolicy->MinSleep) {
|
|||
|
|
|||
|
PowerPolicy->ReducedLatencySleep = PowerPolicy->MinSleep;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ignore whatever the user said what the minimum throttle and force the
|
|||
|
// system to pick whatever the hardware supports as the min throttle
|
|||
|
//
|
|||
|
PowerPolicy->MinThrottle = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Verify all the throttle percentages (in tenths of a percentage points,
|
|||
|
// so 1000 decimal = 100.0% and 777 = 77.7%) in terms of both their maximum
|
|||
|
// and minimum values. Note: Percent is based on POP_PERF_SCALE, which is
|
|||
|
// currently 128. So, actually, 1280 decimal = 100.0%.
|
|||
|
//
|
|||
|
PopVerifyThrottle(&PowerPolicy->FanThrottleTolerance, PO_MAX_FAN_THROTTLE);
|
|||
|
PopVerifyThrottle(&PowerPolicy->MinThrottle, PO_MIN_MIN_THROTTLE);
|
|||
|
PopVerifyThrottle(&PowerPolicy->ForcedThrottle, PowerPolicy->MinThrottle);
|
|||
|
|
|||
|
if (PowerPolicy->FanThrottleTolerance != PO_NO_FAN_THROTTLE ||
|
|||
|
PowerPolicy->ForcedThrottle != PO_NO_FORCED_THROTTLE) {
|
|||
|
|
|||
|
PowerPolicy->OptimizeForPower = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyProcessorPowerPolicy (
|
|||
|
IN BOOLEAN Ac,
|
|||
|
IN PPROCESSOR_POWER_POLICY InputPolicy,
|
|||
|
OUT PPROCESSOR_POWER_POLICY PowerPolicy
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function copies the InputPolicy to the output PowerPolicy and
|
|||
|
adjusts it to represent processor capabilities and other requirements.
|
|||
|
If the input policy has some setting which can not be adjusted, an
|
|||
|
error status is raised.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Ac - Policy is to be adjusted as an AC or DC policy
|
|||
|
InputPolicy - The source policy to adjust
|
|||
|
PowerPolicy - The returned policy which can be used as is
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPROCESSOR_POWER_POLICY_INFO pPolicy;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Setup initial output structure
|
|||
|
//
|
|||
|
memcpy (PowerPolicy, InputPolicy, sizeof(PROCESSOR_POWER_POLICY));
|
|||
|
|
|||
|
//
|
|||
|
// Only revision 1 currently supported
|
|||
|
//
|
|||
|
if (PowerPolicy->Revision != 1) {
|
|||
|
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check each level of the policy
|
|||
|
//
|
|||
|
for (i = 0; i < 3; i++) {
|
|||
|
|
|||
|
pPolicy = &(PowerPolicy->Policy[i]);
|
|||
|
|
|||
|
//
|
|||
|
// We don't allow demotion to Idle0 unless the machine is MP
|
|||
|
//
|
|||
|
if (i == 0 && KeNumberProcessors == 1) {
|
|||
|
|
|||
|
pPolicy->DemotePercent = 0;
|
|||
|
pPolicy->AllowDemotion = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Don't allow promotions past the last state
|
|||
|
//
|
|||
|
if (i == 2) {
|
|||
|
|
|||
|
pPolicy->PromotePercent = 0;
|
|||
|
pPolicy->PromoteLimit = 0;
|
|||
|
pPolicy->AllowPromotion = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Time check must be smaller than Demote Limit (if there is one)
|
|||
|
//
|
|||
|
if (pPolicy->TimeCheck < pPolicy->DemoteLimit) {
|
|||
|
|
|||
|
pPolicy->TimeCheck = pPolicy->DemoteLimit;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (pPolicy->DemotePercent == 0 &&
|
|||
|
pPolicy->AllowPromotion &&
|
|||
|
pPolicy->TimeCheck < pPolicy->PromoteLimit) {
|
|||
|
|
|||
|
pPolicy->TimeCheck = pPolicy->PromoteLimit;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (PowerPolicy->DynamicThrottle >= PO_THROTTLE_MAXIMUM) {
|
|||
|
|
|||
|
if (Ac) {
|
|||
|
|
|||
|
PowerPolicy->DynamicThrottle = PO_THROTTLE_NONE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PowerPolicy->DynamicThrottle = PO_THROTTLE_CONSTANT;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifyThrottle (
|
|||
|
IN PUCHAR Throttle,
|
|||
|
IN UCHAR Min
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
UCHAR t;
|
|||
|
|
|||
|
t = *Throttle;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure max is POP_PERF_SCALE%
|
|||
|
//
|
|||
|
|
|||
|
if (t > POP_PERF_SCALE) {
|
|||
|
t = POP_PERF_SCALE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure it's not below the specificied min.
|
|||
|
//
|
|||
|
|
|||
|
if (t < Min) {
|
|||
|
t = Min;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Round the throttle up to the first supported value
|
|||
|
// Note that we don't need to check against ProcessorMinThrottle
|
|||
|
// or any other value since PopRoundThrottle() will do that for us.
|
|||
|
//
|
|||
|
|
|||
|
PopRoundThrottle(t, NULL, Throttle, NULL, NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PopVerifyPowerActionPolicy (
|
|||
|
IN PPOWER_ACTION_POLICY Action
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function checks & edits the input Action to represent
|
|||
|
system capabilities and other requirements.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Action - Power action policy to check / verify
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean to indicate action was demoted to a disabled state
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
POWER_ACTION LastAction;
|
|||
|
BOOLEAN Disabled;
|
|||
|
BOOLEAN HiberSupport;
|
|||
|
ULONG SleepCount;
|
|||
|
NTSTATUS Status;
|
|||
|
PNP_VETO_TYPE VetoType;
|
|||
|
SYSTEM_POWER_CAPABILITIES PowerCapabilities;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
Disabled = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Verify reserved flag bits are clear
|
|||
|
//
|
|||
|
|
|||
|
if (Action->Flags & !(
|
|||
|
POWER_ACTION_QUERY_ALLOWED |
|
|||
|
POWER_ACTION_UI_ALLOWED |
|
|||
|
POWER_ACTION_OVERRIDE_APPS |
|
|||
|
POWER_ACTION_LOCK_CONSOLE |
|
|||
|
POWER_ACTION_DISABLE_WAKES |
|
|||
|
POWER_ACTION_CRITICAL)) {
|
|||
|
|
|||
|
//
|
|||
|
// N.B. - Later POWER_ACTION_LIGHTEST_FIRST?
|
|||
|
//
|
|||
|
|
|||
|
// reserved bit set in action flags
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the action is critical, then do not notify any applications
|
|||
|
//
|
|||
|
|
|||
|
if (Action->Flags & POWER_ACTION_CRITICAL) {
|
|||
|
Action->Flags &= ~(POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED);
|
|||
|
Action->Flags |= POWER_ACTION_OVERRIDE_APPS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If any legacy drivers are installed, then no sleeping states
|
|||
|
// are allowed at all.
|
|||
|
//
|
|||
|
if ((Action->Action == PowerActionSleep) ||
|
|||
|
(Action->Action == PowerActionHibernate)) {
|
|||
|
|
|||
|
Status = IoGetLegacyVetoList(NULL, &VetoType);
|
|||
|
if (NT_SUCCESS(Status) &&
|
|||
|
(VetoType != PNP_VetoTypeUnknown)) {
|
|||
|
|
|||
|
Action->Action = PowerActionNone;
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Some components may disable some capabilities. So filter them here.
|
|||
|
//
|
|||
|
|
|||
|
PopFilterCapabilities(&PopCapabilities, &PowerCapabilities);
|
|||
|
|
|||
|
//
|
|||
|
// Count the supported sleeping states
|
|||
|
//
|
|||
|
|
|||
|
SleepCount = 0;
|
|||
|
HiberSupport = FALSE;
|
|||
|
if (PowerCapabilities.SystemS1) {
|
|||
|
SleepCount += 1;
|
|||
|
}
|
|||
|
|
|||
|
if (PowerCapabilities.SystemS2) {
|
|||
|
SleepCount += 1;
|
|||
|
}
|
|||
|
|
|||
|
if (PowerCapabilities.SystemS3) {
|
|||
|
SleepCount += 1;
|
|||
|
}
|
|||
|
|
|||
|
if (PowerCapabilities.SystemS4 && PowerCapabilities.HiberFilePresent) {
|
|||
|
HiberSupport = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify the requested action is supported.
|
|||
|
//
|
|||
|
|
|||
|
do {
|
|||
|
LastAction = Action->Action;
|
|||
|
switch (Action->Action) {
|
|||
|
case PowerActionNone:
|
|||
|
// can do nothing, not a problem
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionReserved:
|
|||
|
// used to be doze action. does not exist anymore make it sleep
|
|||
|
Action->Action = PowerActionSleep;
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionSleep:
|
|||
|
//
|
|||
|
// if no sleeping states supported, adjust action to be none
|
|||
|
//
|
|||
|
|
|||
|
if (SleepCount < 1) {
|
|||
|
Disabled = TRUE;
|
|||
|
Action->Action = PowerActionNone;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionHibernate:
|
|||
|
//
|
|||
|
// if no hibernate support, try sleep
|
|||
|
//
|
|||
|
|
|||
|
if (!HiberSupport) {
|
|||
|
Action->Action = PowerActionSleep;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionShutdown:
|
|||
|
case PowerActionShutdownReset:
|
|||
|
// all systems support shutdown & shutdown reset
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionShutdownOff:
|
|||
|
// If action shutdown is not available, use Shutdown
|
|||
|
if (!PowerCapabilities.SystemS5) {
|
|||
|
Action->Action = PowerActionShutdown;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case PowerActionWarmEject:
|
|||
|
//
|
|||
|
// This is a system action associated with an individual device.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// unknown power action setting
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
} while (LastAction != Action->Action);
|
|||
|
|
|||
|
return Disabled;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopAdvanceSystemPowerState (
|
|||
|
IN OUT PSYSTEM_POWER_STATE PowerState,
|
|||
|
IN POP_SUBSTITUTION_POLICY SubstitutionPolicy,
|
|||
|
IN SYSTEM_POWER_STATE LightestSystemState,
|
|||
|
IN SYSTEM_POWER_STATE DeepestSystemState
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function uses the substitution policy to advance the sleep state
|
|||
|
(lighten or deepen) as appropriate.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PowerState - System power state to advance.
|
|||
|
|
|||
|
SubstitutionPolicy - see definitions in pop.h.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SYSTEM_POWER_STATE State;
|
|||
|
BOOLEAN HibernateAllowed;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Verify value is valid
|
|||
|
//
|
|||
|
|
|||
|
State = *PowerState;
|
|||
|
if (State < PowerSystemSleeping1) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER_1);
|
|||
|
}
|
|||
|
|
|||
|
if (State >= PowerSystemShutdown) {
|
|||
|
|
|||
|
//
|
|||
|
// There is nowhere else to go for these states.
|
|||
|
//
|
|||
|
*PowerState = PowerSystemWorking;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
switch(SubstitutionPolicy) {
|
|||
|
|
|||
|
case SubstituteLightestOverallDownwardBounded:
|
|||
|
*PowerState = (State - 1);
|
|||
|
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
|||
|
|
|||
|
//
|
|||
|
// There are three cases to consider:
|
|||
|
// 1. We received in S1, which was previously validated. We try S0
|
|||
|
// and it is automatically accepted. There are no other options
|
|||
|
// as we started in the lightest overall (S1). Thus we are
|
|||
|
// finished.
|
|||
|
// 2. We passed in Sx-1 for verification, but got back Sx. This
|
|||
|
// means we were already at the lightest state (Sx), and we've
|
|||
|
// exhausted the possibilities. Thus we are finished and so
|
|||
|
// we return PowerSystemWorking.
|
|||
|
// 3. We passed in Sx-1 and didn't get Sx. This means we've advanced
|
|||
|
// to another state, although it may be the last if Sx was S1, as
|
|||
|
// rule (1) is actually a special case of this rule.
|
|||
|
//
|
|||
|
if (*PowerState == State) {
|
|||
|
|
|||
|
*PowerState = PowerSystemWorking;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case SubstituteLightenSleep:
|
|||
|
*PowerState = (State - 1);
|
|||
|
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
case SubstituteDeepenSleep:
|
|||
|
//
|
|||
|
// Per above, Deepen goes straight into Hibernate.
|
|||
|
//
|
|||
|
if (State == PowerSystemHibernate) {
|
|||
|
|
|||
|
*PowerState = PowerSystemWorking;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
*PowerState = (State + 1);
|
|||
|
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER_2);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ((*PowerState != PowerSystemWorking) &&
|
|||
|
((*PowerState < LightestSystemState) ||
|
|||
|
(*PowerState > DeepestSystemState))) {
|
|||
|
|
|||
|
*PowerState = PowerSystemWorking;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PopVerifySystemPowerState (
|
|||
|
IN OUT PSYSTEM_POWER_STATE PowerState,
|
|||
|
IN POP_SUBSTITUTION_POLICY SubstitutionPolicy
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function checks & edits the input PowerState to represent
|
|||
|
system capabilities and other requirements.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PowerState - System power state to check / verify
|
|||
|
|
|||
|
SubstitutionPolicy - See definitions in pop.h
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SYSTEM_POWER_STATE State;
|
|||
|
BOOLEAN HibernateAllowed;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Verify value is valid
|
|||
|
//
|
|||
|
|
|||
|
State = *PowerState;
|
|||
|
if (State == PowerSystemUnspecified || State > PowerSystemShutdown) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER_1);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// PowerSystemShutdown is not allowed in any structures. It is generated
|
|||
|
// internally for the sole use of quering drivers before performing
|
|||
|
// a system shutdown
|
|||
|
//
|
|||
|
|
|||
|
if (State == PowerSystemShutdown) {
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER_1);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The working state is always supported
|
|||
|
//
|
|||
|
|
|||
|
if (State == PowerSystemWorking) {
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify the power state is supported. If not, pick the next best state
|
|||
|
//
|
|||
|
HibernateAllowed = TRUE;
|
|||
|
|
|||
|
switch(SubstitutionPolicy) {
|
|||
|
|
|||
|
case SubstituteLightestOverallDownwardBounded:
|
|||
|
case SubstituteLightenSleep:
|
|||
|
|
|||
|
//
|
|||
|
// In LightenSleep, we lighten the power state passed in until
|
|||
|
// we reach PowerStateWorking. Then we give up.
|
|||
|
//
|
|||
|
// In LightestOverall, instead of stopping, we turn around and
|
|||
|
// choose the lightest non-S0 sleep state overall, which may be
|
|||
|
// deeper than the one passed in. Note that we do *not* progress
|
|||
|
// into Hibernation though.
|
|||
|
//
|
|||
|
|
|||
|
if (State == PowerSystemHibernate &&
|
|||
|
(!PopCapabilities.SystemS4 || !PopCapabilities.HiberFilePresent)) {
|
|||
|
State = PowerSystemSleeping3;
|
|||
|
}
|
|||
|
if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
|
|||
|
State = PowerSystemSleeping2;
|
|||
|
}
|
|||
|
if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
|
|||
|
State = PowerSystemSleeping1;
|
|||
|
}
|
|||
|
if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
|
|||
|
State = PowerSystemWorking;
|
|||
|
}
|
|||
|
|
|||
|
if (State != PowerSystemWorking) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (SubstitutionPolicy != SubstituteLightestOverallDownwardBounded) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Rounding down lead to PowerSystemWorking. Try to rounding up
|
|||
|
// towards deeper sleep states. Block the rounding at S3 however.
|
|||
|
//
|
|||
|
State = State + 1;
|
|||
|
HibernateAllowed = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Fall through...
|
|||
|
//
|
|||
|
|
|||
|
case SubstituteDeepenSleep:
|
|||
|
|
|||
|
if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
|
|||
|
State = PowerSystemSleeping2;
|
|||
|
}
|
|||
|
if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
|
|||
|
State = PowerSystemSleeping3;
|
|||
|
}
|
|||
|
if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
|
|||
|
State = PowerSystemHibernate;
|
|||
|
}
|
|||
|
|
|||
|
if (State == PowerSystemHibernate &&
|
|||
|
(!HibernateAllowed ||
|
|||
|
!PopCapabilities.SystemS4 ||
|
|||
|
!PopCapabilities.HiberFilePresent)) {
|
|||
|
|
|||
|
// nothing good supported, disable it
|
|||
|
State = PowerSystemWorking;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER_2);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
*PowerState = State;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PopResetCurrentPolicies (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reads the current policies from the registry and applies them.
|
|||
|
|
|||
|
N.B. PopPolicyLock must be held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE handle;
|
|||
|
NTSTATUS Status;
|
|||
|
PSYSTEM_POWER_POLICY RegPolicy;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
ULONG Length;
|
|||
|
struct {
|
|||
|
KEY_VALUE_PARTIAL_INFORMATION Inf;
|
|||
|
union {
|
|||
|
SYSTEM_POWER_POLICY PowerPolicy;
|
|||
|
} Data;
|
|||
|
} PartialInformation;
|
|||
|
|
|||
|
ASSERT_POLICY_LOCK_OWNED();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize & open registry
|
|||
|
//
|
|||
|
|
|||
|
RegPolicy = (PSYSTEM_POWER_POLICY) PartialInformation.Inf.Data;
|
|||
|
|
|||
|
Status = PopOpenPowerKey (&handle);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read AC policy and apply it
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&UnicodeString, PopAcRegName);
|
|||
|
Status = ZwQueryValueKey (
|
|||
|
handle,
|
|||
|
&UnicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
&PartialInformation,
|
|||
|
sizeof (PartialInformation),
|
|||
|
&Length
|
|||
|
);
|
|||
|
|
|||
|
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
PopDefaultPolicy (RegPolicy);
|
|||
|
Length = sizeof(SYSTEM_POWER_POLICY);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
PopApplyPolicy (FALSE, TRUE, RegPolicy, Length);
|
|||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
ASSERT (GetExceptionCode());
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read DC policy and apply it
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&UnicodeString, PopDcRegName);
|
|||
|
Status = ZwQueryValueKey (
|
|||
|
handle,
|
|||
|
&UnicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
&PartialInformation,
|
|||
|
sizeof (PartialInformation),
|
|||
|
&Length
|
|||
|
);
|
|||
|
|
|||
|
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
PopDefaultPolicy (RegPolicy);
|
|||
|
Length = sizeof(SYSTEM_POWER_POLICY);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
PopApplyPolicy (FALSE, FALSE, RegPolicy, Length);
|
|||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
ASSERT (GetExceptionCode());
|
|||
|
}
|
|||
|
|
|||
|
ZwClose (handle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PopNotifyPolicyDevice (
|
|||
|
IN PVOID Notification,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the notinficant handle for when a new
|
|||
|
policy device appears.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Notification - PnP notification
|
|||
|
|
|||
|
Context - Context registered on notification
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Change;
|
|||
|
POP_POLICY_DEVICE_TYPE DeviceType;
|
|||
|
HANDLE DriverHandle;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
OBJECT_ATTRIBUTES ObjA;
|
|||
|
IO_STATUS_BLOCK IOSB;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Change = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) Notification;
|
|||
|
DeviceType = (POP_POLICY_DEVICE_TYPE) ((ULONG_PTR)Context);
|
|||
|
|
|||
|
//
|
|||
|
// If it's not a device arrival, then we don't care
|
|||
|
//
|
|||
|
|
|||
|
if (memcmp (&Change->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof (GUID))) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
PopAcquirePolicyLock ();
|
|||
|
PopConnectToPolicyDevice (DeviceType, Change->SymbolicLinkName);
|
|||
|
PopReleasePolicyLock (TRUE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PopConnectToPolicyDevice (
|
|||
|
IN POP_POLICY_DEVICE_TYPE DeviceType,
|
|||
|
IN PUNICODE_STRING DriverName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function attempts to connect to the policy device specified.
|
|||
|
If the device is opened, the devices status IRP is allocated and
|
|||
|
sent to the device's IRP handler for initial dispatch.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceType - Policy device type of device to connect
|
|||
|
|
|||
|
DeviceName - Device name to attempt to open
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the device is connected, the *PresetFlag is set to TRUE and
|
|||
|
an initial IRP is queued for the IRP handler.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
HANDLE DriverHandle;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
OBJECT_ATTRIBUTES ObjA;
|
|||
|
IO_STATUS_BLOCK IOSB;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PVOID Context;
|
|||
|
POP_IRP_HANDLER IrpHandler;
|
|||
|
PPOP_SWITCH_DEVICE SwitchDevice;
|
|||
|
PPOP_THERMAL_ZONE ThermalZone;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT_POLICY_LOCK_OWNED();
|
|||
|
|
|||
|
Irp = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// If this is a new battery, then handle the composite battery device is
|
|||
|
// the device to open
|
|||
|
//
|
|||
|
if (DeviceType == PolicyDeviceBattery) {
|
|||
|
|
|||
|
//
|
|||
|
// If the composite battery is already opened, kick the irp handler
|
|||
|
//
|
|||
|
if (PopCB.StatusIrp) {
|
|||
|
|
|||
|
// Don't need to kick the IRP handler. When a new battery is added,
|
|||
|
// the battery tag for the composite battery will change, causing
|
|||
|
// the irp to complete.
|
|||
|
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Battery already connected - not done\n"));
|
|||
|
return ;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to open the composite battery now
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&UnicodeString, PopCompositeBatteryName);
|
|||
|
DriverName = &UnicodeString;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open the device
|
|||
|
//
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjA,
|
|||
|
DriverName,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|||
|
0,
|
|||
|
0
|
|||
|
);
|
|||
|
Status = ZwOpenFile(
|
|||
|
&DriverHandle,
|
|||
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|||
|
&ObjA, // Object
|
|||
|
&IOSB, // io status block
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
|
|||
|
FILE_SYNCHRONOUS_IO_ALERT // open options
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Device open failed\n"));
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the device object
|
|||
|
//
|
|||
|
Status = ObReferenceObjectByHandle(
|
|||
|
DriverHandle,
|
|||
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, // desired access
|
|||
|
NULL,
|
|||
|
KernelMode,
|
|||
|
&FileObject,
|
|||
|
NULL
|
|||
|
);
|
|||
|
ASSERT (NT_SUCCESS(Status));
|
|||
|
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
|
|||
|
ObDereferenceObject(FileObject);
|
|||
|
ZwClose(DriverHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Get an IRP for the device
|
|||
|
//
|
|||
|
Irp = IoAllocateIrp ((CCHAR) (DeviceObject->StackSize + 1), FALSE);
|
|||
|
if (!Irp) {
|
|||
|
|
|||
|
ObDereferenceObject(DeviceObject);
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Setup based on device type
|
|||
|
//
|
|||
|
Context = NULL;
|
|||
|
IrpHandler = NULL;
|
|||
|
|
|||
|
switch (DeviceType) {
|
|||
|
case PolicyDeviceSystemButton:
|
|||
|
SwitchDevice = ExAllocatePoolWithTag(
|
|||
|
NonPagedPool,
|
|||
|
sizeof (*SwitchDevice),
|
|||
|
POP_PSWT_TAG
|
|||
|
);
|
|||
|
if (!SwitchDevice) {
|
|||
|
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory (SwitchDevice, sizeof(*SwitchDevice));
|
|||
|
SwitchDevice->IsInitializing = TRUE;
|
|||
|
SwitchDevice->Opened = TRUE;
|
|||
|
InsertTailList (&PopSwitches, &SwitchDevice->Link);
|
|||
|
IrpHandler = PopSystemButtonHandler;
|
|||
|
Context = SwitchDevice;
|
|||
|
break;
|
|||
|
|
|||
|
case PolicyDeviceBattery:
|
|||
|
|
|||
|
//
|
|||
|
// Loading up the composite battery - status irp is NULL.
|
|||
|
//
|
|||
|
PopSetCapability (&PopCapabilities.SystemBatteriesPresent);
|
|||
|
IrpHandler = PopCompositeBatteryDeviceHandler;
|
|||
|
PopCB.StatusIrp = Irp;
|
|||
|
break;
|
|||
|
|
|||
|
case PolicyDeviceThermalZone:
|
|||
|
|
|||
|
//
|
|||
|
// New thermal zone
|
|||
|
//
|
|||
|
ThermalZone = ExAllocatePoolWithTag (
|
|||
|
NonPagedPool,
|
|||
|
sizeof (*ThermalZone),
|
|||
|
POP_THRM_TAG
|
|||
|
);
|
|||
|
if (!ThermalZone) {
|
|||
|
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize thermal zone structure
|
|||
|
//
|
|||
|
RtlZeroMemory(
|
|||
|
ThermalZone,
|
|||
|
sizeof(POP_THERMAL_ZONE)
|
|||
|
);
|
|||
|
KeInitializeTimer(&ThermalZone->PassiveTimer);
|
|||
|
KeInitializeDpc(
|
|||
|
&ThermalZone->PassiveDpc,
|
|||
|
PopThermalZoneDpc,
|
|||
|
ThermalZone
|
|||
|
);
|
|||
|
ThermalZone->Mode = PO_TZ_INVALID_MODE;
|
|||
|
ThermalZone->ActivePoint = (UCHAR) -1;
|
|||
|
ThermalZone->PendingActivePoint = (UCHAR) -1;
|
|||
|
ThermalZone->Throttle = PO_TZ_NO_THROTTLE;
|
|||
|
ThermalZone->OverThrottled.Type = PolicyDeviceThermalZone;
|
|||
|
ThermalZone->OverThrottled.Flags = PO_TRG_SET;
|
|||
|
ThermalZone->Irp = Irp;
|
|||
|
|
|||
|
//
|
|||
|
// Setup the capabilities of the thermal zones and get ready to
|
|||
|
// ask the thermal zone about itself...
|
|||
|
//
|
|||
|
PopSetCapability (&PopCapabilities.ThermalControl);
|
|||
|
Context = ThermalZone;
|
|||
|
IrpHandler = PopThermalDeviceHandler;
|
|||
|
|
|||
|
//
|
|||
|
// Finally, add the thermal zone to the list of thermal zones
|
|||
|
//
|
|||
|
ExInterlockedInsertTailList(
|
|||
|
&PopThermal,
|
|||
|
&ThermalZone->Link,
|
|||
|
&PopThermalLock
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
PopInternalError (POP_INFO);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in values for IrpHandler dispatch
|
|||
|
//
|
|||
|
IrpSp->Parameters.Others.Argument1 = (PVOID) DeviceObject;
|
|||
|
IrpSp->Parameters.Others.Argument2 = (PVOID) Context;
|
|||
|
IrpSp->Parameters.Others.Argument3 = (PVOID) IrpHandler;
|
|||
|
IoSetNextIrpStackLocation (Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Fill in error to irp so irp handler will re-dispatch it
|
|||
|
//
|
|||
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
|
|||
|
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|||
|
IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
|
|||
|
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Give irp to the completion handler which will dispatch it
|
|||
|
//
|
|||
|
PopCompletePolicyIrp (DeviceObject, Irp, Context);
|
|||
|
Irp = NULL;
|
|||
|
|
|||
|
Done:
|
|||
|
if (Irp) {
|
|||
|
|
|||
|
ObDereferenceObject( DeviceObject );
|
|||
|
IoFreeIrp (Irp);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
POWER_ACTION
|
|||
|
PopMapInternalActionToIrpAction (
|
|||
|
IN POWER_ACTION Action,
|
|||
|
IN SYSTEM_POWER_STATE SystemPowerState,
|
|||
|
IN BOOLEAN UnmapWarmEject
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function maps an internal action and power state to the appropriate
|
|||
|
PowerAction a driver should see in it's S-IRP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Action - The action we are using internally
|
|||
|
|
|||
|
SystemPowerState - The system power state for that action
|
|||
|
|
|||
|
UnmapWarmEject - If TRUE, PowerActionWarmEject is converted to
|
|||
|
PowerActionSleep or PowerActionHibernate as appropriate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The appropriate PowerAction to place in the ShutdownType field of an S-IRP.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ASSERT( Action != PowerActionHibernate );
|
|||
|
|
|||
|
if (Action != PowerActionWarmEject) {
|
|||
|
|
|||
|
//
|
|||
|
// We aren't doing a warm eject, so we simply return the original
|
|||
|
// power action unless it's the sleep is S4, in which case we switch
|
|||
|
// it to PowerActionHibernate.
|
|||
|
//
|
|||
|
|
|||
|
return (SystemPowerState != PowerSystemHibernate) ? Action :
|
|||
|
PowerActionHibernate;
|
|||
|
}
|
|||
|
|
|||
|
if (UnmapWarmEject) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a warm eject operation, but not neccessarily for this device.
|
|||
|
//
|
|||
|
|
|||
|
return (SystemPowerState != PowerSystemHibernate) ? PowerActionSleep :
|
|||
|
PowerActionHibernate;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is a warm eject operation, so we should only see a sleep state
|
|||
|
// (S1-S4). We do the check here because we could get a D0 request in
|
|||
|
// response to our S IRP, and stamp D-IRPs with the current power action.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT((SystemPowerState >= PowerSystemSleeping1) &&
|
|||
|
(SystemPowerState <= PowerSystemHibernate)) ;
|
|||
|
|
|||
|
return PowerActionWarmEject;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PopFilterCapabilities(
|
|||
|
IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
|
|||
|
OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine filters the actual reported capabilities of the system into
|
|||
|
the visible capabilities of the system. Some capabilities will be hidden
|
|||
|
based on the presence of legacy drivers.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SourceCapabilities - Supplies the original capabilities
|
|||
|
|
|||
|
FilteredCapabilities - Returns the filtered capabilities.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PNP_VETO_TYPE VetoType;
|
|||
|
PWSTR VetoList;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
RtlCopyMemory(FilteredCapabilities, SourceCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
|
|||
|
|
|||
|
//
|
|||
|
// If any legacy drivers are installed, then no sleeping states
|
|||
|
// are allowed at all.
|
|||
|
//
|
|||
|
Status = IoGetLegacyVetoList(&VetoList, &VetoType);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
if (VetoType != PNP_VetoTypeUnknown) {
|
|||
|
|
|||
|
PoPrint(PO_WARN,
|
|||
|
("PopFilterCapabilities: disabling sleep states due to legacy %s: %ws\n",
|
|||
|
(VetoType == PNP_VetoLegacyDriver) ? "driver" : "device",
|
|||
|
VetoList));
|
|||
|
FilteredCapabilities->SystemS1 = FALSE;
|
|||
|
FilteredCapabilities->SystemS2 = FALSE;
|
|||
|
FilteredCapabilities->SystemS3 = FALSE;
|
|||
|
FilteredCapabilities->SystemS4 = FALSE;
|
|||
|
}
|
|||
|
if (VetoList != NULL) {
|
|||
|
ExFreePool(VetoList);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we previously tried and failed to hibernate, then we need to
|
|||
|
// disable any further attempts.
|
|||
|
//
|
|||
|
if( PopFailedHibernationAttempt ) {
|
|||
|
FilteredCapabilities->SystemS4 = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we are running in x86 PAE mode, then hibernation is disabled
|
|||
|
//
|
|||
|
#if defined(i386)
|
|||
|
if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]) {
|
|||
|
FilteredCapabilities->SystemS4 = FALSE;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PopUserIsAdmin(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determines whether the current user is an administrator and therefore suitably
|
|||
|
privileged to change the administrative power policy.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - user is an administrator
|
|||
|
|
|||
|
FALSE - user is not an administrator
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
|||
|
PACCESS_TOKEN Token;
|
|||
|
BOOLEAN IsAdmin;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
SeCaptureSubjectContext(&SubjectContext);
|
|||
|
SeLockSubjectContext(&SubjectContext);
|
|||
|
Token = SeQuerySubjectContextToken(&SubjectContext);
|
|||
|
IsAdmin = SeTokenIsAdmin(Token);
|
|||
|
SeUnlockSubjectContext(&SubjectContext);
|
|||
|
SeReleaseSubjectContext(&SubjectContext);
|
|||
|
|
|||
|
return(IsAdmin);
|
|||
|
|
|||
|
}
|