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

📄 power.cpp

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

				}				// 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 b

⌨️ 快捷键说明

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