summaryrefslogtreecommitdiff
path: root/pofx/WDF/Driver/MultiComp/lib/device.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /pofx/WDF/Driver/MultiComp/lib/device.c
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'pofx/WDF/Driver/MultiComp/lib/device.c')
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/device.c868
1 files changed, 868 insertions, 0 deletions
diff --git a/pofx/WDF/Driver/MultiComp/lib/device.c b/pofx/WDF/Driver/MultiComp/lib/device.c
new file mode 100644
index 00000000..aa17eaea
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/device.c
@@ -0,0 +1,868 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ device.c
+
+Abstract:
+ This module contains routines that implement power management for the device
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "WdfPoFxPriv.h"
+#include "device.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, _PfhEvtSelfManagedIoInit)
+#pragma alloc_text(PAGE, _PfhEvtSelfManagedIoFlush)
+#endif
+
+VOID
+UnregisterWithPowerFrameworkWorker(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine description:
+ This routine unregisters a device with the power framework. This routine
+ can be called in EvtDeviceSelfManagedioRestart, which can not be made
+ pageable, therefore this function should also not be pageable.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+Return value:
+ None
+--*/
+{
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PPFH_CALLBACK_POHANDLE_UNAVAILABLE pfhCallbackPoHandleUnavailable;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ if (NULL == devCtx->PoHandle) {
+ //
+ // We didn't successfully register with the power framework, so nothing
+ // to do here.
+ //
+ return;
+ }
+
+ //
+ // Notify the driver layer that the POHANDLE is about to be invalidated
+ //
+ pfhCallbackPoHandleUnavailable =
+ devCtx->DeviceInitSettings.PfhCallbackPoHandleUnavailable;
+ if (NULL != pfhCallbackPoHandleUnavailable) {
+ pfhCallbackPoHandleUnavailable(Device, devCtx->PoHandle);
+ }
+
+ //
+ // Unregister with the power framework
+ //
+ PoFxUnregisterDevice(devCtx->PoHandle);
+ devCtx->PoHandle = NULL;
+
+ return;
+}
+
+NTSTATUS
+RegisterWithPowerFrameworkWorker(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine description:
+ This routine registers a device with the power framework.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+Return value:
+ An NTSTATUS value representing success or failure of the function.
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PPFH_CALLBACK_POHANDLE_AVAILABLE pfhCallbackPoHandleAvailable;
+ ULONG i;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ if (NULL != devCtx->PoHandle) {
+ //
+ // Already registered with power framework, nothing to do here.
+ //
+ status = STATUS_SUCCESS;
+ goto exit;
+ }
+
+ for (i=0; i < (devCtx->PoFxDeviceInfo->ComponentCount); i++) {
+ //
+ // Initially, all components are active
+ //
+ devCtx->ComponentInfo[i].IsActive = TRUE;
+
+ //
+ // For PDOs, we unregister when the device is disabled and re-register
+ // when the device is re-enabled. Before re-registering, we need to
+ // start the component queues. They would all be in the purged state
+ // when the device was disabled.
+ // NOTE: It is okay to start an already-started queue, so we can handle
+ // first registration and re-registration in the same way.
+ //
+ if (NULL != devCtx->ComponentInfo[i].Queue) {
+ WdfIoQueueStart(devCtx->ComponentInfo[i].Queue);
+ }
+ }
+
+ //
+ // Register with the power framework
+ //
+ status = PoFxRegisterDevice(
+ WdfDeviceWdmGetPhysicalDevice(Device),
+ devCtx->PoFxDeviceInfo,
+ &(devCtx->PoHandle)
+ );
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PoFxRegisterDevice failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // Notify the driver layer that the POHANDLE is available
+ //
+ pfhCallbackPoHandleAvailable =
+ devCtx->DeviceInitSettings.PfhCallbackPoHandleAvailable;
+ if (NULL != pfhCallbackPoHandleAvailable) {
+ status = pfhCallbackPoHandleAvailable(Device, devCtx->PoHandle);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+ }
+
+ //
+ // Tell the power framework to start its power management
+ //
+ PoFxStartDevicePowerManagement(devCtx->PoHandle);
+
+ status = STATUS_SUCCESS;
+
+exit:
+ if (FALSE == NT_SUCCESS(status)) {
+ //
+ // If an error occurred, we need to unregister with the power framework.
+ // Note: the function below handles the case where we haven't registered
+ // yet.
+ //
+ UnregisterWithPowerFrameworkWorker(Device);
+ }
+ return status;
+}
+
+NTSTATUS
+_PfhEvtSelfManagedIoInit(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine Description:
+
+ In this routine, we initialize self-managed I/O operations.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+Return Value:
+
+ An NTSTATUS value representing success or failure of the function.
+
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT evtDeviceSelfManagedIoInit;
+
+ PAGED_CODE();
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ //
+ // If the driver layer supplied a self-managed-IO-init callback, invoke it.
+ // We need to do this before checking if power framework settings are
+ // available so that the driver has the opportunity to specify power
+ // framework settings in the self-managed-IO-init callback.
+ //
+ evtDeviceSelfManagedIoInit =
+ devCtx->DeviceInitSettings.EvtDeviceSelfManagedIoInit;
+ if (NULL != evtDeviceSelfManagedIoInit) {
+ status = evtDeviceSelfManagedIoInit(Device);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+ }
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // If S0-idle power management is supported, prevent the device from
+ // powering down to Dx due to S0-idle. We will allow the device to power
+ // down to Dx only after our device-power-not-required callback is invoked.
+ //
+ STOP_DEVICE_IDLE_ON_DEVICE_START(status, Device, devCtx, exit);
+
+ //
+ // Register with the power framework.
+ //
+ // The EvtDeviceSelfManagedIoInit callback is called after the first D0
+ // entry, but not after subsequent D0 entries. This means that it is not
+ // called after D0 entries that occur due to S0-idle, system resuming from
+ // sleep or resource rebalance. Therefore, we register with the power
+ // framework here. We retain the registration until the device is removed.
+ //
+ // Note: The function below handles the case where the driver layer already
+ // registered with the power framework by calling
+ // PfhRegisterDeviceProactive.
+ //
+ status = RegisterWithPowerFrameworkWorker(Device);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+VOID
+_PfhEvtSelfManagedIoFlush(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine Description:
+
+ In this routine, we flush self-managed I/O operations.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+Return Value:
+
+ None
+
+--*/
+{
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH evtDeviceSelfManagedIoFlush;
+
+ PAGED_CODE();
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p.",
+ Device);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ if (devCtx->ShouldReportDevicePoweredOn) {
+ //
+ // We received an S0 IRP and we were supposed to call
+ // PoFxReportDevicePoweredOn after entering D0 in response to the S0
+ // IRP. But an error occurred that prevented us from entering D0 and
+ // KMDF has initiated a device teardown as a result of this error.
+ // Before we attempt to unregister with the power framework, we should
+ // call PoFxReportDevicePoweredOn in order to bring the power framework
+ // to a consistent state.
+ //
+ devCtx->ShouldReportDevicePoweredOn = FALSE;
+ PoFxReportDevicePoweredOn(devCtx->PoHandle);
+ }
+
+ //
+ // The EvtDeviceSelfManagedIoFlush callback is called when the device is
+ // being removed. In this callback, we unregister with the power framework.
+ // Note: the function below handles the case where we did not register
+ // successfully.
+ //
+ UnregisterWithPowerFrameworkWorker(Device);
+
+ //
+ // Perform tasks specific to S0-idle power management (if enabled)
+ //
+ SELF_MANAGED_IO_FLUSH_FOR_S0_IDLE(devCtx);
+
+ //
+ // If the driver layer supplied a self-managed-IO-flush callback, invoke it
+ //
+ evtDeviceSelfManagedIoFlush =
+ devCtx->DeviceInitSettings.EvtDeviceSelfManagedIoFlush;
+ if (NULL != evtDeviceSelfManagedIoFlush) {
+ evtDeviceSelfManagedIoFlush(Device);
+ }
+
+ return;
+}
+
+BOOLEAN
+IsS0Irp(
+ _In_ PIRP Irp,
+ _In_ BOOLEAN StackLocationAdjusted
+ )
+/*++
+Routine description:
+ This routine determines whether the given IRP is an S0 IRP.
+
+Arguments:
+ Irp - Pointer to the IRP
+
+ StackLocationAdjusted - A BOOLEAN value that indicates whether or not the
+ IRP's stack location has already been adjusted for forwarding to the
+ next layer in the device stack. If TRUE, it means that the IRP stack
+ location has already been adjusted and this routine must use the next
+ IRP stack location. If FALSE, it means that the IRP stack location has
+ not yet been adjusted and this routine must use the previous IRP stack
+ location.
+
+Return value:
+ TRUE if the IRP is an S0 IRP, FALSE otherwise
+--*/
+{
+ PIO_STACK_LOCATION stackLoc;
+
+ if (StackLocationAdjusted) {
+ stackLoc = IoGetNextIrpStackLocation(Irp);
+ } else {
+ stackLoc = IoGetCurrentIrpStackLocation(Irp);
+ }
+
+ if ((IRP_MJ_POWER == stackLoc->MajorFunction) &&
+ (IRP_MN_SET_POWER == stackLoc->MinorFunction) &&
+ (SystemPowerState == stackLoc->Parameters.Power.Type) &&
+ (PowerSystemWorking == stackLoc->Parameters.Power.State.SystemState)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+NTSTATUS
+PreprocessIrpAndDispatch(
+ _In_ WDFDEVICE Device,
+ _Inout_ PIRP Irp,
+ _In_ BOOLEAN StackLocationAdjusted
+ )
+/*++
+Routine description:
+ This routine pre-processes a power IRP and dispatches it to KMDF.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+ Irp - Pointer to the IRP
+
+ StackLocationAdjusted - A BOOLEAN value that indicates whether or not the
+ IRP's stack location has already been adjusted for forwarding to the
+ next layer in the device stack. If TRUE, it means that the IRP stack
+ location has already been adjusted and this routine must use the next
+ IRP stack location. If FALSE, it means that the IRP stack location has
+ not yet been adjusted and this routine must use the previous IRP stack
+ location.
+
+Return value:
+ The NTSTATUS value that is returned from the
+ WdfDeviceWdmDispatchPreprocessedIrp call made by this routine to dispatch
+ the IRP to KMDF.
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+
+ if (IsS0Irp(Irp, StackLocationAdjusted)) {
+ //
+ // We have received an S0 IRP. The power framework requires that we call
+ // PoFxReportDevicePoweredOn after we have returned to D0 as a result of
+ // receiving an S0 IRP. Therefore, we make a note in our device context
+ // that we need to call PoFxReportDevicePoweredOn from our next
+ // EvtDeviceD0Entry callback.
+ //
+ devCtx = HelperGetDeviceContext(Device);
+ devCtx->ShouldReportDevicePoweredOn = TRUE;
+ }
+
+ //
+ // Forward the IRP for KMDF to handle
+ //
+ if (FALSE == StackLocationAdjusted) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ }
+ status = WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
+
+ return status;
+}
+
+NTSTATUS
+_PfhEvtWdmPowerIrpPreprocess(
+ _In_ WDFDEVICE Device,
+ _Inout_ PIRP Irp
+ )
+/*++
+Routine description:
+ This routine receives power IRPs before KMDF has processed them. It pre-
+ processes the power IRP before eventually forwarding it to KMDF.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+ Irp - Pointer to the IRP
+
+Return value:
+ If the driver layer is not interested in pre-processing the IRP, the return
+ value is the NTSTATUS value that is returned from the
+ WdfDeviceWdmDispatchPreprocessedIrp call made by this routine to dispatch
+ the IRP to KMDF.
+
+ If the driver layer is interested in pre-processing the IRP, the return
+ value is the NTSTATUS value that is returned by the driver layer's WDM pre-
+ process routine for this IRP.
+--*/
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION stackLoc;
+ UCHAR minorFunction;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ BOOLEAN invokeDriverLayerCallback = FALSE;
+ ULONG i;
+ PFN_WDFDEVICE_WDM_IRP_PREPROCESS evtDeviceWdmPowerIrpPreprocess = NULL;
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p.",
+ Device);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Get the minor function
+ //
+ stackLoc = IoGetCurrentIrpStackLocation(Irp);
+ minorFunction = stackLoc->MinorFunction;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ //
+ // Check if the driver layer is interested in pre-processing an IRP with
+ // this minor function code.
+ //
+ for (i=0;
+ i < devCtx->DriverLayerPowerIrpPreprocessInfo->NumMinorFunctions;
+ i++) {
+
+ if (minorFunction ==
+ devCtx->DriverLayerPowerIrpPreprocessInfo->MinorFunctions[i]) {
+ //
+ // The driver layer is interested in this minor function code
+ //
+ invokeDriverLayerCallback = TRUE;
+ break;
+ }
+ }
+
+ if (invokeDriverLayerCallback) {
+ //
+ // Invoke the driver layer's callback. After the driver layer has
+ // pre-processed the IRP, it will call
+ // PfhWdmDispatchPreprocessedPowerIrp. We will pre-process the IRP
+ // at that time.
+ //
+ evtDeviceWdmPowerIrpPreprocess =
+ devCtx->DeviceInitSettings.EvtDeviceWdmPowerIrpPreprocess;
+ ASSERT(NULL != evtDeviceWdmPowerIrpPreprocess);
+
+ status = evtDeviceWdmPowerIrpPreprocess(Device, Irp);
+
+ } else {
+ //
+ // Preprocess IRP and dispatch to KMDF
+ //
+ status = PreprocessIrpAndDispatch(Device,
+ Irp,
+ FALSE /* StackLocationAdjusted */);
+ }
+
+ return status;
+}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+PfhWdmDispatchPreprocessedPowerIrp(
+ _In_ WDFDEVICE Device,
+ _Inout_ PIRP Irp
+ )
+// See comments in WdfPoFx.h
+{
+ PIO_STACK_LOCATION stackLoc;
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p.",
+ Device);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Verify that this is a power IRP
+ //
+ stackLoc = IoGetNextIrpStackLocation(Irp);
+ if (IRP_MJ_POWER != stackLoc->MajorFunction) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhWdmDispatchPreprocessedPowerIrp must be called "
+ "for power IRPs only. It has been called for IRP %p, which is not"
+ " a power IRP.",
+ Irp);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // The driver layer would have already adjusted the stack location for KMDF
+ //
+ return PreprocessIrpAndDispatch(Device,
+ Irp,
+ TRUE /* StackLocationAdjusted */);
+}
+
+NTSTATUS
+_PfhEvtD0Entry(
+ _In_ WDFDEVICE Device,
+ _In_ WDF_POWER_DEVICE_STATE PreviousState
+ )
+/*++
+Routine Description:
+
+ In this routine, we perform operations that are needed when the device
+ enters the D0 power state.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+ PreviousState - A WDF_POWER_DEVICE_STATE-typed enumerator that identifies
+ the previous device power state.
+
+Return Value:
+
+ An NTSTATUS value representing success or failure of the function.
+
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ PFN_WDF_DEVICE_D0_ENTRY evtDeviceD0Entry;
+
+ if (FALSE == IsDeviceInitialized(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializeDeviceSettings has not yet been "
+ "called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ //
+ // If the driver layer supplied a D0Entry callback, invoke it
+ //
+ evtDeviceD0Entry = devCtx->DeviceInitSettings.EvtDeviceD0Entry;
+ if (NULL != evtDeviceD0Entry) {
+ status = evtDeviceD0Entry(Device, PreviousState);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+ }
+
+ if (devCtx->ShouldReportDevicePoweredOn) {
+ //
+ // This is the first time we are entering D0 after receiving an S0 IRP.
+ // We should call PoFxReportDevicePoweredOn.
+ //
+ devCtx->ShouldReportDevicePoweredOn = FALSE;
+ PoFxReportDevicePoweredOn(devCtx->PoHandle);
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+
+ return status;
+}
+
+NTSTATUS
+_PfhEvtSelfManagedIoRestart(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine Description:
+
+ In this routine, we restart self-managed I/O operations.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+Return Value:
+
+ An NTSTATUS value representing success or failure of the function.
+
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART evtDeviceSelfManagedIoRestart;
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ //
+ // If the driver layer supplied a self-managed-IO-restart callback, invoke
+ // it
+ //
+ evtDeviceSelfManagedIoRestart =
+ devCtx->DeviceInitSettings.EvtDeviceSelfManagedIoRestart;
+ if (NULL != evtDeviceSelfManagedIoRestart) {
+ status = evtDeviceSelfManagedIoRestart(Device);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+ }
+
+ //
+ // For a PDO, if this is the first start after the device was disabled and
+ // if S0-idle power management is supported for the device, then we prevent
+ // the device from powering down to Dx due to S0-idle. We will allow the
+ // device to power down to Dx only after our device-power-not-required
+ // callback is invoked.
+ //
+ // NOTE: The function below figures out whether this is the first start
+ // after the device was disabled and does the right thing based on that.
+ //
+ STOP_DEVICE_IDLE_ON_DEVICE_START(status, Device, devCtx, exit);
+
+ //
+ // For a PDO, we need to register with the power framework in the
+ // self-managed-IO-restart callback if the device was disabled and then
+ // re-enabled. In this case, we would have unregistered with the power
+ // framework in the self-managed-IO-flush callback. Therefore, we need to
+ // re-register now.
+ //
+ // NOTE: The function below handles the case where we are already registered
+ // with the power framework.
+ //
+ status = RegisterWithPowerFrameworkWorker(Device);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+VOID
+_PfhDevicePowerRequiredCallback(
+ _In_ PVOID Context
+ )
+/*++
+Routine Description:
+
+ The power framework invokes this routine to notify us that we need to
+ enter/remain in the D0 state
+
+Arguments:
+
+ Context - Context that we passed in to the power framework
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+
+ //
+ // Get the handle to the KMDF device object
+ //
+ device = (WDFDEVICE) Context;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Perform actions specific to S0-idle power management (if enabled)
+ //
+ DEVICE_POWER_REQUIRED_FOR_S0_IDLE(device, devCtx);
+ return;
+}
+
+VOID
+_PfhDevicePowerNotRequiredCallback(
+ _In_ PVOID Context
+ )
+/*++
+Routine Description:
+
+ The power framework invokes this routine to notify us that we may enter
+ a low-power Dx state
+
+Arguments:
+
+ Context - Context that we passed in to the power framework
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+
+ //
+ // Get the handle to the KMDF device object
+ //
+ device = (WDFDEVICE) Context;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Perform actions specific to S0-idle power management (if enabled)
+ //
+ DEVICE_POWER_NOT_REQUIRED_FOR_S0_IDLE(device, devCtx);
+
+ //
+ // Tell the power framework that we've finished processing device-power-
+ // not-required
+ //
+ PoFxCompleteDevicePowerNotRequired(devCtx->PoHandle);
+
+ return;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PfhRegisterDeviceProactive(
+ _In_ WDFDEVICE Device
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ PPOFX_DEVICE_CONTEXT devCtx;
+
+ if (FALSE == ArePowerFrameworkSettingsAvailable(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet "
+ "been called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ if (NULL != devCtx->PoHandle) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhRegisterDeviceProactive was called when the "
+ "device was already registered with the power framework. "
+ "%!status!.",
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ status = RegisterWithPowerFrameworkWorker(Device);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}