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

📄 power.cpp

📁 Programming the Microsoft Windows driver model.2nd 随书光盘。内有很多作者送的实用工具和随书源码。WDM编程
💻 CPP
📖 第 1 页 / 共 5 页
字号:
				}				// 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

			if (!NT_SUCCESS(ctx->status))

				action = CompleteMainIrp;

			else

				{				// S-irp succeeded

				action = SelectDState;

				SETSTATE(SubPowerUpPending);

				status = STATUS_MORE_PROCESSING_REQUIRED;	// defer completion of S-IRP



				if (stack->MinorFunction == IRP_MN_SET_POWER)

					{			// S-set

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

					

					// Except in 98/Me, complete an S0 IRP right away to allow

					// faster restart after suspend.



					if (pdx->syspower == PowerSystemWorking && !win98)

						{		// S0

						POWTRACE(("%s - %d.%d Completing S0 IRP early\n", pdx->DebugName, ctxid, eventid));

						PoStartNextPowerIrp(Irp);

						status = STATUS_SUCCESS;	// allows S-IRP to complete

						if (pdx->RemoveLock)

							IoReleaseRemoveLock(pdx->RemoveLock, Irp);

						ctx->irp = NULL;				// flag for eventual CompleteMainIrp step

						}		// S0

					}			// S-set

				}				// S-irp succeeded



			continue;

			}					// SysPowerUpComplete



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

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

		// SysPowerDownPending state.



		case SysPowerDownComplete:

			{					// SysPowerDownComplete

			if (!NT_SUCCESS(ctx->status))

				KdPrint(("%s - System power-down IRP failed - %X\n", pdx->DebugName, ctx->status));



			if (stack->MinorFunction == IRP_MN_SET_POWER)

				pdx->syspower = stack->Parameters.Power.State.SystemState;	// (note that this IRP could not legally have been failed)



			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 sstate = stack->Parameters.Power.State.SystemState;



			ctx->devstate = GetLowestDevicePowerState(pdx, sstate);

			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



			// If we want the device in the same state it's already in, bypass sending

			// the D-state IRP. This is necessary in Win98 due to a bug that causes

			// PoRequestPowerIrp to report success in a situation where CONFIGMG won't

			// generate the configuration event. This has also turned out to be necessary

			// when bringing Win2K/Xp out of standby or hibernate, although I don't

			// exactly understand why.



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

				{				// pretend success

				POWTRACE(("%s -  %d.%d pretending to succeed D-state IRP for same state\n", pdx->DebugName, ctxid, eventid));

				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(("%s - 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



			// In Win98, we must not complete a power IRP at DISPATCH_LEVEL, so

			// queue a work item in that case.



			if (win98 && KeGetCurrentIrql() > PASSIVE_LEVEL)

				{				// defer completion to passive level

				#pragma warning(disable:4995)

				#pragma warning(disable:4996)

				C_ASSERT(sizeof(Irp->Tail.Overlay.DriverContext) >= sizeof(WORK_QUEUE_ITEM));



				PWORK_QUEUE_ITEM item = (PWORK_QUEUE_ITEM) Irp->Tail.Overlay.DriverContext;

				ExInitializeWorkItem(item, (PWORKER_THREAD_ROUTINE) PassivePowerComplete, (PVOID) ctx);

				ExQueueWorkItem(item, CriticalWorkQueue);



				#pragma warning(default:4995)

				#pragma warning(default:4996)



				if (event == MainIrpComplete)

					status = STATUS_MORE_PROCESSING_REQUIRED;

				SETSTATE(PassiveCompletePending);

				break;

				}				// defer completion to passive level



			// Skip completion processing if we've already completed an S0 SET_POWER.

			// Otherwise, complete (or allow to complete) the main IRP



			if (Irp)

				{				// not previously completed



				// Tell the power manager to release the next IRP of the same flavor

				// as we're currently processing.



				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

					{

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

					IoCompleteRequest(Irp, IO_NO_INCREMENT);

					

					if (status == -1)

						status = STATUS_SUCCESS;

					}



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

				

				if (pdx->RemoveLock)

					IoReleaseRemoveLock(pdx->RemoveLock, Irp);

				}				// not previously completed



			// If we stalled the request queue for the pendency of this IRP, unstall it now.

			// Sometimes, we will have cleared the flag in order to leave the queue stalled

			// after completing a power-down.



			if (ctx->UnstallQueue)

				{

				pdx->StalledForPower = FALSE;

				POWTRACE(("%s -  %d.%d unstalling queue\n", pdx->DebugName, ctxid, eventid));

				RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);

				}

			

			action = DestroyContext;

			continue;

			}					// CompleteMainIrp



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

		// DestroyContext is the last action for an IRP.



		case DestroyContext:

			{					// DestroyContext

			SETSTATE(FinalState);

			ExFreePool(ctx);

			break;

			}					// DestroyContext



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

		// SubPowerUpComplete is the action for a AsyncNotify event in the

		// SubPowerUpPending state. This should be called from PoCompletionRoutine.

		// We can also get here from SendDeviceIrp to avoid the Win98 no-D-IRP bug,

		// in which case we don't want to alter "status" from its current value.



		case SubPowerUpComplete:

			{					// SubPowerUpComplete

			if (status == -1)

				status = STATUS_SUCCESS; // don't actually care, since called from PoCompletionRoutine

			action = CompleteMainIrp;

			continue;

			}					// SubPowerUpComplete



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

		// SubPowerDownComplete is the action for a AsyncNotify event in the

		// SubPowerDownPending state. This should be called from PoCompletionRoutine.

		// We can also get here from SendDeviceIrp to avoid the Win98 no-D-IRP bug,

		// in which case we don't want to alter "status" from its current value.



		case SubPowerDownComplete:

			{					// SubPowerDownComplete

			if (status == -1)

				status = STATUS_SUCCESS; // don't actually care, since called from PoCompletionRoutine



			if (NT_SUCCESS(ctx->status))

				{

				SETSTATE(SysPowerDownPending);

				action = ForwardMainIrp;

				}

			else

				action = CompleteMainIrp; // D-state IRP failed, so fail S-state IRP too

			

			continue;

			}					// SubPowerDownComplete



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

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

		// DevPowerUpPending state. This should be called from MainCompletionRoutine

		// when a device power-up IRP finishes in the lower layers.



		case DevPowerUpComplete:

			{					// DevPowerUpComplete



			// If this IRP failed, or if we're just dealing with a query, we're done.



			if (!NT_SUCCESS(ctx->status) || stack->MinorFunction != IRP_MN_SET_POWER)

				{

				action = CompleteMainIrp;

				continue;

				}



			status = STATUS_MORE_PROCESSING_REQUIRED; // defer completion of the main IRP while we restore context



			ctx->oldpower = pdx->devpower;

			pdx->devpower = stack->Parameters.Power.State.DeviceState;



			KdPrint(("%s - Now in %s\n", pdx->DebugName, devstate[pdx->devpower]));



			// Since no bus driver currently implements IRP_MN_POWER_SEQUENCE, you

			// don't really need to bother with it. But doing it correctly is enough of a pain

			// in the neck that it's worthwhile showing you how to do it just in case it ever

			// becomes relevant. I thought this was marginal enough that I didn't discuss

			// the extra states in the book, though. In the book, I showed this action as

			// including the stuff that's in RestoreContext, too. [SP-10: don't do this unless

			// PerfBoundary is nonzero. The comment in generic.h says that leaving it zero

			// will suppress the IRP, and a reader reported a problem with PCMCIA.SYS barfing

			// on one of them.]



			if (pdx->PerfBoundary && ctx->oldpower >= pdx->PerfBoundary)

				{				// context restore will be expensive

				SETSTATE(RestoreSeqPending);

				action = SendPowerSequence;

				continue;

				}				// context restore will be expensive



			action = RestoreContext;

			continue;

			}					// DevPowerUpComplete



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

		// ContextRestoreComplete is the last action for a device set power up

		// operation. It's ordinarily reached when GenericSaveRestoreComplete

		// signals a MainIrpComplete event from the ContextRestorePending state.

		// It can also be reached directly from DevPowerUpComplete when there is

		// no context restore function.



		case ContextRestoreComplete:

			{					// ContextRestoreComplete

			if (event == AsyncNotify)

				status = STATUS_SUCCESS; // doesn't actually matter

			action = CompleteMainIrp;



			// If the device IRP failed, just go ahead and let it complete. If we've

			// successfully resumed to a sleeping state (> D0), skip restarting the

			// substantive IRP queue and complete the IRP as well.



			if (!NT_SUCCESS(ctx->status) || pdx->devpower != PowerDeviceD0)

				continue;



			// We've just gone to D0, unstall the request queue by setting

			// the flag that will cause CompleteMainIrp to do so. It's very

			// important in our scheme that we stall the queue for any device

			// IRP that arrives while we're in D0 and omit to unstall it when

			// we complete a SET for a lower power state. We thereby arrange

			// to stall the queue just once across an entire period of low

			// power.



			if (pdx->nqueues)

				ctx->UnstallQueue = TRUE;



			continue;

			}					// ContextRestoreComplete



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

		// SaveContext initiates a context save operation if necessary. This will

		// be the second action for a new device set-power IRP.



		case SaveContext:

⌨️ 快捷键说明

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