📄 power.c
字号:
);
}
/******************************************************************************
*
* Function : OnFinishPowerUp
*
* Description: Completion routine for IRP_MN_SET_POWER
*
******************************************************************************/
NTSTATUS
OnFinishPowerUp(
PDEVICE_OBJECT fdo,
PIRP pIrp,
PVOID junk
)
{
NTSTATUS status;
POWER_STATE state;
POWER_STATE_TYPE type;
PIO_STACK_LOCATION stack;
DEVICE_POWER_STATE devstate;
DebugPrintf(("in OnFinishPowerUp\n"));
if (pIrp->PendingReturned)
{
// Lower-level pended this IRP
IoMarkIrpPending(
pIrp
);
}
status = pIrp->IoStatus.Status;
if (!NT_SUCCESS(status))
{
DebugPrintf(("OnFinishPowerUp: IRP failed\n"));
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;
}
/******************************************************************************
*
* Function : OnPowerRequestComplete
*
* Description: Completion routine for SendSelfSetPowerRequest
*
******************************************************************************/
VOID
OnPowerRequestComplete(
PDEVICE_OBJECT DeviceObject,
U8 MinorFunction,
POWER_STATE PowerState,
PVOID context,
PIO_STATUS_BLOCK ioStatus
)
{
DebugPrintf(("in OnPowerRequestComplete\n"));
// Set event
if ((PKEVENT)context != NULL)
{
KeSetEvent(
(PKEVENT)context,
1,
FALSE
);
}
}
/******************************************************************************
*
* Function : SendDeviceSetPower
*
* Description: Send ourselves an IRP_MN_SET_POWER request
*
******************************************************************************/
NTSTATUS
SendDeviceSetPower(
PDEVICE_OBJECT fdo,
DEVICE_POWER_STATE state,
U32 context
)
{
PIRP pIrp;
KEVENT event;
NTSTATUS status;
PIO_STACK_LOCATION stack;
DebugPrintf(("in SendDeviceSetPower\n"));
// Skip request if we are already at the desired Power level
if (state == ((DEVICE_EXTENSION *)fdo->DeviceExtension)->PowerState)
return STATUS_SUCCESS;
pIrp =
IoAllocateIrp(
fdo->StackSize,
FALSE
);
if (pIrp == NULL)
{
DebugPrintf(("ERROR - Unable to allocate IRP for Power request\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// IRP status must be initialized
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
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(
&event,
Executive,
KernelMode,
FALSE,
NULL
);
status = pIrp->IoStatus.Status;
}
IoFreeIrp(
pIrp
);
return status;
}
/******************************************************************************
*
* Function : SetPowerState
*
* Description: Set the new power state
*
******************************************************************************/
VOID
SetPowerState(
PDEVICE_OBJECT fdo,
DEVICE_POWER_STATE state
)
{
POWER_INFO pPowerInfo;
pPowerInfo.pdx = fdo->DeviceExtension;
pPowerInfo.state = state;
EmpowerDevice(
&pPowerInfo
);
}
/******************************************************************************
*
* Function : EmpowerDevice
*
* Description: Empower device
*
******************************************************************************/
BOOLEAN
EmpowerDevice(
POWER_INFO *pPowerInfo
)
{
// If already in the requested state, do nothing
if (pPowerInfo->state == pPowerInfo->pdx->PowerState)
return TRUE;
DebugPrintf(("Putting device into state ==> "));
switch (pPowerInfo->state)
{
case D0Uninitialized:
DebugPrintf_NoInfo(("D0Uninitialized\n"));
break;
case D0:
DebugPrintf_NoInfo(("D0\n"));
break;
case D1:
DebugPrintf_NoInfo(("D1\n"));
break;
case D2:
DebugPrintf_NoInfo(("D2\n"));
break;
case D3Hot:
DebugPrintf_NoInfo(("D3Hot\n"));
break;
case D3Cold:
DebugPrintf_NoInfo(("D3Cold\n"));
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
PlxPciPowerLevelSet(
pPowerInfo->pdx,
pPowerInfo->state - PowerDeviceD0 + D0
);
// Record the new power state
pPowerInfo->pdx->PowerState = pPowerInfo->state;
return TRUE;
}
/******************************************************************************
*
* Function : SendSelfSetPowerRequest
*
* Description: Change the power level of the device. Note that this is not
* the way Microsoft recommends.
*
******************************************************************************/
NTSTATUS
SendSelfSetPowerRequest(
PDEVICE_OBJECT fdo,
DEVICE_POWER_STATE state
)
{
NTSTATUS status;
POWER_STATE power;
DEVICE_EXTENSION *pdx;
DebugPrintf(("in SendSelfSetPowerRequest\n"));
// Get the device extension
if (fdo->DeviceExtension == NULL)
{
DebugPrintf(("ERROR - NULL extension\n"));
return STATUS_NOT_SUPPORTED;
}
pdx = fdo->DeviceExtension;
// Compare new and old power states
if (state == pdx->PowerState)
return STATUS_SUCCESS;
// PoSetPowerState needs a POWER_STATE instead of a DEVICE_POWER_STATE
power.DeviceState = state;
if (state > pdx->PowerState)
{
// Removing power, process first
PoSetPowerState(
fdo,
DevicePowerState,
power
);
SetPowerState(
fdo,
state
);
}
/*
Normally, here we would create an IRP and send it down to the PCI bus
driver. However, this crashes Win98. So, we do not do it. Note that
the consequence of that is that the PCI bus driver does not know that
we are changing the power level of the device.
*/
if (state < pdx->PowerState)
{
// adding power, process request after
SetPowerState(
fdo,
state
);
PoSetPowerState(
fdo,
DevicePowerState,
power
);
}
return STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -