📄 power.cpp
字号:
/******************************************************************************
*
* File Name:
*
* Power.cpp
*
* Description:
*
* Power Management functions
*
* Revision History:
*
* 03-3-02 : PCI9052Demo v1.00
*
******************************************************************************/
#define INITGUID // initialize WDM1_GUID in this module
#include "PCI9052Demo.h"
#pragma code_seg("PAGE") // start PAGE section
/******************************************************************************
*
* Function : DispatchPower
*
* Description: Handles power requests
*
******************************************************************************/
NTSTATUS DispatchPower(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //DispatchPower
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
NTSTATUS status;
PIO_STACK_LOCATION pIrpStack;
if (!LockDevice(pdx))
return CompleteRequestInfo( pIrp, STATUS_DELETE_PENDING, 0);
DebugPrint("PCI9052Demo: Power Start.");
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
switch (pIrpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
DebugPrint("IRP_MN_SET_POWER.");
if (pIrpStack->Parameters.Power.Type == SystemPowerState)
{
DebugPrint("PCI9052Demo: SystemContext = 0x%x SystemPowerState = 0x%x.",
pIrpStack->Parameters.Power.SystemContext,
pIrpStack->Parameters.Power.State.SystemState);
}
else
{
DebugPrint("PCI9052Demo: SystemContext = 0x%x DevicePowerState = 0x%x.",
pIrpStack->Parameters.Power.SystemContext,
pIrpStack->Parameters.Power.State.DeviceState);
}
status = PowerSetPower(fdo,pIrp);
break;
case IRP_MN_QUERY_POWER:
DebugPrint("PCI9052Demo: IRP_MN_QUERY_POWER,SystemContext = 0x%x",pIrpStack->Parameters.Power.SystemContext);
status = PowerQueryPower(fdo,pIrp);
break;
case IRP_MN_WAIT_WAKE:
DebugPrint("IRP_MN_WAIT_WAKE.");
status = DefaultPowerHandler(fdo,pIrp);
break;
case IRP_MN_POWER_SEQUENCE:
DebugPrint("IRP_MN_POWER_SEQUENCE.");
status = DefaultPowerHandler(fdo,pIrp);
break;
default:
DebugPrint("Unsupported IRP_MN_Xxx (0x%x)\n", pIrpStack->MinorFunction);
status = DefaultPowerHandler(fdo,pIrp);
break;
}
UnlockDevice(pdx);
return status;
} //DispatchPower
/******************************************************************************
*
* Function : DefaultPowerHandler
*
* Description: Handle defaults power requests
*
******************************************************************************/
NTSTATUS DefaultPowerHandler(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //DefaultPowerHandler
PoStartNextPowerIrp(pIrp); // Must be done while we own the IRP
IoSkipCurrentIrpStackLocation(pIrp);
return PoCallDriver(
((DEVICE_EXTENSION *)fdo->DeviceExtension)->pLowerDeviceObject,pIrp);
} //DefaultPowerHandler
#pragma code_seg() // end PAGE section
/******************************************************************************
*
* Function : HandleSetPower
*
* Description: Handles IRP_MN_SET_POWER and IRP_MN_QUERY_POWER requests
*
******************************************************************************/
NTSTATUS PowerSetPower(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //HandleSetPower
ULONG context;
NTSTATUS status;
POWER_STATE state;
POWER_STATE_TYPE type;
PDEVICE_EXTENSION pdx;
PIO_STACK_LOCATION stack;
DEVICE_POWER_STATE devstate;
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
stack = IoGetCurrentIrpStackLocation(pIrp);
context = stack->Parameters.Power.SystemContext;
type = stack->Parameters.Power.Type;
state = stack->Parameters.Power.State;
/* If this IRP pertains to a system state, we want to put ourselves into
* a corresponding device state. The rule here is very simple: if the
* system is below SystemWorking, we must go to D3. If the system is
* in SystemWorking, we're allowed to pick our own state (so we pick
* D0). We can't just change our power state now, though: we must send
* ourselves a separate POWER IRP with the selected device state.
*/
if (type == SystemPowerState)
{
if (state.SystemState <= PowerSystemWorking)
devstate = PowerDeviceD0;
else
devstate = PowerDeviceD3;
}
else
{
devstate = state.DeviceState;
}
// If we're adding power, first pass the IRP down. Queue the
// requisite device IRP in the completion routine after the
// lower layers have restored power.
if (devstate < pdx->DevicePower)
{
// Adding more power
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,(PIO_COMPLETION_ROUTINE) OnFinishPowerUp,
NULL,TRUE,TRUE,TRUE);
return PoCallDriver(pdx->pLowerDeviceObject,pIrp);
}
else if (devstate > pdx->DevicePower)
{
/* If we're removing power, first do the device specific part.
* Then send the request down the stack. In the case of a system
* power request, send ourselves a device power IRP to power down first.
* In the case of a device power request, use PoSetPowerState to tell
* the Power Manager what we're about to do and then actually depower
* the hardware.
*/
// Removing power
if (type == SystemPowerState)
{ // Change in system state
status = SendDeviceSetPower(fdo,devstate,context);
if (!NT_SUCCESS(status))
{ // Couldn't set device power state
PoStartNextPowerIrp(pIrp);
return CompleteRequestInfo(pIrp,status,0);
}
}
else
{ // Change in device state
PoSetPowerState(fdo,type,state); // before we power down
SetPowerState(fdo,devstate);
}
// Pass request down
return DefaultPowerHandler(fdo,pIrp);
}
// Pass request down
return DefaultPowerHandler(fdo,pIrp);
} //HandleSetPower
/******************************************************************************
*
* Function : HandleQueryPower
*
* Description: Handle the IRP_MN_QUERY_POWER power IRP.
*
******************************************************************************/
NTSTATUS PowerQueryPower(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //HandleQueryPower
ULONG context;
POWER_STATE state;
POWER_STATE_TYPE type;
PDEVICE_EXTENSION pdx;
PIO_STACK_LOCATION stack;
DEVICE_POWER_STATE devstate;
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
stack = IoGetCurrentIrpStackLocation(pIrp);
context = stack->Parameters.Power.SystemContext;
type = stack->Parameters.Power.Type;
state = stack->Parameters.Power.State;
if (type == SystemPowerState)
{
if (state.SystemState <= PowerSystemWorking)
devstate = PowerDeviceD0;
else
devstate = PowerDeviceD3;
}
else
devstate = state.DeviceState;
if ((devstate - PowerDeviceD0 + PowerDeviceD0)!=PowerDeviceD0)
{
// Unsupported power level, we must fail the IRP
DebugPrint("PCI9052Demo: WARNING - PowerQueryPower() unsupported power level.");
return CompleteRequestInfo(pIrp,STATUS_NOT_IMPLEMENTED,0);
}
// Pass request down
return DefaultPowerHandler(fdo,pIrp);
} //HandleQueryPower
/******************************************************************************
*
* Function : OnFinishPowerUp
*
* Description: Completion routine for IRP_MN_SET_POWER
*
******************************************************************************/
NTSTATUS OnFinishPowerUp(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp,
IN PVOID junk)
{ //OnFinishPowerUp
NTSTATUS status;
POWER_STATE state;
POWER_STATE_TYPE type;
PIO_STACK_LOCATION stack;
DEVICE_POWER_STATE devstate;
DebugPrint("PCI9052Demo: in OnFinishPowerUp.");
if (pIrp->PendingReturned)
IoMarkIrpPending(pIrp); // lower-level pended this IRP
status = pIrp->IoStatus.Status;
if (!NT_SUCCESS(status))
{
DebugPrint("PCI9052Demo: OnFinishPowerUp: IRP failed.");
return status;
}
stack = IoGetCurrentIrpStackLocation(pIrp);
type = stack->Parameters.Power.Type;
state = stack->Parameters.Power.State;
/* If we just handled a request to restore power to the system, we
* want to send ourselves a device power IRP. But don't do it unless
* there's actually a request pending right now (we may immediately get
* another system IRP to go to a different sleep state than we were in
* to start with).
*/
if (type == SystemPowerState)
{
// Restoring power to the system
if (state.SystemState <= PowerSystemWorking)
devstate = PowerDeviceD0;
else
devstate = PowerDeviceD3;
status = SendDeviceSetPower(fdo,devstate,stack->Parameters.Power.SystemContext);
}
else
{
/* For a device re-power request, first restore power to the actual
* device and then call PoSetPowerState to tell the Power Manager we
* did so.
*/
// Restoring power to the device
SetPowerState(fdo,state.DeviceState);
PoSetPowerState(fdo,type,state); // after we power up
}
PoStartNextPowerIrp(pIrp);
return status;
} //OnFinishPowerUp
/******************************************************************************
*
* Function : OnPowerRequestComplete
*
* Description: Completion routine for SendSelfSetPowerRequest
*
******************************************************************************/
VOID OnPowerRequestComplete(IN PDEVICE_OBJECT DeviceObject,
IN unsigned char MinorFunction,
IN POWER_STATE PowerState,
IN PVOID context,
IN PIO_STATUS_BLOCK ioStatus)
{ //OnPowerRequestComplete
DebugPrint("PCI9052Demo: in OnPowerRequestComplete.");
// Set event
if ((PKEVENT)context != NULL)
{
KeSetEvent((PKEVENT)context,(KPRIORITY)1,FALSE);
}
} //OnPowerRequestComplete
/******************************************************************************
*
* Function : SendDeviceSetPower
*
* Description: Send ourselves an IRP_MN_SET_POWER request
*
******************************************************************************/
NTSTATUS SendDeviceSetPower(IN PDEVICE_OBJECT fdo,
IN DEVICE_POWER_STATE state,
IN ULONG context)
{ //SendDeviceSetPower
PIRP pIrp;
KEVENT event;
NTSTATUS status;
PIO_STACK_LOCATION stack;
DebugPrint("PCI9052Demo: in SendDeviceSetPower.");
// Skip request if we are already at the desired Power level
if (state == ((DEVICE_EXTENSION *)fdo->DeviceExtension)->DevicePower)
return STATUS_SUCCESS;
pIrp = IoAllocateIrp(fdo->StackSize,FALSE);
if (pIrp == NULL)
{
DebugPrint("PCI9052Demo: ERROR - Unable to allocate IRP for Power request.");
return STATUS_INSUFFICIENT_RESOURCES;
}
stack = IoGetNextIrpStackLocation(pIrp);
stack->MajorFunction = IRP_MJ_POWER;
stack->MinorFunction = IRP_MN_SET_POWER;
stack->Parameters.Power.SystemContext = context;
stack->Parameters.Power.Type = DevicePowerState;
stack->Parameters.Power.State.DeviceState = state;
KeInitializeEvent(&event,NotificationEvent,FALSE);
IoSetCompletionRoutine( pIrp,(PIO_COMPLETION_ROUTINE) OnRequestComplete,
(PVOID) &event,TRUE,TRUE,TRUE);
status = PoCallDriver(fdo,pIrp);
if (status == STATUS_PENDING)
{
// Wait for completion
KeWaitForSingleObject((PVOID)&event,Executive,KernelMode,FALSE,NULL);
status = pIrp->IoStatus.Status;
}
IoFreeIrp(pIrp);
return status;
} //SendDeviceSetPower
/******************************************************************************
*
* Function : SetPowerState
*
* Description: Set the new power state
*
******************************************************************************/
VOID SetPowerState(IN PDEVICE_OBJECT fdo,
IN DEVICE_POWER_STATE state)
{ //SetPowerState
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// If already in the requested state, do nothing
if (state == pdx->DevicePower)
return;
DebugPrint("PCI9052Demo: Putting device into state:");
switch (state)
{
case PowerDeviceD0:
DebugPrint("PowerDeviceD0.");
break;
case PowerDeviceD1:
DebugPrint("PowerDeviceD1.");
break;
case PowerDeviceD2:
DebugPrint("PowerDeviceD2.");
break;
case PowerDeviceD3:
DebugPrint("PowerDeviceD3.");
break;
}
// A real device would interpret the new state relative to the old state
// and save (or restore) some context information, send control information
// to the device, etc. This fake device just records the power state in the
// device extension.
// Set the new power state
// SetPowerLevel(pdx,state - PowerDeviceD0 + D0 );
// Record the new power state
pdx->DevicePower = state;
} //SetPowerState
#pragma code_seg() // end PAGE section
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -