Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

343 lines
9.5 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
idle.c
Abstract:
This module implements the power management idle timing code for
device objects
Author:
Bryan Willman (bryanwi) 7-Nov-96
Revision History:
--*/
#include "pop.h"
NTKERNELAPI
PULONG
PoRegisterDeviceForIdleDetection (
IN PDEVICE_OBJECT DeviceObject,
IN ULONG ConservationIdleTime,
IN ULONG PerformanceIdleTime,
IN DEVICE_POWER_STATE State
)
/*++
Routine Description:
A device driver calls this routine to either:
a. Create and initialize a new idle detection block
b. Reset values in an existing idle detection block
If the device object has an idle detection block, it is
filled in with new values.
Otherwise, an idle detect block is created and linked to the device
object.
Arguments:
DeviceObject - Device object which wants idle detection, set_power
IRPs will be sent here
ConservationIdleTime - timeout for system in "conserve mode"
PerformanceIdleTime - timeout for system in "performance mode"
Type - Type of set_power sent (for set_power irp)
State - what state to go to (for set_power irp)
Return Value:
NULL - if an attempt to create a new idle block failed
non-NULL - if an idle block was created, or if an existing one was reset
--*/
{
PDEVICE_OBJECT_POWER_EXTENSION pdope;
KIRQL OldIrql;
ULONG DeviceType, OldDeviceType;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
ASSERT(DeviceObject != NULL);
//
// deal with the case where idle detection is being turned off
//
if ((ConservationIdleTime == 0) && (PerformanceIdleTime == 0)) {
PopLockDopeGlobal(&OldIrql);
pdope = DeviceObject->DeviceObjectExtension->Dope;
if (pdope == NULL) {
//
// cannot be linked into the chain, so must already be off,
// so we're done
//
} else {
//
// there is a pdope, so we may be on the idle list
//
if ((pdope->IdleList.Flink == &(pdope->IdleList)) &&
(pdope->IdleList.Blink == &(pdope->IdleList)))
{
//
// we're off the queue already, so we're done
//
} else {
//
// a dope vector exists and is on the idle scan list,
// so we must delist ourselves
//
RemoveEntryList(&(pdope->IdleList));
OldDeviceType = pdope->DeviceType | ES_CONTINUOUS;
pdope->DeviceType = 0;
PopApplyAttributeState (ES_CONTINUOUS, OldDeviceType);
pdope->ConservationIdleTime = 0L;
pdope->PerformanceIdleTime = 0L;
pdope->State = PowerDeviceUnspecified;
pdope->IdleCount = 0;
InitializeListHead(&(pdope->IdleList));
}
}
PopUnlockDopeGlobal(OldIrql);
return NULL;
}
//
// Set DeviceType if this is an idle registration by type
//
DeviceType = 0;
if (ConservationIdleTime == (ULONG) -1 &&
PerformanceIdleTime == (ULONG) -1) {
switch (DeviceObject->DeviceType) {
case FILE_DEVICE_DISK:
case FILE_DEVICE_MASS_STORAGE:
//
// Or-in ES_CONTINUOUS which will go up
// in the high bits. We'll ignore this bit
// when we typecast this into a UCHAR as we
// assign this to pdope->DeviceType, however, we
// need this high bit set for when we call into
// PopApplyAttributeState. That's because we
// overload the flags we send into this function
// with both the device type and the flags to
// apply to that device type.
//
DeviceType = POP_DISK_SPINDOWN | ES_CONTINUOUS;
break;
default:
//
// Unsupported type
//
return NULL;
}
}
//
// now, the case where it's being turned on
//
pdope = PopGetDope(DeviceObject);
if (pdope == NULL) {
//
// we didn't have a DOPE structure and couldn't allocate one, fail
//
return NULL;
}
//
// May be a newly allocated Dope, or an existing one.
// In either case, update values.
// Enqueue if not already in queue
//
PopLockDopeGlobal(&OldIrql);
OldDeviceType = pdope->DeviceType | ES_CONTINUOUS;
pdope->ConservationIdleTime = ConservationIdleTime;
pdope->PerformanceIdleTime = PerformanceIdleTime;
pdope->State = State;
pdope->IdleCount = 0;
//
// type cast this so we ignore any high bits set which
// may contain attributes. All we care about is the
// device type, which is in the low byte.
//
pdope->DeviceType = (UCHAR) DeviceType;
if ((pdope->IdleList.Flink == &(pdope->IdleList)) &&
(pdope->IdleList.Blink == &(pdope->IdleList)))
{
//
// we're off the queue, and must be enqueued
//
InsertTailList(&PopIdleDetectList, &(pdope->IdleList));
}
PopUnlockDopeGlobal(OldIrql);
PopApplyAttributeState(DeviceType, OldDeviceType);
PopCheckForWork(TRUE);
return (PULONG) &(pdope->IdleCount); // success
}
VOID
PopScanIdleList(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
Called by the PopIdleScanTimer at PopIdleScanTimeInseconds interval,
this routine runs the list of Idle Blocks, finding any that meet the
trip conditions, and sends commands to the appropriate device objects
to change state.
The timer that calls this DPC is setup in poinit.c.
Arguments:
Standard DPC arguments, all are ignored.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PLIST_ENTRY link;
ULONG idlelimit;
PDEVICE_OBJECT_POWER_EXTENSION pblock;
POWER_STATE PowerState;
PLONG pIdleCount;
ULONG oldCount;
UNREFERENCED_PARAMETER (Dpc);
UNREFERENCED_PARAMETER (DeferredContext);
UNREFERENCED_PARAMETER (SystemArgument1);
UNREFERENCED_PARAMETER (SystemArgument2);
PopLockDopeGlobal(&OldIrql);
link = PopIdleDetectList.Flink;
while (link != &PopIdleDetectList) {
pblock = CONTAINING_RECORD(link, DEVICE_OBJECT_POWER_EXTENSION, IdleList);
pIdleCount = &(pblock->IdleCount);
oldCount = InterlockedIncrement(pIdleCount);
switch (pblock->DeviceType) {
case 0:
idlelimit = pblock->PerformanceIdleTime;
if (PopIdleDetectionMode == PO_IDLE_CONSERVATION) {
idlelimit = pblock->ConservationIdleTime;
}
break;
case POP_DISK_SPINDOWN:
idlelimit = PopPolicy->SpindownTimeout;
break;
default:
idlelimit = 0;
PopInternalAddToDumpFile( NULL, 0, pblock->DeviceObject, NULL, NULL, pblock );
KeBugCheckEx( INTERNAL_POWER_ERROR,
0x200,
POP_IDLE,
(ULONG_PTR)pblock->DeviceObject,
(ULONG_PTR)pblock );
}
if ((idlelimit > 0) && ((oldCount+1) == idlelimit)) {
PowerState.DeviceState = pblock->State;
PoRequestPowerIrp (
pblock->DeviceObject,
IRP_MN_SET_POWER,
PowerState,
NULL,
NULL,
NULL
);
}
link = link->Flink;
}
PopUnlockDopeGlobal(OldIrql);
return;
}
PDEVICE_OBJECT_POWER_EXTENSION
PopGetDope (
PDEVICE_OBJECT DeviceObject
)
{
PDEVOBJ_EXTENSION Doe;
PDEVICE_OBJECT_POWER_EXTENSION Dope;
KIRQL OldIrql;
Doe = (PDEVOBJ_EXTENSION) DeviceObject->DeviceObjectExtension;
if (!Doe->Dope) {
PopLockDopeGlobal(&OldIrql);
if (!Doe->Dope) {
Dope = (PDEVICE_OBJECT_POWER_EXTENSION)
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(DEVICE_OBJECT_POWER_EXTENSION),
POP_DOPE_TAG
);
if (Dope) {
RtlZeroMemory (Dope, sizeof(DEVICE_OBJECT_POWER_EXTENSION));
Dope->DeviceObject = DeviceObject;
Dope->State = PowerDeviceUnspecified;
InitializeListHead(&(Dope->IdleList));
InitializeListHead(&(Dope->NotifySourceList));
InitializeListHead(&(Dope->NotifyTargetList));
// force the signature to 0 so buildpowerchannel gets called
Dope->PowerChannelSummary.Signature = (ULONG)0;
InitializeListHead(&(Dope->PowerChannelSummary.NotifyList));
Doe->Dope = Dope;
}
}
PopUnlockDopeGlobal(OldIrql);
}
return Doe->Dope;
}