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

📄 powerfdo.cpp

📁 Programming the Microsoft Windows driver model.2nd 随书光盘。内有很多作者送的实用工具和随书源码。WDM编程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// Power request handler notify driver

// Copyright (C) 1999 by Walter Oney

// All rights reserved



#include "stddcls.h"

#include "driver.h"



NTSTATUS DefaultPowerHandler(PDEVICE_EXTENSION pdx, IN PIRP Irp);



enum POWSTATE {

	InitialState = 0,				// initial state of FSM

	SysPowerUpPending,				// system power-up IRP forwarded

	SubPowerUpPending,				// waiting for nested device power up to finish

	SubPowerDownPending,			// waiting from device to power down before forwarding system power-down IRP

	SysPowerDownPending,			// waiting for system power-down IRP to finish

	DevPowerUpPending,				// waiting for device power-up IRP

	DevPowerDownPending,			// waiting for device power-down IRP

	ContextSavePending,				// context save is underway

	ContextRestorePending,			// context restore is underway

	DevQueryUpPending,				// device query for power-up pending

	DevQueryDownPending,			// device query for power-down pending

	QueueStallPending,				// waiting for device to be idle

	FinalState,						// final state of FSM

	NUMPOWSTATES,

	};



enum POWEVENT {

	NewIrp = 0,						// new query/set IRP

	MainIrpComplete,				// the main IRP has finished

	AsyncNotify,					// some other event has occurred

	NUMPOWEVENTS,

	};



typedef struct _POWCONTEXT {

	PDEVICE_EXTENSION pdx;			// our own device extension

	PIRP irp;						// the IRP we're processing

	enum POWSTATE state;			// current state of FSM

	NTSTATUS status;				// completion status for main IRP

	PKEVENT pev;					// event to set when IRP is complete

	DEVICE_POWER_STATE devstate;	// device power state to use

	DEVICE_POWER_STATE oldpower;	// previous device power state

	UCHAR MinorFunction;			// minor function to use in requested power IRP

	} POWCONTEXT, *PPOWCONTEXT;



NTSTATUS HandlePowerEvent(PPOWCONTEXT ctx, enum POWEVENT event);



#if DBG



	static char* fcnname[] = {

		"IRP_MN_WAIT_WAKE",

		"IRP_MN_POWER_SEQUENCE",

		"IRP_MN_SET_POWER",

		"IRP_MN_QUERY_POWER",

		};



	static char* sysstate[] = {

		"PowerSystemUnspecified",

		"PowerSystemWorking",

		"PowerSystemSleeping1",

		"PowerSystemSleeping2",

		"PowerSystemSleeping3",

		"PowerSystemHibernate",

		"PowerSystemShutdown",

		"PowerSystemMaximum",

		};



	static char* devstate[] = {

		"PowerDeviceUnspecified",

		"PowerDeviceD0",

		"PowerDeviceD1",

		"PowerDeviceD2",

		"PowerDeviceD3",

		"PowerDeviceMaximum",

		};

#endif // DBG

									  

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



#pragma PAGEDCODE



NTSTATUS DispatchPowerFdo(IN PDEVICE_OBJECT fdo, IN PIRP Irp)

	{							// DispatchPowerFdo

	PAGED_CODE();

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);

	if (!NT_SUCCESS(status))

		return CompleteRequest(Irp, status, 0);



	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

	ASSERT(stack->MajorFunction == IRP_MJ_POWER);



	ULONG fcn = stack->MinorFunction;



	if (fcn == IRP_MN_SET_POWER || fcn == IRP_MN_QUERY_POWER)

		{						// handle set/query



#if DBG

		KdPrint((DRIVERNAME " - POWER Request (%s)", fcnname[fcn]));

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

			KdPrint((", S-state = %s\n", sysstate[stack->Parameters.Power.State.SystemState]));

		else

			KdPrint((", D-state = %s\n", devstate[stack->Parameters.Power.State.DeviceState]));

#endif // DBG

			{					// launch FSM

			PPOWCONTEXT ctx = (PPOWCONTEXT) ExAllocatePool(NonPagedPool, sizeof(POWCONTEXT));

			if (!ctx)

				{

				KdPrint((DRIVERNAME " - Can't allocate power context structure\n"));

				status = CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);

				}

			else

				{				// process this IRP

				RtlZeroMemory(ctx, sizeof(POWCONTEXT));

				ctx->pdx = pdx;

				ctx->irp = Irp;

				status = HandlePowerEvent(ctx, NewIrp);

				}				// process this IRP

			}					// launch FSM

		}						// handle set/query



	else

		{						// handle other power request

		KdPrint((DRIVERNAME " - POWER Request (%s)\n", fcn < arraysize(fcnname) ? fcnname[fcn] : "??"));

			status = DefaultPowerHandler(pdx, Irp);

		}						// handle other power request



	IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

	return status;

	}							// DispatchPowerFdo



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

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



NTSTATUS DefaultPowerHandler(PDEVICE_EXTENSION pdx, IN PIRP Irp)

	{							// DefaultPowerHandler

	PoStartNextPowerIrp(Irp);	// must be done while we own the IRP

	IoSkipCurrentIrpStackLocation(Irp);

	return PoCallDriver(pdx->LowerDeviceObject, Irp);

	}							// DefaultPowerHandler



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



VOID SendAsyncNotification(PVOID context)

	{							// SendAsyncNotification

	HandlePowerEvent((PPOWCONTEXT) context, AsyncNotify);

	}							// SendAsyncNotification



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



struct SDSP_CONTEXT {

	PKEVENT pev;				// event to signal when request complete

	NTSTATUS status;			// ending status

	};



#pragma LOCKEDCODE



VOID SendDeviceSetPowerComplete(PDEVICE_OBJECT junk, UCHAR fcn, POWER_STATE state, SDSP_CONTEXT* context, PIO_STATUS_BLOCK pstatus)

	{							// SendDeviceSetPowerComplete

	context->status = pstatus->Status;

	KeSetEvent(context->pev, EVENT_INCREMENT, FALSE);

	}							// SendDeviceSetPowerComplete



NTSTATUS SendDeviceSetPower(PDEVICE_EXTENSION pdx, DEVICE_POWER_STATE devpower, BOOLEAN wait /* = FALSE */)

	{							// SendDeviceSetPower

	POWER_STATE state;

	state.DeviceState = devpower;

	NTSTATUS status;



	if (wait)

		{						// synchronous operation

		KEVENT event;

		KeInitializeEvent(&event, NotificationEvent, FALSE);

		SDSP_CONTEXT context = {&event};

		status = PoRequestPowerIrp(pdx->Pdo, IRP_MN_SET_POWER, state,

			(PREQUEST_POWER_COMPLETE) SendDeviceSetPowerComplete, &context, NULL);

		if (status == STATUS_PENDING)

			{

			KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);

			status = context.status;

			}

		}						// synchronous operation

	else

		status = PoRequestPowerIrp(pdx->Pdo, IRP_MN_SET_POWER, state, NULL, NULL, NULL);

	

	return status;

	}							// SendDeviceSetPower



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

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



NTSTATUS MainCompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp, PPOWCONTEXT ctx);

VOID PoCompletionRoutine(PDEVICE_OBJECT junk, UCHAR fcn, POWER_STATE state, PPOWCONTEXT ctx, PIO_STATUS_BLOCK pstatus);

NTSTATUS SafePoCallDriver(PDEVICE_OBJECT DeviceObject, PIRP Irp);



NTSTATUS HandlePowerEvent(PPOWCONTEXT ctx, enum POWEVENT event)

	{							// HandlePowerEvent

	NTSTATUS status = -1;		// an invalid value

	ASSERT(ctx);

	ASSERT((ULONG) event < NUMPOWEVENTS);



	PIRP Irp = ctx->irp;

	PIO_STACK_LOCATION stack = Irp ? IoGetCurrentIrpStackLocation(Irp) : NULL;



	PDEVICE_EXTENSION pdx = ctx->pdx;



	enum POWACTION {

		InvalidAction,			// code for invalid state/event combinations

		TriageNewIrp,			// decide what to do with new IRP

		QueueStallComplete,		// device queue has been stalled

		ForwardMainIrp,			// begin system or device IRP for more power

		SysPowerUpComplete,		// system power-up IRP completed

		SysPowerDownComplete,	// system power-down IRP completed

		SelectDState,			// choose D-state corresponding to main IRP's S-state

		SendDeviceIrp,			// send device IRP

		CompleteMainIrp,		// complete the main IRP

		DestroyContext,			// terminate FSM

		SubPowerUpComplete,		// nested power-up IRP finished or failed

		SubPowerDownComplete,	// nested power-down IRP finished or failed

		DevPowerUpComplete,		// device power-up IRP has completed

		SaveContext,			// save context in preparation for powering down

		ContextSaveComplete,	// device context has been saved

		ContextRestoreComplete,	// device context has been restored

		DevQueryUpComplete,		// device query for power-up complete

		DevQueryDown,			// see if device can power down

		DevQueryDownComplete,	// device query for power-down complete

		};



	static enum POWACTION actiontable[NUMPOWSTATES][NUMPOWEVENTS] = {

/*							NewIrp				MainIrpComplete				AsyncNotify	*/

/* InitialState */			{TriageNewIrp,		InvalidAction,				InvalidAction},

/* SysPowerUpPending */		{InvalidAction,		SysPowerUpComplete,			InvalidAction},

/* SubPowerUpPending */		{InvalidAction,		InvalidAction,				SubPowerUpComplete},

/* SubPowerDownPending */	{InvalidAction,		InvalidAction,				SubPowerDownComplete},

/* SysPowerDownPending */	{InvalidAction,		SysPowerDownComplete,		InvalidAction},

/* DevPowerUpPending */		{InvalidAction,		DevPowerUpComplete,			InvalidAction},

/* DevPowerDownPending */	{InvalidAction,		CompleteMainIrp,			InvalidAction},

/* ContextSavePending */	{InvalidAction,		InvalidAction,				ContextSaveComplete},

/* ContextRestorePending */	{InvalidAction,		InvalidAction,				ContextRestoreComplete},

/* DevQueryUpPending */		{InvalidAction,		DevQueryUpComplete,			InvalidAction},

/* DevQueryDownPending */	{InvalidAction,		DevQueryDownComplete,		InvalidAction},

/* QueueStallPending */		{InvalidAction,		InvalidAction,				QueueStallComplete},

/* FinalState */			{InvalidAction,		InvalidAction,				InvalidAction},

		};



	// Determine the first action to take based on the current state of the FSM and the event that occurred.

	// Note that this isn't as complicated as the use of 2-D array might suggest: all states except

	// the initial state lead to a single action for the one-and-only event that's possible to get in

	// that state.



	enum POWACTION action = actiontable[ctx->state][event];



	// Structurally, the following code is a switch on "action" imbedded within an

	// infinite loop. A case that does a "break" from the switch executes a "break"

	// from the loop, whereupon we return whatever value is left in "status". A case

	// that does a "continue" from the switch repeats the loop -- this is how actions

	// can be strung together during one call to this routine. I coded it this way to

	// avoid return statements in the middle that make it harder to prove that the

	// routine behaves in a predictable way. Note that any "break" should be preceded

	// by a change to the state recorded in the context structure and to the initially

	// invalid valid of "status". There are ASSERTs at the end to check this.



	// Concerning the required change to "ctx->state": there are many cases where we

	// call PoRequestPowerIrp or PoCallDriver, whereupon the context structure gets

	// released before those routines return. We use a SETSTATE macro so we don't

	// have to dereference a possibly invalid "ctx" pointer at the end of the loop. Any

	// action that calls a routine that might result in completing the current IRP

	// should also take care not to touch "ctx" afterwards. (These are always cases that

	// "break" from the switch, so you can just verify that the break always immediately

	// follows the PoXxx call.)



	// Concerning the required change to "status": only TriageNewIrp

⌨️ 快捷键说明

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