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 + -
显示快捷键?