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.
 
 
 
 
 
 

1133 lines
40 KiB

/*****************************************************************************
* power.cpp - WDM Streaming port class driver
*****************************************************************************
* Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
*
* This file contains code related to ACPI / power management
* for the audio adpaters/miniports
*/
#include "private.h"
#ifndef DEBUGLVL_POWER
#define DEBUGLVL_POWER DEBUGLVL_VERBOSE
#endif
NTSTATUS
ProcessPowerIrp
(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpStack,
IN PDEVICE_OBJECT pDeviceObject
);
#pragma code_seg("PAGE")
/*****************************************************************************
* GetDeviceACPIInfo()
*****************************************************************************
* Called in response to a PnP - IRP_MN_QUERY_CAPABILITIES
* Call the bus driver to fill out the inital info,
* Then overwrite with our own...
*
*/
NTSTATUS
GetDeviceACPIInfo
(
IN PIRP pIrp,
IN PDEVICE_OBJECT pDeviceObject
)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_POWER,("GetDeviceACPIInfo"));
ASSERT( pDeviceObject );
PDEVICE_CONTEXT pDeviceContext
= PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT( pDeviceContext );
// Gotta call down to the PDO (bus driver)
// and let it fill out the default for this bus
NTSTATUS ntStatus = ForwardIrpSynchronous( pDeviceContext, pIrp );
if( NT_SUCCESS(ntStatus) )
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
PDEVICE_CAPABILITIES pDeviceCaps = irpSp->Parameters.DeviceCapabilities.Capabilities;
ASSERT( pDeviceCaps );
ASSERT( pDeviceCaps->Size >= sizeof( DEVICE_CAPABILITIES ) );
if( pDeviceCaps && ( pDeviceCaps->Size >= sizeof( DEVICE_CAPABILITIES ) ) )
{
// pass the structure on down to the adapter
if( pDeviceContext )
{
if( pDeviceContext->pAdapterPower )
{
ntStatus = pDeviceContext->pAdapterPower->QueryDeviceCapabilities( pDeviceCaps );
ASSERT(ntStatus != STATUS_PENDING);
}
}
// make sure that we have sensible settings for the system sleep states
pDeviceCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0;
for(ULONG i=ULONG(PowerSystemSleeping1); i <= ULONG(PowerSystemShutdown); i++ )
{
// and we want some sleeping in the sleep modes.
//
// DEADISSUE-00/11/11-MartinP
// We go ahead and include this code, even though it is possible that
// there are devices that exist that can maintain state in the device
// while sleeping.
//
if(pDeviceCaps->DeviceState[i] == PowerDeviceD0)
{
pDeviceCaps->DeviceState[i] = PowerDeviceD3;
}
}
// save in our device extension the stuff we're interested in
for( i=ULONG(PowerSystemUnspecified); i < ULONG(PowerSystemMaximum); i++)
{
pDeviceContext->DeviceStateMap[ i ] = pDeviceCaps->DeviceState[ i ];
}
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemUnspecified = D%d", pDeviceCaps->DeviceState[PowerSystemUnspecified] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemWorking = D%d", pDeviceCaps->DeviceState[PowerSystemWorking] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping1 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping1] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping2 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping2] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping3 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping3] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemHibernate = D%d", pDeviceCaps->DeviceState[PowerSystemHibernate] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemShutdown = D%d", pDeviceCaps->DeviceState[PowerSystemShutdown] - 1));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: SystemWake = %d", pDeviceCaps->SystemWake ));
_DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: DeviceWake = %d", pDeviceCaps->DeviceWake ));
}
}
// complete the irp
CompleteIrp( pDeviceContext, pIrp, ntStatus );
// set the current power states
pDeviceContext->CurrentDeviceState = PowerDeviceD0;
pDeviceContext->CurrentSystemState = PowerSystemWorking;
// attempt to get the idle info from the registry
if( NT_SUCCESS(ntStatus) )
{
ULONG ConservationIdleTime;
ULONG PerformanceIdleTime;
DEVICE_POWER_STATE IdleDeviceState;
NTSTATUS ntStatus2 = GetIdleInfoFromRegistry( pDeviceContext,
&ConservationIdleTime,
&PerformanceIdleTime,
&IdleDeviceState );
if(NT_SUCCESS(ntStatus2))
{
pDeviceContext->ConservationIdleTime = ConservationIdleTime;
pDeviceContext->PerformanceIdleTime = PerformanceIdleTime;
pDeviceContext->IdleDeviceState = IdleDeviceState;
}
// register for idle detection
pDeviceContext->IdleTimer = PoRegisterDeviceForIdleDetection( pDeviceContext->PhysicalDeviceObject,
pDeviceContext->ConservationIdleTime,
pDeviceContext->PerformanceIdleTime,
pDeviceContext->IdleDeviceState );
_DbgPrintF(DEBUGLVL_POWER,("Idle Detection Enabled (%d %d %d) %s", pDeviceContext->ConservationIdleTime,
pDeviceContext->PerformanceIdleTime,
ULONG(pDeviceContext->IdleDeviceState),
pDeviceContext->IdleTimer ? "" : "FAILED!"));
}
return ntStatus;
}
#pragma code_seg()
VOID
DevicePowerRequestRoutine(
IN PKDPC Dpc,
IN PVOID Context,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
{
PDEVICE_CONTEXT pDeviceContext = (PDEVICE_CONTEXT) Context;
POWER_STATE newPowerState;
newPowerState.DeviceState = PowerDeviceD0;
PoRequestPowerIrp(pDeviceContext->PhysicalDeviceObject,
IRP_MN_SET_POWER,
newPowerState,
NULL,
NULL,
NULL
);
}
/*****************************************************************************
* PowerIrpCompletionRoutine()
*****************************************************************************
* Used when requested a new power irp.
* Just signal an event and return.
*
*/
VOID
PowerIrpCompletionRoutine
(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
ASSERT(Context);
_DbgPrintF( DEBUGLVL_POWER, ("PowerIrpCompletionRoutine"));
PPOWER_IRP_CONTEXT pPowerIrpContext = PPOWER_IRP_CONTEXT(Context);
// set the return status
pPowerIrpContext->Status = IoStatus->Status;
// complete any pending system power irp
if( pPowerIrpContext->PendingSystemPowerIrp )
{
_DbgPrintF(DEBUGLVL_POWER,("Device Set/Query Power Irp completed, Completing Associated System Power Irp"));
if (NT_SUCCESS(IoStatus->Status))
{
// Forward the system set power irp to the PDO
ForwardIrpSynchronous( pPowerIrpContext->DeviceContext,
pPowerIrpContext->PendingSystemPowerIrp );
} else
{
pPowerIrpContext->PendingSystemPowerIrp->IoStatus.Status = IoStatus->Status;
}
// start the next power irp
PoStartNextPowerIrp( pPowerIrpContext->PendingSystemPowerIrp );
// complete the system set power irp
CompleteIrp( pPowerIrpContext->DeviceContext,
pPowerIrpContext->PendingSystemPowerIrp,
pPowerIrpContext->PendingSystemPowerIrp->IoStatus.Status );
// free the context (only when completing a pending system power irp)
ExFreePool( pPowerIrpContext );
} else
{
// set the sync event (not used in conjunction with pending system power irps)
if( pPowerIrpContext->PowerSyncEvent )
{
KeSetEvent( pPowerIrpContext->PowerSyncEvent,
0,
FALSE );
}
}
}
#pragma code_seg("PAGE")
/*****************************************************************************
* DispatchPower()
*****************************************************************************
* Deals with all the power/ACPI messages from the OS.
* yay.
*
*/
NTSTATUS
DispatchPower
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pIrp);
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation(pIrp);
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
if (!NT_SUCCESS(ntStatus))
{
// Don't know what to do, but this is probably a PDO.
// We'll try to make this right by completing the IRP
// untouched (per PnP, WMI, and Power rules). Note
// that if this isn't a PDO, and isn't a portcls FDO, then
// the driver messed up by using Portcls as a filter (huh?)
// In this case the verifier will fail us, WHQL will catch
// them, and the driver will be fixed. We'd be very surprised
// to see such a case.
PoStartNextPowerIrp( pIrp );
ntStatus = pIrp->IoStatus.Status;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return ntStatus;
}
IncrementPendingIrpCount( pDeviceContext );
#if (DBG)
static PCHAR aszMnNames[] =
{
"IRP_MN_WAIT_WAKE",
"IRP_MN_POWER_SEQUENCE",
"IRP_MN_SET_POWER",
"IRP_MN_QUERY_POWER"
};
if (pIrpStack->MinorFunction >= SIZEOF_ARRAY(aszMnNames))
{
_DbgPrintF( DEBUGLVL_POWER,("DispatchPower function 0x%02x",pIrpStack->MinorFunction));
}
else
{
_DbgPrintF( DEBUGLVL_POWER,("DispatchPower function %s",aszMnNames[pIrpStack->MinorFunction]));
}
#endif
// Assume we won't deal with the irp.
BOOL IrpHandled = FALSE;
switch (pIrpStack->MinorFunction)
{
case IRP_MN_QUERY_POWER:
case IRP_MN_SET_POWER:
// Is this a device state change?
if( DevicePowerState == pIrpStack->Parameters.Power.Type )
{
// yeah. Deal with it
ntStatus = ProcessPowerIrp( pIrp,
pIrpStack,
pDeviceObject );
IrpHandled = TRUE;
// And quit.
} else
{
// A system state change
if( IRP_MN_QUERY_POWER == pIrpStack->MinorFunction )
{
_DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_QUERY_POWER: ->S%d",
pIrpStack->Parameters.Power.State.SystemState-1));
} else
{
_DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_SET_POWER: ->S%d",
pIrpStack->Parameters.Power.State.SystemState-1));
}
POWER_STATE newPowerState;
// determine appropriate device state
newPowerState.DeviceState = pDeviceContext->DeviceStateMap[ pIrpStack->Parameters.Power.State.SystemState ];
//
// do a sanity check on the device state
if ((newPowerState.DeviceState < PowerDeviceD0) ||
(newPowerState.DeviceState > PowerDeviceD3) )
{
if (pIrpStack->Parameters.Power.State.SystemState == PowerSystemWorking)
{
newPowerState.DeviceState = PowerDeviceD0;
} else
{
newPowerState.DeviceState = PowerDeviceD3;
}
}
_DbgPrintF(DEBUGLVL_POWER,(" ...Requesting Device Power IRP -> D%d",newPowerState.DeviceState-1));
if ((pIrpStack->MinorFunction == IRP_MN_SET_POWER) &&
(newPowerState.DeviceState == PowerDeviceD0)) {
//
// doing a resume, request the D irp, but complete S-irp immediately
//
KeInsertQueueDpc(&pDeviceContext->DevicePowerRequestDpc, NULL, NULL);
break;
} else {
// allocate a completion context (can't be on the stack because we're not going to block)
PPOWER_IRP_CONTEXT PowerIrpContext =
PPOWER_IRP_CONTEXT(ExAllocatePoolWithTag(NonPagedPool,
sizeof(POWER_IRP_CONTEXT),
'oPcP' ) ); // 'PcPo'
if (PowerIrpContext)
{
_DbgPrintF(DEBUGLVL_POWER,("...Pending System Power Irp until Device Power Irp completes"));
// set up device power irp completion context
PowerIrpContext->PowerSyncEvent = NULL;
#if DBG
PowerIrpContext->Status = STATUS_PENDING;
#endif
PowerIrpContext->PendingSystemPowerIrp = pIrp;
PowerIrpContext->DeviceContext = pDeviceContext;
// pend the system set power irp
//
#if DBG
pIrp->IoStatus.Status = STATUS_PENDING;
#endif
IoMarkIrpPending( pIrp );
// set our tracking of system power state
if (pIrpStack->MinorFunction == IRP_MN_SET_POWER) {
pDeviceContext->CurrentSystemState = pIrpStack->Parameters.Power.State.SystemState;
}
// request the new device state
//
ntStatus = PoRequestPowerIrp(
pDeviceContext->PhysicalDeviceObject,
pIrpStack->MinorFunction,
newPowerState,
PowerIrpCompletionRoutine,
PowerIrpContext,
NULL
);
if (!NT_SUCCESS(ntStatus))
{
_DbgPrintF(DEBUGLVL_TERSE,("PoRequestPowerIrp failed (%08x)", ntStatus));
CompleteIrp( pDeviceContext, pIrp, ntStatus );
}
IrpHandled = TRUE;
// set up return status
ntStatus = STATUS_PENDING;
} else
{
// couldn't allocate completion context
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
PoStartNextPowerIrp( pIrp );
CompleteIrp( pDeviceContext, pIrp, ntStatus);
return ntStatus;
}
}
}
break;
}
// If we didn't cope with the irp
if( !IrpHandled )
{
// Send it on it's way.
ntStatus = ForwardIrpSynchronous( pDeviceContext, pIrp );
// and complete it.
PoStartNextPowerIrp( pIrp );
CompleteIrp( pDeviceContext, pIrp, ntStatus );
}
return ntStatus;
}
/*****************************************************************************
* PcRegisterAdapterPowerManagement()
*****************************************************************************
* Register the adapter's power management interface
* with portcls. This routine also does a QI for a shutdown notification
* interface.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterAdapterPowerManagement
(
IN PUNKNOWN Unknown,
IN PVOID pvContext1
)
{
PAGED_CODE();
ASSERT(pvContext1);
ASSERT(Unknown);
_DbgPrintF(DEBUGLVL_POWER,("PcRegisterAdapterPowerManagement"));
//
// Validate Parameters.
//
if (NULL == pvContext1 ||
NULL == Unknown)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterAdapterPowerManagement : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
PDEVICE_OBJECT pDeviceObject = PDEVICE_OBJECT(pvContext1);
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT( pDeviceContext );
//
// Validate DeviceContext.
//
if (NULL == pDeviceContext)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterAdapterPowerManagement : Invalid DeviceContext"));
return STATUS_INVALID_PARAMETER;
}
#if (DBG)
if( pDeviceContext->pAdapterPower )
{
_DbgPrintF( DEBUGLVL_POWER, ("Adapter overwriting PowerManagement interface"));
}
#endif
// Make sure this is really the right
// interface (Note: We have to release
// it when the device is closed/stoped )
PVOID pResult;
ntStatus = Unknown->QueryInterface
(
IID_IAdapterPowerManagement,
&pResult
);
if( NT_SUCCESS(ntStatus) )
{
// Store the interface for later use.
pDeviceContext->pAdapterPower = PADAPTERPOWERMANAGEMENT( pResult );
} else
{
pDeviceContext->pAdapterPower = 0;
}
return ntStatus;
}
/*****************************************************************************
* PowerNotifySubdevices()
*****************************************************************************
* Called by ProcessPowerIrp to notify the device's subdevices of a power
* state change.
*
*/
void
PowerNotifySubdevices
(
IN PDEVICE_CONTEXT pDeviceContext,
IN POWER_STATE PowerState
)
{
PAGED_CODE();
ASSERT(pDeviceContext);
_DbgPrintF(DEBUGLVL_POWER,("PowerNotifySubdevices"));
// only notify the subdevices if we're started and if there are subdevices
if (pDeviceContext->DeviceStopState == DeviceStarted)
{
PKSOBJECT_CREATE_ITEM createItem = pDeviceContext->CreateItems;
// iterate through the subdevices
for( ULONG index=0; index < pDeviceContext->MaxObjects; index++,createItem++)
{
if( createItem && (createItem->Create) )
{
PSUBDEVICE subDevice = PSUBDEVICE( createItem->Context );
if( subDevice )
{
// notify the subdevice
subDevice->PowerChangeNotify( PowerState );
}
}
}
}
}
/*****************************************************************************
* DevicePowerWorker()
*****************************************************************************
* Called by ProcessPowerIrp in order to notify the device of the state change.
* This is done in a work item so that the processing for the D0 irp doesn't
* block the rest of the system from processing D0 irps.
*/
QUEUED_CALLBACK_RETURN
DevicePowerWorker
(
IN PDEVICE_OBJECT pDeviceObject,
IN PVOID PowerState
)
{
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
BOOL ProcessPendedIrps = FALSE;
POWER_STATE NewPowerState;
NewPowerState.DeviceState = (DEVICE_POWER_STATE)(ULONG_PTR)PowerState;
// acquire the device so we're sync'ed with creates
AcquireDevice(pDeviceContext);
// change the driver state if it has a registered POWER interface
if( pDeviceContext->pAdapterPower )
{
// notify the adapter
pDeviceContext->pAdapterPower->PowerChangeState( NewPowerState );
}
// keep track of new state
pDeviceContext->CurrentDeviceState = NewPowerState.DeviceState;
// notify everyone we're now in our lighter D-state
PoSetPowerState( pDeviceObject,
DevicePowerState,
NewPowerState );
PowerNotifySubdevices( pDeviceContext, NewPowerState );
// set PendCreates appropriately
if( pDeviceContext->DeviceStopState == DeviceStarted )
{
// start allowing creates
pDeviceContext->PendCreates = FALSE;
// we have to process the pended irps after we release the device
ProcessPendedIrps = TRUE;
}
ReleaseDevice(pDeviceContext);
// complete if necessary any pended IRPs
if ( ProcessPendedIrps )
{
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_PROCESS );
}
return QUEUED_CALLBACK_FREE;
}
/*****************************************************************************
* ProcessPowerIrp()
*****************************************************************************
* Called by DispatchPower to call the Adapter driver and all other work
* related to a request. Note that this routine MUST return STATUS_SUCCESS
* for IRP_MN_SET_POWER requests.
*
*/
NTSTATUS
ProcessPowerIrp
(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpStack,
IN PDEVICE_OBJECT pDeviceObject
)
{
PAGED_CODE();
ASSERT(pIrp);
ASSERT(pIrpStack);
ASSERT(pDeviceObject);
_DbgPrintF(DEBUGLVL_POWER,("ProcessPowerIrp"));
// Assume the worst
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
POWER_STATE NewPowerState = pIrpStack->Parameters.Power.State;
// Get the current count of open
// objects for this device (pins, streams, whatever).
// NOTE: This count is maintained by KSO.CPP
ULONG objectCount = pDeviceContext->ExistingObjectCount;
// get the active pin count
// NOTE: This count is maintained by IRPSTRM.CPP
ULONG activePinCount = pDeviceContext->ActivePinCount;
BOOL MovingToALighterState = (pDeviceContext->CurrentDeviceState > NewPowerState.DeviceState);
if (pDeviceContext->CurrentDeviceState != NewPowerState.DeviceState) {
// Deal with the particular IRP_MN
switch( pIrpStack->MinorFunction )
{
case IRP_MN_QUERY_POWER:
// simply query the driver if it has registered an interface
if( pDeviceContext->pAdapterPower )
{
ntStatus = pDeviceContext->pAdapterPower->QueryPowerChangeState( NewPowerState );
} else
{
// succeed the query
ntStatus = STATUS_SUCCESS;
}
_DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_QUERY_POWER: D%d->D%d %s",
pDeviceContext->CurrentDeviceState-1,
NewPowerState.DeviceState-1,
NT_SUCCESS(ntStatus) ? "OKAY" : "FAIL"));
break;
case IRP_MN_SET_POWER:
_DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_SET_POWER: D%d->D%d",
pDeviceContext->CurrentDeviceState-1,
NewPowerState.DeviceState-1));
// acquire the device so we're sync'ed with creates
AcquireDevice(pDeviceContext);
// if we're moving from a low power state to a higher power state
if( MovingToALighterState )
{
ASSERT(pDeviceContext->CurrentDeviceState != PowerDeviceD0);
ASSERT(NewPowerState.DeviceState == PowerDeviceD0);
// Then we need to forward to the PDO BEFORE doing our work.
ForwardIrpSynchronous( pDeviceContext, pIrp );
ReleaseDevice(pDeviceContext);
// Do the rest of the work in a work item in order to complete the D0 Irp
// as soon as possible
ntStatus = CallbackEnqueue(
&pDeviceContext->pWorkQueueItemStart,
DevicePowerWorker,
pDeviceObject,
(PVOID)(ULONG_PTR)NewPowerState.DeviceState,
PASSIVE_LEVEL,
EQCF_DIFFERENT_THREAD_REQUIRED
);
// If we fail to enqueue the callback, do this the slow way
if ( !NT_SUCCESS(ntStatus) )
{
DevicePowerWorker( pDeviceObject,
(PVOID)(ULONG_PTR)NewPowerState.DeviceState );
}
} else {
// warn everyone we're about to enter a deeper D-state
PoSetPowerState( pDeviceObject,
DevicePowerState,
NewPowerState );
// moving to a lower state, notify the subdevices
PowerNotifySubdevices( pDeviceContext, NewPowerState );
// keep track of suspends for debugging only
pDeviceContext->SuspendCount++;
// change the driver state if it has a registered POWER interface
if( pDeviceContext->pAdapterPower )
{
// notify the adapter
pDeviceContext->pAdapterPower->PowerChangeState( NewPowerState );
}
// keep track of new state
pDeviceContext->CurrentDeviceState = NewPowerState.DeviceState;
ReleaseDevice(pDeviceContext);
}
// this irp is non-failable
ntStatus = STATUS_SUCCESS;
break;
default:
ASSERT(!"Called with unknown PM IRP ");
break;
}
} else {
//
// We're already there...
//
ntStatus = STATUS_SUCCESS;
ASSERT(!MovingToALighterState);
}
// set the return status
pIrp->IoStatus.Status = ntStatus;
// if not moving to a higher state, forward to the PDO.
if( !MovingToALighterState )
{
ForwardIrpSynchronous( pDeviceContext, pIrp );
}
// start the next power irp
PoStartNextPowerIrp( pIrp );
// complete this irp
CompleteIrp( pDeviceContext, pIrp, ntStatus );
return ntStatus;
}
/*****************************************************************************
* UpdateActivePinCount()
*****************************************************************************
*
*/
NTSTATUS
UpdateActivePinCount
(
IN PDEVICE_CONTEXT DeviceContext,
IN BOOL Increment
)
{
PAGED_CODE();
ASSERT(DeviceContext);
ULONG ActivePinCount;
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOL DoSystemStateRegistration;
//
// PoRegisterSystemState and PoUnregisterSystemState are not available on WDM 1.0 (Win98 and Win98SE)
DoSystemStateRegistration = IoIsWdmVersionAvailable( 0x01, 0x10 );
// adjust the active pin count
if( Increment )
{
ActivePinCount = InterlockedIncrement( PLONG(&DeviceContext->ActivePinCount) );
//#if COMPILED_FOR_WDM110
if ( 1 == ActivePinCount )
{
// register the system state as busy
DeviceContext->SystemStateHandle = PoRegisterSystemState( DeviceContext->SystemStateHandle,
ES_SYSTEM_REQUIRED | ES_CONTINUOUS );
}
//#endif // COMPILED_FOR_WDM110
} else
{
ActivePinCount = InterlockedDecrement( PLONG(&DeviceContext->ActivePinCount) );
//#if COMPILED_FOR_WDM110
if( 0 == ActivePinCount )
{
PoUnregisterSystemState( DeviceContext->SystemStateHandle );
DeviceContext->SystemStateHandle = NULL;
}
//#endif // COMPILED_FOR_WDM110
}
_DbgPrintF(DEBUGLVL_VERBOSE,("UpdateActivePinCount (%d)",ActivePinCount));
// _DbgPrintF(DEBUGLVL_POWER,("UpdateActivePinCount (%d)",ActivePinCount));
return ntStatus;
}
/*****************************************************************************
* GetIdleInfoFromRegistry()
*****************************************************************************
*
*/
NTSTATUS
GetIdleInfoFromRegistry
(
IN PDEVICE_CONTEXT DeviceContext,
OUT PULONG ConservationIdleTime,
OUT PULONG PerformanceIdleTime,
OUT PDEVICE_POWER_STATE IdleDeviceState
)
{
PAGED_CODE();
ASSERT(DeviceContext);
ASSERT(ConservationIdleTime);
ASSERT(PerformanceIdleTime);
ASSERT(IdleDeviceState);
NTSTATUS ntStatus;
HANDLE DriverRegistryKey;
HANDLE PowerSettingsKey;
// store default values in return parms
*ConservationIdleTime = DEFAULT_CONSERVATION_IDLE_TIME;
*PerformanceIdleTime = DEFAULT_PERFORMANCE_IDLE_TIME;
*IdleDeviceState = DEFAULT_IDLE_DEVICE_POWER_STATE;
// open the driver registry key
ntStatus = IoOpenDeviceRegistryKey( DeviceContext->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
KEY_READ,
&DriverRegistryKey );
if(NT_SUCCESS(ntStatus))
{
OBJECT_ATTRIBUTES PowerSettingsAttributes;
UNICODE_STRING PowerSettingsKeyName;
// init the power settings key name
RtlInitUnicodeString( &PowerSettingsKeyName, L"PowerSettings" );
// init the power settings key object attributes
InitializeObjectAttributes( &PowerSettingsAttributes,
&PowerSettingsKeyName,
OBJ_CASE_INSENSITIVE,
DriverRegistryKey,
NULL );
// open the power settings key
ntStatus = ZwOpenKey( &PowerSettingsKey,
KEY_READ,
&PowerSettingsAttributes );
if(NT_SUCCESS(ntStatus))
{
UNICODE_STRING ConservationKey,PerformanceKey,IdleStateKey;
ULONG BytesReturned;
// init the key names
RtlInitUnicodeString( &ConservationKey, L"ConservationIdleTime" );
RtlInitUnicodeString( &PerformanceKey, L"PerformanceIdleTime" );
RtlInitUnicodeString( &IdleStateKey, L"IdlePowerState" );
// allocate a buffer to hold the query
PVOID KeyData = ExAllocatePoolWithTag(PagedPool,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
'dKcP' ); // 'PcKd'
if( NULL != KeyData )
{
// get the conservation idle time
ntStatus = ZwQueryValueKey( PowerSettingsKey,
&ConservationKey,
KeyValuePartialInformation,
KeyData,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
&BytesReturned );
if(NT_SUCCESS(ntStatus))
{
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
if(PartialInfo->DataLength == sizeof(DWORD))
{
// set the return value
*ConservationIdleTime = *(PDWORD(PartialInfo->Data));
}
}
// get the performance idle time
ntStatus = ZwQueryValueKey( PowerSettingsKey,
&PerformanceKey,
KeyValuePartialInformation,
KeyData,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
&BytesReturned );
if(NT_SUCCESS(ntStatus))
{
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
if(PartialInfo->DataLength == sizeof(DWORD))
{
// set the return value
*PerformanceIdleTime = *(PDWORD(PartialInfo->Data));
}
}
// get the device idle state
ntStatus = ZwQueryValueKey( PowerSettingsKey,
&IdleStateKey,
KeyValuePartialInformation,
KeyData,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
&BytesReturned );
if(NT_SUCCESS(ntStatus))
{
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
if(PartialInfo->DataLength == sizeof(DWORD))
{
// determine the return value
switch( *(PDWORD(PartialInfo->Data)) )
{
case 3:
*IdleDeviceState = PowerDeviceD3;
break;
case 2:
*IdleDeviceState = PowerDeviceD2;
break;
case 1:
*IdleDeviceState = PowerDeviceD1;
break;
default:
*IdleDeviceState = PowerDeviceD0;
break;
}
}
}
// free the key info buffer
ExFreePool( KeyData );
}
// close the power settings key
ZwClose( PowerSettingsKey );
}
// close the driver registry key
ZwClose( DriverRegistryKey );
}
// always succeed since we return either the registry value(s) or the defaults
return STATUS_SUCCESS;
}
/*****************************************************************************
* PcRequestNewPowerState()
*****************************************************************************
* This routine is used to request a new power state for the device. It is
* normally used internally by portcls but is also exported to adapters so
* that the adapters can also request power state changes.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRequestNewPowerState
(
IN PDEVICE_OBJECT pDeviceObject,
IN DEVICE_POWER_STATE RequestedNewState
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
_DbgPrintF(DEBUGLVL_POWER,("PcRequestNewPowerState"));
//
// Validate Parameters.
//
if (NULL == pDeviceObject)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRequestNewPowerState : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT(pDeviceContext);
NTSTATUS ntStatus = STATUS_SUCCESS;
//
// Validate DeviceContext.
//
if (NULL == pDeviceContext)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRequestNewPowerState : Invalid DeviceContext"));
return STATUS_INVALID_PARAMETER;
}
// check if this is actually a state change
if( RequestedNewState != pDeviceContext->CurrentDeviceState )
{
POWER_STATE newPowerState;
POWER_IRP_CONTEXT PowerIrpContext;
KEVENT SyncEvent;
// prepare the requested state
newPowerState.DeviceState = RequestedNewState;
// setup the sync event and the completion routine context
KeInitializeEvent( &SyncEvent,
SynchronizationEvent,
FALSE );
PowerIrpContext.PowerSyncEvent = &SyncEvent;
#if DBG
PowerIrpContext.Status = STATUS_PENDING;
#endif // DBG
PowerIrpContext.PendingSystemPowerIrp = NULL;
PowerIrpContext.DeviceContext = NULL;
// Set the new power state
ntStatus = PoRequestPowerIrp( pDeviceContext->PhysicalDeviceObject,
IRP_MN_SET_POWER,
newPowerState,
PowerIrpCompletionRoutine,
&PowerIrpContext,
NULL );
// Did this get allocated and sent??
//
if( NT_SUCCESS(ntStatus) )
{
// Wait for the completion event
KeWaitForSingleObject( &SyncEvent,
Suspended,
KernelMode,
FALSE,
NULL );
ntStatus = PowerIrpContext.Status;
}
}
return ntStatus;
}
/*****************************************************************************
* CheckCurrentPowerState()
*****************************************************************************
* This routine resets the idle timer and checks to see if the device is
* current in the D0 (full power) state. If it isn't, it requests that the
* device power up to D0.
*/
NTSTATUS
CheckCurrentPowerState
(
IN PDEVICE_OBJECT pDeviceObject
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
NTSTATUS ntStatus = STATUS_SUCCESS;
// reset the idle timer
if( pDeviceContext->IdleTimer )
{
PoSetDeviceBusy( pDeviceContext->IdleTimer );
}
// check if we're in PowerDeviceD0
if( pDeviceContext->CurrentDeviceState != PowerDeviceD0 )
{
ntStatus = STATUS_DEVICE_NOT_READY;
}
return ntStatus;
}
#pragma code_seg()