drvpower.c
来自「ddk编写的usb驱动源代码」· C语言 代码 · 共 630 行 · 第 1/2 页
C
630 行
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
hwASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
hwASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
hwASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
hwASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
dx->CurrentDevicePowerState = PowerDeviceD0;
Irp->IoStatus.Status = ntStatus;
hwDecrementIoCount(deviceObject);
hwDbgPrint(" <<<<< zjHMCFUsb_PowerIrp_Complete Exit IRP_MN_SET_POWER D0 complete\n");
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - Pointer to the device object for the class device.
* DeviceState - Device specific power state to set the device in to.
* Context - Driver defined context.
* Return Value : For requests to DeviceState D0 ( fully on ), returns TRUE to signal caller
* that we must set a completion routine and finish there.
* Description : This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
* has been received by zjHMCFUsb_PowerIrp().
*************************************************************************************************/
BOOLEAN zjHMCFUsb_SetDevicePowerState
(
IN PDEVICE_OBJECT fdo,
IN DEVICE_POWER_STATE DeviceState
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION dx;
BOOLEAN fRes = FALSE;
dx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
hwDbgPrint("zjHMCFUsb_SetDevicePowerState(fdo=0x%x,DeviceState=0x%x)\n",fdo,DeviceState);
PrintCurIrql();
switch (DeviceState)
{
case PowerDeviceD3:
//------------------------------------------------------------------
// Device will be going OFF,
// TODO: add any needed device-dependent code to save state here.
// ( We have nothing to do in this sample )
//------------------------------------------------------------------
hwDbgPrint("zjHMCFUsb_SetDevicePowerState() PowerDeviceD3 (OFF)\n");
dx->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD1:
case PowerDeviceD2:
// power states D1,D2 translate to USB suspend
hwDbgPrint("zjHMCFUsb_SetDevicePowerState() %s\n",
hwStringForDevState(DeviceState) );
dx->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD0:
hwDbgPrint("zjHMCFUsb_SetDevicePowerState() PowerDeviceD0 (ON)\n");
// We'll need to finish the rest in the completion routine;
// signal caller we're going to D0 and will need to set a completion routine
fRes = TRUE;
// Caller will pass on to PDO ( Physical Device object )
break;
default:
hwDbgPrint(" Bogus DeviceState = %x\n", DeviceState);
}
return fRes;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* IRP - pointer to an I/O Request Packet
* Return Value : NT status code
* Description : This is our FDO's dispatch table function for IRP_MJ_POWER.
* It processes the Power IRPs sent to the PDO for this device.
* For every power IRP, drivers must call PoStartNextPowerIrp and use PoCallDriver
* to pass the IRP all the way down the driver stack to the underlying PDO.
*************************************************************************************************/
NTSTATUS zjHMCFUsb_PowerIrp(IN PDEVICE_OBJECT fdo, IN PIRP Irp )
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION dx;
BOOLEAN fGoingToD0 = FALSE;
POWER_STATE sysPowerState, desiredDevicePowerState;
KEVENT event;
hwDbgPrint("zjHMCFUsb_PowerIrp() IRP_MJ_POWER\n");
PrintCurIrql();
dx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp);
hwIncrementIoCount(fdo);
switch (irpStack->MinorFunction)
{
case IRP_MN_WAIT_WAKE: //等待唤醒
hwDbgPrint("zjHMCFUsb_PowerIrp() Enter IRP_MN_WAIT_WAKE\n");
//------------------------------------------------------------------
// 驱动发送IRP_MN_WAIT_WAKE表明系统将等待它的设备
// 发送唤醒事件
// 驱动发送这个事件有以下两个原因:
// 1) 允许设备唤醒系统
// 2) 唤醒一个已经进入休眠的设备
// 当一个唤醒事件发生时,驱动将完成这个IRP并
// 返回STATUS_SUCCESS,如果设备是休眠了,驱动必须
// 在完成IRP之前唤醒设备,在完成例程里,驱动将
// 调用PoRequestPowerIrp来发送PowerDeviceD0请求,当设备
// 电源是开启的,驱动就能处理IRP_MN_WAIT_WAKE请求
//------------------------------------------------------------------
// dx->DeviceCapabilities.DeviceWake 指定了能被唤醒的最低电源状态
dx->PowerDownLevel = dx->DeviceCapabilities.DeviceWake;
if(
( PowerDeviceD0 == dx->CurrentDevicePowerState ) //设备已经是唤醒的
||
( dx->DeviceCapabilities.DeviceWake > dx->CurrentDevicePowerState ) //设备电源状态低于能被唤醒的电源状态,此设备不能被唤醒
)
{
// 如果驱动处理失败了这个IRP,那么将立即完成这个IRP的处理,
// 并不将这个IRP 传给下层驱动
ntStatus = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp,IO_NO_INCREMENT );
hwDbgPrint(" <<<<< zjHMCFUsb_PowerIrp(), ntStatus STATUS_INVALID_DEVICE_STATE\n" );
hwDecrementIoCount(fdo);
return ntStatus;
}
// 标志我们允许唤醒
dx->EnabledForWakeup = TRUE;
// 初始化一个事件,当FDO处理完IRP时将触发这个事件
KeInitializeEvent(&event, NotificationEvent, FALSE);
//如果没失败,将这个Irp交给下层驱动做深层的处理
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine( Irp,
hwIRPCompletionRoutine,
&event, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation
//informs the Power Manager that the driver is ready to handle the next power IRP
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(dx->LowerDeviceObject,Irp);
if (ntStatus == STATUS_PENDING)
{
NTSTATUS waitStatus = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
hwDbgPrint("zjHMCFUsb_PowerIrp() done waiting for PDO to finish IRP_MN_WAIT_WAKE\n");
}
// now tell the device to actually wake up
hwSelfSuspendOrActivate( fdo, FALSE );
// 标志我们已经处理了唤醒IRP
dx->EnabledForWakeup = FALSE;
hwDecrementIoCount(fdo);
hwDbgPrint("zjHMCFUsb_PowerIrp() Exit IRP_MN_WAIT_WAKE\n");
break;
case IRP_MN_SET_POWER: //设置电源
//系统电源策略管理器发送这个IRP来设置系统电源状态
hwDbgPrint("zjHMCFUsb_PowerIrp() Enter IRP_MN_SET_POWER\n");
// Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device
// has entered the requested state. Drivers cannot fail this IRP.
switch (irpStack->Parameters.Power.Type)
{
case SystemPowerState:
// Get input system power state
sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;
hwDbgPrint("zjHMCFUsb_PowerIrp() Set Power, type SystemPowerState = 0x%x\n",Irp);
// 如果系统在工作状态,我们总是设置设备电源状态为D0
if ( sysPowerState.SystemState == PowerSystemWorking)
{
desiredDevicePowerState.DeviceState = PowerDeviceD0;
hwDbgPrint("zjHMCFUsb_PowerIrp() PowerSystemWorking, will set D0, not use state map\n");
}
else
{
// set to corresponding system state if IRP_MN_WAIT_WAKE pending
if ( dx->EnabledForWakeup ) // got a WAIT_WAKE IRP pending?
{
// Find the device power state equivalent to the given system state.
// We get this info from the DEVICE_CAPABILITIES struct in our device
// extension (initialized in zjHMCFUsb_AddDevice() )
desiredDevicePowerState.DeviceState = dx->DeviceCapabilities.DeviceState[ sysPowerState.SystemState ];
hwDbgPrint("zjHMCFUsb_PowerIrp() IRP_MN_WAIT_WAKE pending, will use state map\n");
}
else
{
// if no wait pending and the system's not in working state, just turn off
desiredDevicePowerState.DeviceState = PowerDeviceD3;
hwDbgPrint("zjHMCFUsb_PowerIrp() Not EnabledForWakeup and the system's not in working state,\n settting PowerDeviceD3 (off )\n");
}
}
// We've determined the desired device state; are we already in this state?
hwDbgPrint("zjHMCFUsb_PowerIrp() Set Power, desiredDevicePowerState = %s\n",
hwStringForDevState( desiredDevicePowerState.DeviceState ));
if (desiredDevicePowerState.DeviceState != dx->CurrentDevicePowerState)
{
// hwIncrementIoCount(fdo);
// No, request that we be put into this state
// by requesting a new Power Irp from the Pnp manager
dx->PowerIrp = Irp;
ntStatus = PoRequestPowerIrp(dx->pdo,
IRP_MN_SET_POWER,
desiredDevicePowerState,
// completion routine will pass the Irp down to the PDO
zjHMCFUsb_PoRequestCompletion,
fdo,
NULL);
}
else
{
// Yes, just pass it on to PDO (Physical Device Object)
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(dx->LowerDeviceObject,Irp);
hwDecrementIoCount(fdo);
hwDbgPrint("zjHMCFUsb_PowerIrp() Exit IRP_MN_SET_POWER\n");
}
break;
case DevicePowerState:
hwDbgPrint("zjHMCFUsb_PowerIrp() Set Power, type DevicePowerState = 0x%x\n",Irp);
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets dx->CurrentDevicePowerState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
// For requests to DeviceState D0 ( fully on ), sets fGoingToD0 flag TRUE
// to flag that we must set a completion routine and update
// dx->CurrentDevicePowerState there.
// In the case of powering up to fully on, we really want to make sure
// the process is completed before updating our CurrentDevicePowerState,
// so no IO will be attempted or accepted before we're really ready.
fGoingToD0 = zjHMCFUsb_SetDevicePowerState(fdo,
irpStack->Parameters.Power.State.DeviceState); // returns TRUE for D0
IoCopyCurrentIrpStackLocationToNext(Irp);
if (fGoingToD0)
{
hwDbgPrint("zjHMCFUsb_PowerIrp() Set PowerIrp Completion Routine, fGoingToD0 =%d\n", fGoingToD0);
IoSetCompletionRoutine(Irp,
zjHMCFUsb_PowerIrp_Complete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
fdo,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
}
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(dx->LowerDeviceObject,Irp);
if ( !fGoingToD0 ) // completion routine will decrement
hwDecrementIoCount(fdo);
hwDbgPrint("zjHMCFUsb_PowerIrp() Exit IRP_MN_SET_POWER\n");
break;
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
// A power policy manager sends this IRP to determine whether it can change
// the system or device power state, typically to go to sleep.
hwDbgPrint("zjHMCFUsb_PowerIrp() IRP_MN_QUERY_POWER\n");
// We do nothing special here, just let the PDO handle it
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(dx->LowerDeviceObject,Irp);
hwDecrementIoCount(fdo);
break;
default:
hwDbgPrint("zjHMCFUsb_PowerIrp() UNKNOWN POWER MESSAGE (%x)\n", irpStack->MinorFunction);
// All unhandled power messages are passed on to the PDO
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(dx->LowerDeviceObject, Irp);
hwDecrementIoCount(fdo);
} /* irpStack->MinorFunction */
hwDbgPrint(" <<<<< zjHMCFUsb_PowerIrp() ntStatus = 0x%x\n", ntStatus );
return ntStatus;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?