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

📄 power.cpp

📁 WDM驱动程序的范例程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		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:
			{					// SaveContext
			DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;

			// If we're actually changing to a lower power state, give the client driver
			// a chance to save any device context information asynchronously. It will
			// call GenericSaveRestoreComplete when it finishes.

			if (pdx->SaveDeviceContext && devpower > pdx->devpower)
				{				// save context
				SETSTATE(ContextSavePending);
				(*pdx->SaveDeviceContext)(pdx->DeviceObject, pdx->devpower, devpower, ctx);
				break;

⌨️ 快捷键说明

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