📄 drvpower.c
字号:
#include "zjHMCFUsb.h"
/************************************************************************************************
* Function Type : Global
* Parameter : fdo - Pointer to the device object for the class device. ( Physical Device Object )
* MinorFunction - Specifies the minor function code in the power IRP.
* PowerState - Specifies the device power state passed to PoRequestPowerIrp.
* Context - Driver defined context, in this case our FDO ( functional device object )
* IoStatus - Points to the IoStatus block in the completed IRP.
* Return Value : The function value is the final status from the operation.
* Description : 当驱动完成一个自己创建的IRP时就调用这个例程。
* 这个例程在调用hwSelfSuspendOrActivate()时产生
* 电源在第一个管道打开时打开,最后一个管道关闭时关闭。
* 在电源开启的情况下,我们将设置设备扩展中的一个事件
* 为有信号来表示电源IRP处理完成,因此电源请求可以作为
* 同步调用
* 我们必须知道设备电源是开启的在第一个管道打开的时候
* 比如,在电源关闭的时候我们不会设置一个事件,因为
* 不会有任何调用者会在电源关闭的时候等待irp的完成
*************************************************************************************************/
NTSTATUS hwPoSelfRequestCompletion
(
IN PDEVICE_OBJECT fdo,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PDEVICE_OBJECT deviceObject = Context;
PDEVICE_EXTENSION dx = deviceObject->DeviceExtension;
NTSTATUS ntStatus = IoStatus->Status;
// 确保当前不是正在处理系统产生的电源IRP
hwASSERT( NULL == dx->PowerIrp );
// 我们仅仅在电源打开的情况下才触发事件dx->SelfRequestedPowerIrpEvent
// 在电源关闭的情况下不会有调用者在等待这个处理完成
if ( (ULONG) PowerState.DeviceState < dx->PowerDownLevel )
{
// Trigger Self-requested power irp completed event;
// The caller is waiting for completion
KeSetEvent(&dx->SelfRequestedPowerIrpEvent, 1, FALSE);
}
hwDecrementIoCount(deviceObject);
hwDbgPrint("hwPoSelfRequestCompletion() ntStatus = 0x%x\n", ntStatus );
return ntStatus;
}
/************************************************************************************************
* Function Type : private
* Parameter : fdo - Pointer to the device object
* PowerState - power state requested, e.g PowerDeviceD0.
* Return Value : The function value is the final status from the operation.
* Description : This routine is called by hwSelfSuspendOrActivate() to
* actually make the system request for a power down/up to PowerState.
* It first checks to see if we are already in Powerstate and immediately
* returns SUCCESS with no further processing if so
* 通过系统请求改变电源状态
*************************************************************************************************/
NTSTATUS hwSelfRequestPowerIrp
(
IN PDEVICE_OBJECT fdo,
IN POWER_STATE PowerState
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION dx;
dx = fdo->DeviceExtension;
// This should have been reset in completion routine
hwASSERT( !dx->SelfPowerIrp );
if ( dx->CurrentDevicePowerState == PowerState.DeviceState )
return STATUS_SUCCESS; // nothing to do
hwDbgPrint(" -->>>>>> hwSelfRequestPowerIrp() will request power irp to state %s\n",
hwStringForDevState( PowerState.DeviceState ));
hwIncrementIoCount(fdo);
// flag we're handling a self-generated power irp
dx->SelfPowerIrp = TRUE;
// allocates a power IRP and sends it to the top driver in the device stack for the specified device
ntStatus = PoRequestPowerIrp(dx->pdo, // Points to the target device object for the IRP
IRP_MN_SET_POWER,
PowerState, // Specifies a power state to pass in the IRP
hwPoSelfRequestCompletion,
fdo, // Context
NULL);
if ( ntStatus == STATUS_PENDING )
{
// 这正是我们想要的返回值
// 只有在电源开启的情况下才需要等待处理完成的事件
if ( (ULONG) PowerState.DeviceState < dx->PowerDownLevel )
{
NTSTATUS waitStatus;
waitStatus = KeWaitForSingleObject(
&dx->SelfRequestedPowerIrpEvent,
Suspended,
KernelMode,
FALSE,
NULL);
}
ntStatus = STATUS_SUCCESS;
dx->SelfPowerIrp = FALSE;
hwDbgPrint("Request change power state success , PowerState %s\n",
hwStringForDevState(PowerState.DeviceState));
}
else
{
// The return status was not STATUS_PENDING; any other codes must be considered in error here;
// i.e., it is not possible to get a STATUS_SUCCESS or any other non-error return from this call;
hwDbgPrint("Request change power state FAILED , state %s , status = 0x%x\n",
hwStringForDevState( PowerState.DeviceState ),ntStatus);
}
return ntStatus;
}
/************************************************************************************************
* Function Type : Global
* Parameter : fdo - Pointer to the device object
* fSuspend - TRUE to Suspend, FALSE to acivate.
* Return Value : SUCCESS - If the operation is not attemtped
If the operation is attemtped, the value is the final status from the operation.
* Description : Called on zjHMCFUsb_AddDevice() to power down until needed (i.e., till a pipe is actually opened).
* Called on zjHMCFUsb_Create() to power up device to D0 before opening 1st pipe.
* Called on zjHMCFUsb_Close() to power down device if this is the last pipe.
* 挂起或激活设备,实际上是改变电源状态
*************************************************************************************************/
NTSTATUS hwSelfSuspendOrActivate
(
IN PDEVICE_OBJECT fdo,
IN BOOLEAN fSuspend
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
POWER_STATE PowerState;
PDEVICE_EXTENSION dx;
dx = fdo->DeviceExtension;
hwDbgPrint(" -->>>>>> hwSelfSuspendOrActivate(fdo=0x%x,fSuspend = %s\n",fdo, fSuspend?"TRUE":"FALSE");
if ( !hwCanAcceptIoRequests( fdo ) )
{
ntStatus = STATUS_DELETE_PENDING;
hwDbgPrint("ABORTING hwSelfSuspendOrActivate()\n");
return ntStatus;
}
// 如果系统产生的任何设备PNP IRPs正在处理,我们不做任何事情,直接返回
if ( NULL != dx->PowerIrp )
{
hwDbgPrint("refusing on pending dx->PowerIrp 0x%I\n", dx->PowerIrp);
goto done;
}
// 如果自己产生的任何设备PNP IRPs正在处理,我们不做任何事情,直接返回
if ( dx->SelfPowerIrp )
{
hwDbgPrint("refusing on pending dx->SelfPowerIrp\n");
goto done;
}
// 如果任何管道被打开了,我们的设备不能自动挂起
if ( fSuspend && ( 0 != dx->OpenPipeCount ) )
{
hwDbgPrint("refusing to self-suspend on OpenPipeCount %d\n", dx->OpenPipeCount);
goto done;
}
// 如果没有管道被打开,我们的设备不能自动激活
if ( !fSuspend && ( 0 == dx->OpenPipeCount ) )
{
hwDbgPrint(" refusing to self-activate, no pipes open\n");
goto done;
}
// dont do anything if registry CurrentControlSet\Services\zjHMCFUsb\Parameters\PowerDownLevel
// has been set to zero, PowerDeviceD0 ( 1 ), or a bogus high value
if ( ( dx->PowerDownLevel == PowerDeviceD0 ) ||
( dx->PowerDownLevel == PowerDeviceUnspecified) ||
( dx->PowerDownLevel >= PowerDeviceMaximum ) )
{
hwDbgPrint("refusing on dx->PowerDownLevel == %d\n", dx->PowerDownLevel);
goto done;
}
if ( fSuspend )
PowerState.DeviceState = dx->PowerDownLevel;
else
PowerState.DeviceState = PowerDeviceD0; // power up all the way; we're probably just about to do some IO
ntStatus = hwSelfRequestPowerIrp( fdo, PowerState );
hwDbgPrint("hwSelfSuspendOrActivate() status 0x%x on setting dev state %s\n",
ntStatus, hwStringForDevState(PowerState.DeviceState ));
done:
hwDbgPrint ( "hwSelfSuspendOrActivate() -->>>>>>\n");
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - Pointer to the device object for the class device.
* Note that we must get our own device object from the Context
* Context - Driver defined context, in this case our own functional device object ( FDO )
* Return Value : The function value is the final status from the operation.
* Description : This is the completion routine set in a call to PoRequestPowerIrp()
* that was made in zjHMCFUsb_PowerIrp() in response to receiving
* an IRP_MN_SET_POWER of type 'SystemPowerState' when the device was
* not in a compatible device power state. In this case, a pointer to
* the IRP_MN_SET_POWER Irp is saved into the FDO device extension
* (dx->PowerIrp), and then a call must be
* made to PoRequestPowerIrp() to put the device into a proper power state,
* and this routine is set as the completion routine.
* We decrement our pending io count and pass the saved IRP_MN_SET_POWER Irp
* on to the next driver
*************************************************************************************************/
NTSTATUS zjHMCFUsb_PoRequestCompletion
(
IN PDEVICE_OBJECT fdo,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP irp;
PDEVICE_EXTENSION dx;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS ntStatus;
hwDbgPrint(" -->>>>>> zjHMCFUsb_PoRequestCompletion()\n");
PrintCurIrql();
dx = deviceObject->DeviceExtension;
// Get the Irp we saved for later processing in zjHMCFUsb_PowerIrp()
// when we decided to request the Power Irp that this routine
// is the completion routine for.
irp = dx->PowerIrp;
// We will return the status set by the PDO for the power request we're completing
ntStatus = IoStatus->Status;
// we should not be in the midst of handling a self-generated power irp
hwASSERT( !dx->SelfPowerIrp );
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(irp);
//------------------------------------------------------------------
// Calling PoStartNextPowerIrp() indicates that the driver is finished
// with the previous power IRP, if any, and is ready to handle the next power IRP.
// It must be called for every power IRP.Although power IRPs are completed only once,
// typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
// for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
// stack location points to the current driver. Therefore, this routine must be called
// before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.
//------------------------------------------------------------------
PoStartNextPowerIrp(irp);
//------------------------------------------------------------------
// PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
// When passing a power IRP down to a lower-level driver, the caller should use
// IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
// the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
// if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
// if no completion routine is needed.
//------------------------------------------------------------------
PoCallDriver(dx->LowerDeviceObject,irp);
hwDecrementIoCount(deviceObject);
hwDbgPrint("zjHMCFUsb_PoRequestCompletion() Exit IRP_MN_SET_POWER\n");
dx->PowerIrp = NULL;
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Irp - Irp completed.
* Context - Driver defined context.
* Return Value : The function value is the final status from the operation.
* Description : This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
* has been received by zjHMCFUsb_PowerIrp(), and that routine has determined
* 1) the request is for full powerup ( to PowerDeviceD0 ), and
* 2) We are not already in that state
* A call is then made to PoRequestPowerIrp() with this routine set as the completion routine.
*************************************************************************************************/
NTSTATUS zjHMCFUsb_PowerIrp_Complete(IN PDEVICE_OBJECT NullDeviceObject,IN PIRP Irp,IN PVOID Context)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION dx;
hwDbgPrint(" -->>>>>> zjHMCFUsb_PowerIrp_Complete\n");
PrintCurIrql();
deviceObject = (PDEVICE_OBJECT) Context;
dx = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -