windows-nt/Source/XPSP1/NT/base/ntos/po/attrib.c
2020-09-26 16:20:57 +08:00

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);
}