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

📄 power.cpp

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


			if (pdx->devpower > pdx->devcaps.DeviceWake 

				|| pdx->syspower > pdx->devcaps.SystemWake

				|| pdx->devpower != PowerDeviceD0)

				{

				KdPrint(("%s - Deferring WAIT_WAKE due to state or capabilities\n", pdx->DebugName));

				return STATUS_INVALID_DEVICE_REQUEST;

				}



			if (InterlockedExchange(&pdx->wwoutstanding, 1))

				break;			// IRP already pending



			pdx->wwcancelled = 0;



			POWER_STATE junk;

			junk.SystemState = pdx->devcaps.SystemWake; // lowest state from which this IRP will wake system



			// I have seen systems where SystemState has a ridiculous value, such that we have to

			// ask for S0 or else it doesn't work...



			if (junk.SystemState > PowerSystemHibernate)

				{				// correct bogus value

				KdPrint(("%s - Requesting WAIT_WAKE with S0 instead of bogus S%d from capabilities\n", pdx->DebugName, junk.SystemState - 1));

				junk.SystemState = PowerSystemWorking;

				}				// correct bogus value

			

			KdPrint(("%s - Issuing WAIT_WAKE\n", pdx->DebugName));

			

			status = PoRequestPowerIrp(pdx->Pdo, IRP_MN_WAIT_WAKE, junk, (PREQUEST_POWER_COMPLETE) WaitWakeCallback, pdx, &pdx->WaitWakeIrp);

			if (!NT_SUCCESS(status))

				{					// error starting wakeup IRP

				KdPrint(("%s - PoRequestPowerIrp(IRP_MN_WAIT_WAIT) failed - %X\n", pdx->DebugName, status));

				pdx->WakeupEnabled = FALSE;

				pdx->wwoutstanding = 0;

				break;

				}					// error starting wakeup IRP



			status = STATUS_SUCCESS;	// especially *not* STATUS_PENDING!



			break;

			}					// wakeup is enabled



		// Note fall-through to CanceWaitWake here!!



		}						// ManageWaitWake



	case CancelWaitWake:

		{						// CancelWaitWake



		// If the following exchange operation returns NULL, WaitWakeComplete has run and

		// the IRP may no longer exist.



		PIRP Irp = (PIRP) InterlockedExchangePointer((PVOID*) &pdx->WaitWakeIrp, NULL);

		if (Irp)

			{				// cancel pending IRP



			// We need to be sure that IoCancelIrp and any cancel routine it may

			// call finish before the Power Manager calls IoFreeIrp to get rid

			// of the WAIT_WAKE IRP. The call to IoFreeIrp can't happen sooner

			// than the IRP gets all the way through IoCompleteRequest, however, so we establish

			// an interlock such that whichever of us and our completion routine

			// sees the IRP last allows it to complete.



			IoCancelIrp(Irp);

			KdPrint(("%s - IRP_MN_WAIT_WAKE cancelled\n", pdx->DebugName));



			if (InterlockedExchange(&pdx->wwcancelled, 1))

				IoCompleteRequest(Irp, IO_NO_INCREMENT); // pickup with aborted completion

			}				// cancel pending IRP

		break;

		}						// CancelWaitWake



	default:

		ASSERT(FALSE);

		status = STATUS_INVALID_DEVICE_REQUEST;

		break;

		}						// perform requested function



	return status;

	}							// GenericWakeupControl



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



GENERICAPI NTSTATUS GENERIC_EXPORT GenericWakeupFromIdle(PGENERIC_EXTENSION pdx, BOOLEAN wait /* = FALSE */)

	{							// GenericWakeupFromIdle

	if (pdx->devpower == PowerDeviceD0)

		return STATUS_SUCCESS;

	NTSTATUS status = SendDeviceSetPower(pdx, PowerDeviceD0, wait);

	if (status == STATUS_PENDING)

		status = STATUS_SUCCESS;

	return status;

	}							// GenericWakeupFromIdle



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

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



VOID AdjustSpecialFileCounter(PGENERIC_EXTENSION pdx, BOOLEAN inpath, PLONG counter)

	{							// AdjustSpecialFileCounter



	// Increment or decrement the appopriate special-file usage counter. Note

	// that IoAdjustPagingPathCount (recommended for this use in the DDK doc) is

	// just a macro that does exactly this...



	if (inpath)

		InterlockedIncrement(counter);

	else

		InterlockedDecrement(counter);



	// Enable or disable idle detection, as appropriate. Alter the not-disableable

	// status flag as well (SP-7, ver 1.6)



	LONG totcount = pdx->ndumpfiles + pdx->nhibernatefiles + pdx->npagefiles;

	if (totcount == 0)

		{						// resume idle detection

		if (pdx->cto && pdx->pto)

			pdx->idlecount = PoRegisterDeviceForIdleDetection(pdx->Pdo, pdx->cto, pdx->pto, pdx->idlestate);

		GenericSetDeviceState(pdx, 0);

		}						// resume idle detection

	else if (inpath && totcount == 1)

		{						// disable idle detection

		pdx->idlecount = PoRegisterDeviceForIdleDetection(pdx->Pdo, 0, 0, PowerDeviceD0);

		GenericSetDeviceState(pdx, PNP_DEVICE_NOT_DISABLEABLE);

		}						// disable idle detection

	}							// AdjustSpecialFileCounter



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



NTSTATUS DefaultPowerHandler(PGENERIC_EXTENSION pdx, PIRP Irp)

	{							// DefaultPowerHandler

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

	IoSkipCurrentIrpStackLocation(Irp);

	return PoCallDriver(pdx->LowerDeviceObject, Irp);

	}							// DefaultPowerHandler



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

// GetLowestDevicePowerState returns the lowest device power state that is

// consistent with a given system power state and the current wakeup state of

// the device.



DEVICE_POWER_STATE GetLowestDevicePowerState(PGENERIC_EXTENSION pdx, SYSTEM_POWER_STATE sysstate)

	{							// GetLowestDevicePowerState

	DEVICE_POWER_STATE maxstate = pdx->devcaps.DeviceState[sysstate];

	DEVICE_POWER_STATE minstate = PowerDeviceD3;



	if (pdx->WakeupEnabled && sysstate <= pdx->devcaps.SystemWake)

		minstate = pdx->devcaps.DeviceWake;	// select state that will preserve wakeup ability



	DEVICE_POWER_STATE dstate = minstate > maxstate ? minstate : maxstate;



	// Allow minidriver to pick the new state, subject to the minimum and maximum

	// already established.



	if (pdx->GetDevicePowerState)

		{						// let minidriver pick state

		dstate = (*pdx->GetDevicePowerState)(pdx->DeviceObject, sysstate, dstate);

		if (dstate < maxstate)

			dstate = maxstate;

		else if (dstate > minstate)

			dstate = minstate;

		}						// let minidriver pick state



	return dstate;

	}							// GetLowestDevicePowerState



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



NTSTATUS GetPowerInfoFromRegistry(PGENERIC_EXTENSION pdx, PPOWERINFO pip)

	{							// GetPowerInfoFromRegistry

	HANDLE hkey;

	NTSTATUS status = IoOpenDeviceRegistryKey(pdx->Pdo, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &hkey);

	if (!NT_SUCCESS(status))

		{

		KdPrint((DRIVERNAME " - Error %X trying to open registry key\n", status));

		return status;

		}



	UNICODE_STRING valname;

	RtlInitUnicodeString(&valname, L"PowerSettings");

	ULONG size = 0;

	UCHAR junk;



	status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, &junk, 0, &size);

	if (status != STATUS_OBJECT_NAME_NOT_FOUND && size)

		{						// value exists

		PKEY_VALUE_PARTIAL_INFORMATION vpip = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(PagedPool, size);

		status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, vpip, size, &size);

		if (NT_SUCCESS(status))

			{					// copy value

			if (vpip->DataLength < 2 * sizeof(ULONG))

				{

				KdPrint(("%s - Ignoring PowerSettings value with strange size %d\n", pdx->DebugName, vpip->DataLength));

				status = STATUS_UNSUCCESSFUL;

				}

			else

				RtlCopyBytes(pip, vpip->Data, 2 * sizeof(ULONG));

			}					// copy value

		else

			KdPrint((DRIVERNAME " - ZwQueryValueKey failed - %X\n", status));



		ExFreePool(vpip);

		}						// value exists



	ZwClose(hkey);

	return status;

	}							// GetPowerInfoFromRegistry



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



NTSTATUS ImplementPowerPolicy(PGENERIC_EXTENSION pdx, PPOWERINFO pip)

	{							// ImplementPowerPolicy

	if (pdx->Flags & GENERIC_IDLE_DETECT)

		GenericRegisterForIdleDetection(pdx,

		pip->ulConservation, pip->ulPerformance, PowerDeviceD3);

	GenericWakeupControl(pdx, pip->bWakeup ? EnableWakeup : DisableWakeup);

	return STATUS_SUCCESS;

	}							// ImplementPowerPolicy



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



BOOLEAN OkayToRemove(PGENERIC_EXTENSION pdx)

	{							// OkayToRemove

	if (pdx->ndumpfiles || pdx->nhibernatefiles || pdx->npagefiles)

		return FALSE;

	if (!pdx->OkayToRemove)

		return TRUE;

	return (*pdx->OkayToRemove)(pdx->DeviceObject);

	}							// OkayToRemove



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



BOOLEAN OkayToStop(PGENERIC_EXTENSION pdx)

	{							// OkayToStop

	if (pdx->ndumpfiles || pdx->nhibernatefiles || pdx->npagefiles)

		return FALSE;

	if (!pdx->OkayToStop)

		return TRUE;

	return (*pdx->OkayToStop)(pdx->DeviceObject);

	}							// OkayToStop



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



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



#pragma PAGEDCODE



NTSTATUS SendDeviceSetPower(PGENERIC_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



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



#pragma LOCKEDCODE



VOID WaitWakeCallback(PDEVICE_OBJECT junk, UCHAR MinorFunction, POWER_STATE state,

	PGENERIC_EXTENSION pdx, PIO_STATUS_BLOCK pstatus)

	{							// WaitWakeCallback



	// Indicate that wait-wake is no longer outstanding



	pdx->wwoutstanding = 0;



	if (!NT_SUCCESS(pstatus->Status))

		{						// IRP failed

		KdPrint(("%s - IRP_MN_WAIT_WAKE failed - %X\n", pdx->DebugName, pstatus->Status));

		return;

		}						// IRP failed



	// Wakeup our own device. This is necessary if the device signalled a wakeup while

	// the system was already in S0 because, in this case, we won't otherwise get

	// an IRP to power ourselves on.

	

	SendDeviceSetPower(pdx, PowerDeviceD0, FALSE);

	}							// WaitWakeCallback



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



#pragma LOCKEDCODE



NTSTATUS WaitWakeCompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp, PGENERIC_EXTENSION pdx)

	{							// WaitWakeCompletionRoutine



	if (Irp->PendingReturned)

		IoMarkIrpPending(Irp);



	// Nullify our WaitWakeIrp pointer to prevent anyone from dereferncing

	// the pointer once the IRP gets released as part of the completion process.

	// If it's already NULL, someone has gotten into CancelWaitWake in GenericWakeupControl,

	// meaning we have to avoid a race with IoCancelIrp.



	if (InterlockedExchangePointer((PVOID*) &pdx->WaitWakeIrp, NULL))

		return STATUS_SUCCESS;	// we got here before anyone tried to cancel the IRP



	// CancelWaitWake has run. If wwcancelled is nonzero, so has the call to

	// IoCancelIrp and we can allow the IRP to complete. If wwcancelled is still zero

	// (left over from when we launched the IRP), IoCancelIrp hasn't been called yet

	// and we want to interrupt the completion process.



	if (InterlockedExchange(&pdx->wwcancelled, 1))

		return STATUS_SUCCESS;	// allow it to complete



	return STATUS_MORE_PROCESSING_REQUIRED; // let CancelWakeWait complete it

	}							// WaitWakeCompletionRoutine



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



#pragma PAGEDCODE

⌨️ 快捷键说明

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