⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 powerfdo.cpp

📁 Programming the Microsoft Windows driver model.2nd 随书光盘。内有很多作者送的实用工具和随书源码。WDM编程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	// will arrange to return STATUS_PENDING. Many of the other initial actions are entered

	// from a standard I/O completion routine and will need to return STATUS_MORE_PROCESSING_REQUIRED

	// to hold off final completion. Any action for MainIrpComplete that goes out through

	// CompleteMainIrp will end up returning ctx->status, which gets set in MainCompletionRoutine

	// to whatever's in the IRP -- this allows the IRP to complete normally. Any action off of

	// AsyncNotify should be changing "status" explicitly (and they do -- I checked).



#if DBG

	enum POWSTATE originalstate = ctx->state;

	enum POWSTATE nextstate = originalstate;

	#define SETSTATE(s) ctx->state = nextstate = s

#else

	#define SETSTATE(s) ctx->state = s

#endif



	while (TRUE)

		{						// handle this event

		switch (action)

			{					// perform next action



		///////////////////////////////////////////////////////////////////////

		// TriageNewIrp is the first action for a newly receive query or set IRP



		case TriageNewIrp:

			{					// TriageNewIrp

			ASSERT(stack->MajorFunction == IRP_MJ_POWER);

			ASSERT(stack->MinorFunction == IRP_MN_QUERY_POWER || stack->MinorFunction == IRP_MN_SET_POWER);

			ASSERT(ctx->state == InitialState);



			// We want the power dispatch routine to return STATUS_PENDING unless

			// something goes wrong right away. If we do return STATUS_PENDING, we

			// need to be sure we mark the IRP pending, 



			status = STATUS_PENDING;

			IoMarkIrpPending(Irp);



			// Acquire remove lock an extra time. We'll release it when we eventually

			// complete this IRP.



			IoAcquireRemoveLock(&pdx->RemoveLock, Irp);



			// For a system IRP, we'll request the corresponding device IRP. If system power is

			// being restored, we wait until the lower level drivers finish the system IRP. If

			// system power is being removed, we do it now and forward the system IRP when the

			// device IRP finishes.



			if (stack->Parameters.Power.Type == SystemPowerState)

				{				// system IRP

				if (stack->Parameters.Power.State.SystemState < pdx->syspower)

					{

					action = ForwardMainIrp;

					SETSTATE(SysPowerUpPending);

					}

				else

					{

					action = SelectDState;

					SETSTATE(SubPowerDownPending);

					}

				}				// system IRP



			// For a device set-power IRP, we have a variety of tasks to carry out. If device

			// power is being restored, we do those tasks when the lower level drivers complete

			// the IRP. If device power is being removed or staying the same, we do those tasks

			// before passing this IRP down. In either case, we ensure that the device isn't busy

			// with any substantive IRPs first.



			else

				{				// device IRP

				SETSTATE(QueueStallPending);



				action = QueueStallComplete;

				}				// device IRP



			continue;

			}					// TriageNewIrp

			

		///////////////////////////////////////////////////////////////////////

		// QueueStallComplete is the action for a MainIrpComplete event in th

		// QueueStallPending state. It's reached when StartNextPacket calls

		// GenericSaveRestoreComplete, which we specified as the current-irp

		// complete notification routine in our earlier call to StallRequestsAndNotify.

		// This action can also be reached directly from TriageNewIrp if the

		// device was idle to begin with or if we were already in a low-power

		// state (so that the queue should have been stalled)



		case QueueStallComplete:

			{					// QueueStallComplete

			if (stack->MinorFunction == IRP_MN_SET_POWER)

				{				// device set-power IRP

				if (stack->Parameters.Power.State.DeviceState < pdx->devpower)

					{

					action = ForwardMainIrp;

					SETSTATE(DevPowerUpPending);

					}

				else

					action = SaveContext;

				}				// device set-power IRP

			else

				{				// device query-power IRP

				if (stack->Parameters.Power.State.DeviceState < pdx->devpower)

					{

					action = ForwardMainIrp;

					SETSTATE(DevQueryUpPending);

					}

				else

					action = DevQueryDown;

				}				// device query-power IRP

			continue;

			}					// QueueStallComplete

			

		///////////////////////////////////////////////////////////////////////

		// ForwardMainIrp sends the current power IRP to the next driver in the

		// stack. We regain control in MainCompletionRoutine.



		case ForwardMainIrp:

			{					// ForwardMainIrp

			IoCopyCurrentIrpStackLocationToNext(Irp);

			IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) MainCompletionRoutine, (PVOID) ctx, TRUE, TRUE, TRUE);

			SafePoCallDriver(pdx->LowerDeviceObject, Irp); // avoid Win98 problem later on

			break;

			}					// ForwardMainIrp



		///////////////////////////////////////////////////////////////////////

		// SysPowerUpComplete is the action for a MainIrpComplete event in the

		// SysPowerUpPending state. If the IRP succeeded, request the corresponding

		// D-state IRP. When the subsidiary IRP finishes, we'll complete this

		// S-state IRP as well.

		//

		// The DDK doesn't explicitly say you need to send a D-state query when you

		// get an S-state query. It simplifies our own logic a good deal to do this,

		// however.



		case SysPowerUpComplete:

			{					// SysPowerUpComplete

			ASSERT(event == MainIrpComplete);



			if (!NT_SUCCESS(ctx->status))

				action = CompleteMainIrp;

			else

				{

				if (stack->MinorFunction == IRP_MN_SET_POWER)

					pdx->syspower = stack->Parameters.Power.State.SystemState;

				action = SelectDState;

				SETSTATE(SubPowerUpPending);

				status = STATUS_MORE_PROCESSING_REQUIRED;

				}



			continue;

			}					// SysPowerUpComplete



		///////////////////////////////////////////////////////////////////////

		// SysPowerDownComplete is the action for a MainIrpComplete event in the

		// SysPowerDownPending state.



		case SysPowerDownComplete:

			{					// SysPowerDownComplete

			if (stack->MinorFunction == IRP_MN_SET_POWER)

				pdx->syspower = stack->Parameters.Power.State.SystemState;



			action = CompleteMainIrp;

			continue;

			}					// SysPowerDownComplete



		///////////////////////////////////////////////////////////////////////

		// SelectDState is used to establish the power state and minor function

		// code for a D-state IRP that corresponds to the S-state IRP we're

		// processing. After doing that, we do the SendDeviceIrp action.



		case SelectDState:

			{					// SelectDState

			SYSTEM_POWER_STATE sysstate = stack->Parameters.Power.State.SystemState;



			// TODO In my testing, if I didn't go to D0 here, Win2K wouldn't come out

			// of suspend. Oddly enough, Win98SE automatically repowers the device the next time

			// a R/W IRP comes along if I just leave the device in D3. The DDK says

			// you can just leave the device depowered until another IRP comes along

			// so long as you're not an INRUSH device. It also says you must repower

			// yourself when you get a new IRP. This all needs more investigation...



			if (sysstate == PowerSystemWorking)

				ctx->devstate = PowerDeviceD0;

			else

				{

				DEVICE_POWER_STATE maxstate = pdx->devcaps.DeviceState[sysstate];

				DEVICE_POWER_STATE minstate = PowerDeviceD3;

				ctx->devstate = minstate > maxstate ? minstate : maxstate;

				}

			ctx->MinorFunction = stack->MinorFunction;

			action = SendDeviceIrp;

			continue;

			}					// SelectDState



		///////////////////////////////////////////////////////////////////////

		// SendDeviceIrp requests a device set- or query-power IRP using the power

		// state and minor function code currently in the context block. SelectDState

		// put them there.



		case SendDeviceIrp:

			{					// SendDeviceIrp



			// Win98 has a bug such that, if you request a set-power IRP for the same

			// D-state you're already in, PoRequestPowerIrp will report success but

			// CONFIGMG won't generate the configuration event that causes the IRP to

			// actually be sent. Without the following test, we would wait forever

			// for this expected IRP to complete.



			if (win98 && ctx->devstate == pdx->devpower)

				{				// pretend success

				ctx->status = STATUS_SUCCESS;

				action = actiontable[ctx->state][AsyncNotify];

				continue;

				}				// pretend success



			// Ask the power manager to send us an IRP. In Win98, we need to supply the

			// PDO as the device object address because NTKERN needs to go directly from

			// there to the devnode address.



			POWER_STATE powstate;

			powstate.DeviceState = ctx->devstate;



			NTSTATUS postatus = PoRequestPowerIrp(pdx->Pdo, ctx->MinorFunction, powstate,

				(PREQUEST_POWER_COMPLETE) PoCompletionRoutine, ctx, NULL);



			// If PoRequestPowerIrp fails, it never actually sent an IRP down the stack,

			// so we can certain that PoCompletionRoutine never ran



			if (NT_SUCCESS(postatus))

				break;			// started device IRP okay



			KdPrint((DRIVERNAME " - PoRequestPowerIrp failed - %X\n", postatus));

			action = CompleteMainIrp;

			ctx->status = postatus;

			continue;

			}					// SendDeviceIrp



		///////////////////////////////////////////////////////////////////////

		// CompleteMainIrp is the penultimate action of the finite state machine.

		// This is where we actually complete the power IRP we've been handling.



		case CompleteMainIrp:

			{					// CompleteMainIrp

			PoStartNextPowerIrp(Irp);



			// If called from MainCompletionRoutine, just allow the completion process

			// to take its course. Otherwise, explicitly complete the main IRP.



			if (event == MainIrpComplete)

				status = ctx->status;	// might have been STATUS_MORE_PROCESSING_REQUIRED until now

			else

				{

				ASSERT(ctx->status != STATUS_PENDING);

				Irp->IoStatus.Status = ctx->status;

				IoCompleteRequest(Irp, IO_NO_INCREMENT);

				}



			// Release the remove lock to balance the extra acquisition in TriageNewIrp

			

			IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

			

			action = DestroyContext;

			continue;

			}					// CompleteMainIrp



		///////////////////////////////////////////////////////////////////////

		// DestroyContext is the last action for an IRP.



		case DestroyContext:

			{					// DestroyContext

			SETSTATE(FinalState);

			ExFreePool(ctx);

			break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -