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

📄 power.cpp

📁 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

NTSTATUS WritePowerInfoToRegistry(PGENERIC_EXTENSION pdx, PPOWERINFO pip)
	{							// WritePowerInfoToRegistry
	HANDLE hkey;

⌨️ 快捷键说明

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