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

📄 power.cpp

📁 WDM驱动程序的范例程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
				}				// save context

			action = ContextSaveComplete;
			continue;
			}					// SaveContext

		///////////////////////////////////////////////////////////////////////
		// ContextSaveComplete is the action for an AsyncNotify event in the
		// ContextSavePending state. It should be entered from GenericSaveRestoreComplete,
		// which in turn should have been called by the client driver when its
		// context save operation finished. It can also be entered directly from
		// SaveContext when there is no context save routine.

		case ContextSaveComplete:
			{					// ContextSaveComplete
			if (event == AsyncNotify)
				status = STATUS_SUCCESS;	// doesn't actually matter in this case

			// Obtain a set of power-state sequence numbers to optimize state restoration later.
			// In the book, I didn't include this bit of nonsense. The code in ForwardDevDown
			// appears right here in the book. [SP-10: see note elsewhere]

			if (pdx->PerfBoundary && stack->Parameters.Power.State.DeviceState >= pdx->PerfBoundary)
				{				// context restore will be expensive
				SETSTATE(SaveSeqPending);
				action = SendPowerSequence;
				continue;
				}				// context restore will be expensive/

			action = ForwardDevDown;
			continue;
			}					// ContextSaveComplete

		///////////////////////////////////////////////////////////////////////
		// DevQueryUpComplete is the action for a MainIrpComplete event in the
		// DevQueryUpPending state. This should be called by MainCompletionRoutine
		// when a device query-power-up IRP completes. We don't expect to ever get this
		// kind of a query, by the way, but we should handle it nontheless.

		case DevQueryUpComplete:
			{					// DevQueryUpComplete
			if (NT_SUCCESS(ctx->status) && pdx->QueryPower)
				{				// ask client if change okay

				// Everybody belows us has acquiesced in restoring power. Ask the
				// client driver if it's cool by this too.

				if (!(*pdx->QueryPower)(pdx->DeviceObject, pdx->devpower, stack->Parameters.Power.State.DeviceState))
					ctx->status = STATUS_UNSUCCESSFUL; // fail the query
				}				// ask client if change okay

			action = CompleteMainIrp;
			continue;
			}					// DevQueryUpComplete

		///////////////////////////////////////////////////////////////////////
		// DevQueryDown is the second action (after TriageNewIrp) for a device
		// query-power that specifies less than or equal to the current device
		// power state.

		case DevQueryDown:
			{					// DevQueryDown
			DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;

			// If the proposed power state is less than the current state,
			// ask the client driver if it's okay to change.

			if (devpower > pdx->devpower && pdx->QueryPower && !(*pdx->QueryPower)(pdx->DeviceObject, pdx->devpower, devpower))
				{				// fail the query
				ctx->status = STATUS_UNSUCCESSFUL;
				action = DevQueryDownComplete;
				continue;
				}				// fail the query

			SETSTATE(DevQueryDownPending);
			action = ForwardMainIrp;
			continue;
			}					// DevQueryDown

		///////////////////////////////////////////////////////////////////////
		// DevQueryDownComplete is the action for a MainIrpComplete event in the
		// DevQueryDownPending state. It can be reached from MainCompletionRoutine
		// or directly from DevQueryDown.

		case DevQueryDownComplete:
			{					// DevQueryDownComplete

			// The Windows 98 version of the USB hub driver fails device power
			// query operations, which is incorrect...

			if (ctx->status == STATUS_INVALID_PARAMETER)
				ctx->status = STATUS_SUCCESS;

			// If the query is succeeding, leave the request queue stalled

			if (NT_SUCCESS(ctx->status))
				ctx->UnstallQueue = FALSE;

			action = CompleteMainIrp;
			continue;
			}					// DevQueryDownComplete

		///////////////////////////////////////////////////////////////////////
		// SendPowerSequence creates an IRP_MN_POWER_SEQUENCE request. It can be
		// entered from DevPowerUpComplete or ContextSaveComplete

		case SendPowerSequence:
			{					// SendPowerSequence
			PIRP seqirp = IoAllocateIrp(pdx->LowerDeviceObject->StackSize, FALSE);
			if (seqirp)
				{				// sequence IRP created
				PIO_STACK_LOCATION seqstack = IoGetNextIrpStackLocation(seqirp);
				seqstack->MajorFunction = IRP_MJ_POWER;
				seqstack->MinorFunction = IRP_MN_POWER_SEQUENCE;
				seqstack->Parameters.PowerSequence.PowerSequence = &ctx->sequence;

				IoSetCompletionRoutine(seqirp, (PIO_COMPLETION_ROUTINE) SequenceCompletionRoutine, (PVOID) ctx, TRUE, TRUE, TRUE);

				PoCallDriver(pdx->LowerDeviceObject, seqirp);
				break;
				}				// sequence IRP created
			else
				{				// couldn't create IRP
				if (ctx->state == SaveSeqPending)
					action = ForwardDevDown;
				else
					action = RestoreContext;

				continue;
				}				// couldn't create IRP
			}					// SendPowerSequence

		///////////////////////////////////////////////////////////////////////
		// SaveSeqComplete is the action for an AsyncNotify event in the
		// SaveSeqPending state. It should be entered from SequenceCompletionRoutine
		// when an IRP_MN_POWER_SEQUENCE request completes.

		case SaveSeqComplete:
			{					// SaveSeqComplete
			if (NT_SUCCESS(ctx->status))
				{
				KdPrint(("%s - Someone actually succeeded a POWER_SEQUENCE request!\n", pdx->DebugName));
				pdx->oldseq = ctx->sequence; // save sequence numbers for power-up
				}
			else
				RtlZeroMemory(&pdx->oldseq, sizeof(pdx->oldseq));

			status = STATUS_MORE_PROCESSING_REQUIRED; // won't actually be used
			ctx->status = STATUS_SUCCESS;	// status from POWER_SEQUENCE not actually relevant

			action = ForwardDevDown;
			continue;
			}					// SaveSeqComplete

		///////////////////////////////////////////////////////////////////////
		// ForwardDevDown forwards a device set-power down IRP. It can be reached
		// from SaveSeqComplete or from ContextSaveComplete.

		case ForwardDevDown:
			{					// ForwardDevDown
			SETSTATE(DevPowerDownPending);
			action = ForwardMainIrp;

			DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;
			if (devpower <= pdx->devpower)
				continue;		// no actual change in device power

			pdx->devpower = devpower;

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

			// If power has now been removed, leave the queue stalled

			if (devpower > PowerDeviceD0)
				ctx->UnstallQueue = FALSE;

			continue;
			}					// ForwardDevDown

		///////////////////////////////////////////////////////////////////////
		// RestoreSeqComplete is the action for an AsyncNotify event in the
		// RestoreSeqPending state. It should be entered from SequenceCompletionRoutine
		// when an IRP_MN_POWER_SEQUENCE request completes

		case RestoreSeqComplete:
			{					// RestoreSeqComplete

			// Now decide if we really need to restore the device context by comparing
			// the sequence numbers for the performance boundary state

			action = RestoreContext;	// assume we'll want to restore context

			if (NT_SUCCESS(ctx->status))
				switch (pdx->PerfBoundary)
					{			// check relevant sequence numbers
					
				case PowerDeviceD1:
					if (ctx->sequence.SequenceD1 <= pdx->oldseq.SequenceD1)
						action = ContextRestoreComplete;
					break;
					
				case PowerDeviceD2:
					if (ctx->sequence.SequenceD2 <= pdx->oldseq.SequenceD2)
						action = ContextRestoreComplete;
					break;
					
				case PowerDeviceD3:
					if (ctx->sequence.SequenceD3 <= pdx->oldseq.SequenceD3)
						action = ContextRestoreComplete;
					break;

					}			// check relevant sequence numbers

		#if DBG
			if (action != RestoreContext)
				KdPrint(("%s - Bypassing context restore due to sequence number optimization\n", pdx->DebugName));
		#endif

			ctx->status = STATUS_SUCCESS; // ignore status from POWER_SEQUENCE
			status = STATUS_MORE_PROCESSING_REQUIRED;

			continue;
			}					// RestoreSeqComplete

		///////////////////////////////////////////////////////////////////////
		// RestoreContext restores device context if necessary. It can be entered
		// from RestoreSeqComplete or from DevPowerUpComplete

		case RestoreContext:
			{					// RestoreContext

			// Allow the client driver to restore any device context. This occurs
			// asynchronously. The client notifies us when the the restore operation
			// finishes by calling GenericSaveRestoreComplete.

			if (pdx->RestoreDeviceContext)
				{				// restore context
				SETSTATE(ContextRestorePending);
				(*pdx->RestoreDeviceContext)(pdx->DeviceObject, ctx->oldpower, pdx->devpower, ctx);
				break;
				}				// restore context

			action = ContextRestoreComplete;
			continue;
			}					// RestoreContext

		///////////////////////////////////////////////////////////////////////
		// InvalidAction is the action for any unexpected event. It should never occur.

		case InvalidAction:
		default:
			status = STATUS_UNSUCCESSFUL;
			break;
			}					// perform next action

		break;					// for cases that "break" from the switch
		}						// handle this event

#if DBG

	// Check to make sure the state got changed before we exit

	if (nextstate == originalstate)
		KdPrint(("%s - State didn't change from %d in HandlePowerEvent!\n", pdx->DebugName, originalstate));

	// Check to make sure a valid status will be returned

	if (status == -1)
		KdPrint(("%s - returned status didn't change in HandlePowerEvent!\n", pdx->DebugName));

#endif // DBG

	POWTRACE(("%s - %d.%d returning %X, state is %s\n", pdx->DebugName, ctxid, eventid, status, powstatenames[nextstate]));

	return status;
	}							// HandlePowerEvent

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

NTSTATUS MainCompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp, PPOWCONTEXT ctx)
	{							// MainCompletionRoutine
	ctx->status = Irp->IoStatus.Status;
	return HandlePowerEvent(ctx, MainIrpComplete);
	}							// MainCompletionRoutine

NTSTATUS SequenceCompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp, PPOWCONTEXT ctx)
	{							// SequenceCompletionRoutine
	ctx->status = Irp->IoStatus.Status;
	HandlePowerEvent(ctx, AsyncNotify);
	IoFreeIrp(Irp);
	return STATUS_MORE_PROCESSING_REQUIRED;
	}							// SequenceCompletionRoutine

VOID PoCompletionRoutine(PDEVICE_OBJECT junk, UCHAR fcn, POWER_STATE state, PPOWCONTEXT ctx, PIO_STATUS_BLOCK pstatus)
	{							// PoCompletionRoutine
	ctx->status = pstatus->Status;
	HandlePowerEvent(ctx, AsyncNotify);
	}							// PoCompletionRoutine

VOID PassivePowerCall(PIRP Irp)
	{							// PassivePowerCall
	PoCallDriver(IoGetNextIrpStackLocation(Irp)->DeviceObject, Irp);
	}							// PassivePowerCall

NTSTATUS SafePoCallDriver(PDEVICE_OBJECT DeviceObject, PIRP Irp)
	{							// SafePoCallDriver

	// If running in Win2K, or if Win98 and already at PASSIVE_LEVEL, just call
	// PoCallDriver.

	if (!win98 || KeGetCurrentIrql() == PASSIVE_LEVEL)
		return PoCallDriver(DeviceObject, Irp);
	
	// Win98's PoCallDriver is the same as IoCallDriver, and it won't do anything to
	// present the IRP at passive level if we're currently above. Build a work queue
	// item in the DriverContext field of the IRP and queue the work item so we
	// can present the IRP properly. Boy, is this something we shouldn't have to
	// worry about!

	IoMarkIrpPending(Irp);		// be sure it's marked pending
	IoGetNextIrpStackLocation(Irp)->DeviceObject = DeviceObject; // so PassivePowerCall can find it

	// Note: The ExXxxWorkItem functions are deprecated for Win2K and WinXp but
	// okay for win98. This code only executes in Win98, so these should be okay

	#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) PassivePowerCall, (PVOID) Irp);
	ExQueueWorkItem(item, CriticalWorkQueue);

	#pragma warning(default:4995)
	#pragma warning(default:4996)

	return STATUS_PENDING;
	}							// SafePoCallDriver

⌨️ 快捷键说明

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