507 lines
8.7 KiB
C
507 lines
8.7 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
attrib.c
|
|
|
|
Abstract:
|
|
|
|
Power management attribute accounting
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 25-Feb-97
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "pop.h"
|
|
|
|
VOID
|
|
PopUserPresentSetWorker(
|
|
PVOID Context
|
|
);
|
|
|
|
//
|
|
// System state structure to track registered settings
|
|
//
|
|
|
|
typedef struct {
|
|
ULONG State;
|
|
} POP_SYSTEM_STATE, *PPOP_SYSTEM_STATE;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PopUserPresentSetWorker)
|
|
#endif
|
|
|
|
VOID
|
|
PoSetSystemState (
|
|
IN ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to pulse attribute(s) as busy.
|
|
|
|
Arguments:
|
|
|
|
Flags - Attributes to pulse
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Verify reserved bits are clear and continous is not set
|
|
//
|
|
|
|
if (Flags & ~(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED | POP_LOW_LATENCY | ES_USER_PRESENT)) {
|
|
PopInternalError (POP_ATTRIB);
|
|
}
|
|
|
|
//
|
|
// Apply the attributes
|
|
//
|
|
|
|
PopApplyAttributeState (Flags, 0);
|
|
|
|
//
|
|
// Check for work
|
|
//
|
|
|
|
PopCheckForWork (TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
PVOID
|
|
PoRegisterSystemState (
|
|
IN PVOID StateHandle,
|
|
IN ULONG NewFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to register or pulse attribute(s) as busy.
|
|
|
|
Arguments:
|
|
|
|
StateHandle - If StateHandle is null, then a new registration is allocated, set
|
|
accordingly, and returned. If non-null, the pass registeration
|
|
is adjusted to its new setting.
|
|
|
|
NewFlags - Attributes to set or pulse
|
|
|
|
Return Value:
|
|
|
|
Handle to unregister when complete
|
|
|
|
--*/
|
|
{
|
|
ULONG OldFlags;
|
|
PPOP_SYSTEM_STATE SystemState;
|
|
|
|
//
|
|
// Verify reserved bits are clear
|
|
//
|
|
|
|
if (NewFlags & ~(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED |
|
|
POP_LOW_LATENCY | ES_USER_PRESENT)) {
|
|
|
|
PopInternalError (POP_ATTRIB);
|
|
}
|
|
|
|
//
|
|
// If there's no state handle allocated, do it now
|
|
//
|
|
|
|
if (!StateHandle) {
|
|
StateHandle = ExAllocatePoolWithTag (
|
|
NonPagedPool,
|
|
sizeof (POP_SYSTEM_STATE),
|
|
POP_PSTA_TAG
|
|
);
|
|
|
|
if (!StateHandle) {
|
|
return NULL;
|
|
}
|
|
RtlZeroMemory(StateHandle, sizeof(POP_SYSTEM_STATE));
|
|
}
|
|
|
|
//
|
|
// If the continous bit is set, modify current flags
|
|
//
|
|
|
|
SystemState = (PPOP_SYSTEM_STATE) StateHandle;
|
|
OldFlags = SystemState->State | ES_CONTINUOUS;
|
|
if (NewFlags & ES_CONTINUOUS) {
|
|
OldFlags = InterlockedExchange (&SystemState->State, NewFlags);
|
|
}
|
|
|
|
//
|
|
// Apply the changes
|
|
//
|
|
|
|
PopApplyAttributeState (NewFlags, OldFlags);
|
|
|
|
//
|
|
// Check for any outstanding work
|
|
//
|
|
|
|
PopCheckForWork (FALSE);
|
|
|
|
//
|
|
// Done
|
|
//
|
|
|
|
return SystemState;
|
|
}
|
|
|
|
|
|
VOID
|
|
PoUnregisterSystemState (
|
|
IN PVOID StateHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a registration allocated by PoRegisterSystemState
|
|
|
|
Arguments:
|
|
|
|
StateHandle - If non-null, existing registeration to change
|
|
|
|
NewFlags - Attributes to set or pulse
|
|
|
|
Return Value:
|
|
|
|
Handle to unregister when complete
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Make sure current attribute settings are clear
|
|
//
|
|
|
|
PoRegisterSystemState (StateHandle, ES_CONTINUOUS);
|
|
|
|
//
|
|
// Free state structure
|
|
//
|
|
|
|
ExFreePool (StateHandle);
|
|
}
|
|
|
|
|
|
VOID
|
|
PopApplyAttributeState (
|
|
IN ULONG NewFlags,
|
|
IN ULONG OldFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function applies attribute flags to system. If the attributes
|
|
are continuous in nature, then a count is updated to reflect
|
|
the total number of outstanding settings.
|
|
|
|
Arguments:
|
|
|
|
NewFlags - Attributes being set
|
|
|
|
OldFlags - Current attributes
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
ULONG Count;
|
|
ULONG Changes;
|
|
ULONG Mask;
|
|
PPOP_STATE_ATTRIBUTE Attribute;
|
|
|
|
//
|
|
// Get flags which have changed
|
|
//
|
|
|
|
Changes = (NewFlags ^ OldFlags) & ~ES_CONTINUOUS;
|
|
|
|
//
|
|
// Check each flag
|
|
//
|
|
|
|
while (Changes) {
|
|
//
|
|
// Get change
|
|
//
|
|
|
|
i = KeFindFirstSetRightMember(Changes);
|
|
Mask = 1 << i;
|
|
Changes &= ~Mask;
|
|
Attribute = PopAttributes + i;
|
|
|
|
//
|
|
// If this is a continous change, update the flags
|
|
//
|
|
|
|
if (NewFlags & ES_CONTINUOUS) {
|
|
|
|
//
|
|
// Count the times the attribite is set or cleared
|
|
//
|
|
|
|
if (NewFlags & Mask) {
|
|
|
|
//
|
|
// Being set
|
|
//
|
|
|
|
Count = InterlockedIncrement (&Attribute->Count);
|
|
|
|
//
|
|
// If attributes count is moved from zero, set it
|
|
//
|
|
|
|
if (Count == 1) {
|
|
Attribute->Set (Attribute->Arg);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Being cleared
|
|
//
|
|
|
|
Count = InterlockedDecrement (&Attribute->Count);
|
|
ASSERT (Count != -1);
|
|
|
|
//
|
|
// If attributes count is now zero, clear it
|
|
//
|
|
|
|
if (Count == 0 && Attribute->NotifyOnClear) {
|
|
Attribute->Set (Attribute->Arg);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If count is 0, pulse it
|
|
//
|
|
|
|
|
|
if (Attribute->Count == 0) {
|
|
|
|
//
|
|
// Pulse the attribute
|
|
//
|
|
|
|
Attribute->Set (Attribute->Arg);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PopAttribNop (
|
|
IN ULONG Arg
|
|
)
|
|
{
|
|
}
|
|
|
|
VOID
|
|
PopSystemRequiredSet (
|
|
IN ULONG Arg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
System required attribute has been set
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// System is not idle
|
|
//
|
|
|
|
if (PopSIdle.Time) {
|
|
PopSIdle.Time = 0;
|
|
}
|
|
}
|
|
|
|
#define AllBitsSet(a,b) ( ((a) & (b)) == (b) )
|
|
|
|
VOID
|
|
PopDisplayRequired (
|
|
IN ULONG Arg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display required attribute has been set/cleared
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// If gdi isn't on, do it now
|
|
//
|
|
|
|
if ( !AnyBitsSet (PopFullWake, PO_GDI_STATUS | PO_GDI_ON_PENDING)) {
|
|
InterlockedOr (&PopFullWake, PO_GDI_ON_PENDING);
|
|
}
|
|
|
|
//
|
|
// Inform GDI of the display needed change
|
|
//
|
|
|
|
PopSetNotificationWork (PO_NOTIFY_DISPLAY_REQUIRED);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
PopUserPresentSet (
|
|
IN ULONG Arg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
User presence attribute has been set
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PULONG runningWorker;
|
|
|
|
//
|
|
// System is not idle
|
|
//
|
|
|
|
if (PopSIdle.Time) {
|
|
PopSIdle.Time = 0;
|
|
}
|
|
|
|
//
|
|
// If the system isn't fully awake, and the all the wake pending bits
|
|
// are not set, set them
|
|
//
|
|
|
|
if (!AllBitsSet (PopFullWake, PO_FULL_WAKE_STATUS | PO_GDI_STATUS)) {
|
|
|
|
if (!AllBitsSet (PopFullWake, PO_FULL_WAKE_PENDING | PO_GDI_ON_PENDING)) {
|
|
|
|
InterlockedOr (&PopFullWake, (PO_FULL_WAKE_PENDING | PO_GDI_ON_PENDING));
|
|
PopSetNotificationWork (PO_NOTIFY_FULL_WAKE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Go to passive level to look for lid switches.
|
|
//
|
|
|
|
runningWorker = InterlockedExchangePointer(&PopUserPresentWorkItem.Parameter,
|
|
(PVOID)TRUE);
|
|
|
|
if (runningWorker) {
|
|
return;
|
|
}
|
|
|
|
ExInitializeWorkItem(&PopUserPresentWorkItem,
|
|
PopUserPresentSetWorker,
|
|
PopUserPresentWorkItem.Parameter);
|
|
|
|
ExQueueWorkItem(
|
|
&PopUserPresentWorkItem,
|
|
DelayedWorkQueue
|
|
);
|
|
}
|
|
|
|
VOID
|
|
PopUserPresentSetWorker(
|
|
PVOID Context
|
|
)
|
|
{
|
|
PPOP_SWITCH_DEVICE switchDev;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// We can't always know for sure whether the lid (if there is one)
|
|
// is opened or closed. Assume that if the user is present,
|
|
// the lid is opened.
|
|
//
|
|
|
|
switchDev = (PPOP_SWITCH_DEVICE)PopSwitches.Flink;
|
|
|
|
while (switchDev != (PPOP_SWITCH_DEVICE)&PopSwitches) {
|
|
|
|
if ((switchDev->Caps & SYS_BUTTON_LID) &&
|
|
(switchDev->Opened == FALSE)) {
|
|
|
|
//
|
|
// We currently believe that the lid is closed. Set
|
|
// it to "opened."
|
|
//
|
|
|
|
switchDev->Opened = TRUE;
|
|
//
|
|
// Notify the PowerState callback.
|
|
//
|
|
|
|
ExNotifyCallback (
|
|
ExCbPowerState,
|
|
UIntToPtr(PO_CB_LID_SWITCH_STATE),
|
|
UIntToPtr(switchDev->Opened)
|
|
);
|
|
}
|
|
|
|
switchDev = (PPOP_SWITCH_DEVICE)switchDev->Link.Flink;
|
|
}
|
|
|
|
InterlockedExchangePointer(&PopUserPresentWorkItem.Parameter,
|
|
(PVOID)FALSE);
|
|
}
|