summaryrefslogtreecommitdiff
path: root/pofx/WDF/Driver/MultiComp/lib
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
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'pofx/WDF/Driver/MultiComp/lib')
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj183
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters35
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/WdfPoFxPriv.h382
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/component.c562
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/device.c868
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/init.c1336
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/s0idle.c471
-rw-r--r--pofx/WDF/Driver/MultiComp/lib/s0idle.h113
8 files changed, 3950 insertions, 0 deletions
diff --git a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj
new file mode 100644
index 00000000..ec187a39
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{21F832DD-6A4C-4E5F-941E-15BF98CE4137}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{568CF874-EF69-46EF-AAE1-E59FAE847FBA}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="init.c; device.c; component.c; s0idle.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppScanConfigurationData>WdfPoFxPriv.h</WppScanConfigurationData>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>WdfPoFx</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>WdfPoFx</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>WdfPoFx</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>WdfPoFx</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);PFH_S0IDLE_SUPPORTED=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters
new file mode 100644
index 00000000..50376050
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/WdfPoFx.vcxproj.Filters
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{A155D773-8FFA-4E28-9C42-A363BDD03866}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{7CBF3FE5-FDC1-4483-B02B-EDCEEAF60743}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{D4BDD463-7BCE-4779-856D-4D42D6FBB5E1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{29D299CC-0D9F-4BB4-8E92-8A1E35E7A85E}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="component.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="init.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="s0idle.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/pofx/WDF/Driver/MultiComp/lib/WdfPoFxPriv.h b/pofx/WDF/Driver/MultiComp/lib/WdfPoFxPriv.h
new file mode 100644
index 00000000..6e294572
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/WdfPoFxPriv.h
@@ -0,0 +1,382 @@
+/*++
+
+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:
+
+ WdfPoFxPriv.h
+
+Abstract:
+ Private header file for the power framework helper library. Contains
+ structures and function headers that are used by various source files in the
+ library.
+
+Environment:
+
+ Kernel mode
+
+--*/
+#if !defined(_WDFPOFXPRIV_H_)
+#define _WDFPOFXPRIV_H_
+
+#include <ntddk.h>
+#include <ntintsafe.h>
+#include "WdfPoFx.h"
+
+#define DO_NOTHING() (0)
+
+//
+// The following structure is used to capture the driver layer's settings for a
+// device
+//
+typedef struct _HELPER_DEVICE_INIT {
+ //
+ // KMDF callbacks registered by the driver layer. The power framework helper
+ // library invokes these callbacks when KMDF invokes that corresponding
+ // callback that the library has registered.
+ //
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit;
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush;
+ PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart;
+ PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry;
+
+ //
+ // Callbacks that notify the driver layer about registration and
+ // unregistration with the power framework. The power framework helper
+ // library invokes these callbacks after registering with the power
+ // framework and before unregistering from the power framework.
+ //
+ PPFH_CALLBACK_POHANDLE_AVAILABLE PfhCallbackPoHandleAvailable;
+ PPFH_CALLBACK_POHANDLE_UNAVAILABLE PfhCallbackPoHandleUnavailable;
+
+ //
+ // The driver layer's WDM pre-process callback for power IRPs. The power
+ // framework helper library invokes this callback when KMDF invokes the
+ // corresponding callback that the library has registered.
+ //
+ PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmPowerIrpPreprocess;
+
+ //
+ // Memory object containing the array of power IRP minor functions that the
+ // driver layer is interested in preprocessing.
+ //
+ WDFMEMORY PowerIrpPreprocessMinorFunctions;
+
+ //
+ // The following members track the status of the initialization performed by
+ // the driver layer for a given device. They are used in verification.
+ //
+ BOOLEAN PnpPowerEventCallbacksIntercepted;
+ BOOLEAN PoHandleAvailabilityCallbacksSet;
+ BOOLEAN PowerIrpPreprocessCallbackAssigned;
+#if PFH_S0IDLE_SUPPORTED
+ BOOLEAN S0IdleConfigSet;
+
+ //
+ // The driver's S0-idle configuration
+ //
+ PFH_S0IDLE_CONFIG S0IdleConfig;
+#endif
+
+} HELPER_DEVICE_INIT, *PHELPER_DEVICE_INIT;
+
+//
+// The following structure is used to capture the driver layer's settings for a
+// component queue
+//
+typedef struct _HELPER_QUEUE_INIT {
+ //
+ // Component number of the component that the queue is associated with
+ //
+ ULONG Component;
+
+ //
+ // The driver layer's EvtIoCanceledOnQueue callback for the component queue.
+ // The power framework helper library invokes this callback when KMDF
+ // invokes the corresponding callback that the library has registered.
+ //
+ PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue;
+
+ //
+ // The following members track the status of the initialization performed by
+ // the driver layer for a given queue. They are used in verification.
+ //
+ BOOLEAN ComponentQueueConfigIntercepted;
+ BOOLEAN ComponentSet;
+} HELPER_QUEUE_INIT, *PHELPER_QUEUE_INIT;
+
+//
+// Enumeration of KMDF objects that can be initialized using the power framework
+// helper library's initializer object.
+//
+typedef enum _HELPER_INIT_TYPE {
+ HelperInitTypeNone,
+ HelperInitTypeDevice,
+ HelperInitTypeQueue,
+} HELPER_INIT_TYPE, *PHELPER_INIT_TYPE;
+
+//
+// The following structure represents the object context space for the power
+// framework helper library's initializer object.
+//
+typedef struct _HELPER_INIT {
+ //
+ // Type of KMDF object being initialized using the power framework helper
+ // library's initializer object.
+ //
+ HELPER_INIT_TYPE InitType;
+ union {
+ //
+ // Driver layer's device initialization settings
+ //
+ HELPER_DEVICE_INIT DeviceInit;
+
+ //
+ // Driver layer's queue initialization settings
+ //
+ HELPER_QUEUE_INIT QueueInit;
+ } u;
+} HELPER_INIT, *PHELPER_INIT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HELPER_INIT,
+ HelperGetInitContext)
+
+//
+// The following structure represents the array of power IRP minor functions
+// that the driver layer is interested in preprocessing
+//
+#pragma warning(push)
+#pragma warning(disable:4200)
+typedef struct _POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO {
+ //
+ // Number of power IRP minor functions that the driver layer is interested
+ // in preprocessing
+ //
+ ULONG NumMinorFunctions;
+
+ //
+ // Array of power IRP minor functions that the driver layer is interested in
+ // preprocessing
+ //
+ UCHAR MinorFunctions[];
+} POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO,
+ *PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO;
+#pragma warning(pop)
+
+//
+// Per-component information maintained by the power framework helper library
+//
+typedef struct _POFX_COMPONENT_INFO {
+ //
+ // Queue associated with the component
+ //
+ WDFQUEUE Queue;
+
+ //
+ // Whether or not the component is active
+ //
+ BOOLEAN IsActive;
+} POFX_COMPONENT_INFO, *PPOFX_COMPONENT_INFO;
+
+//
+// The following structure represents the driver layer's power framework
+// callbacks. The power framework helper library invokes these callbacks when
+// the power framework invokes the corresponding callbacks that the library has
+// registered.
+//
+typedef struct _POFX_DRIVER_LAYER_POWER_CALLBACKS {
+ PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback;
+ PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback;
+ PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback;
+ PPO_FX_DEVICE_POWER_REQUIRED_CALLBACK DevicePowerRequiredCallback;
+ PPO_FX_DEVICE_POWER_NOT_REQUIRED_CALLBACK DevicePowerNotRequiredCallback;
+} POFX_DRIVER_LAYER_POWER_CALLBACKS, *PPOFX_DRIVER_LAYER_POWER_CALLBACKS;
+
+//
+// The following structure represents the power framework helper library's
+// device context space.
+//
+typedef struct _POFX_DEVICE_CONTEXT {
+ //
+ // Pointer to the power framework settings registered by the power framework
+ // helper library
+ //
+ PPO_FX_DEVICE PoFxDeviceInfo;
+
+ //
+ // Pointer to the driver layer's power framework callbacks
+ //
+ POFX_DRIVER_LAYER_POWER_CALLBACKS DriverLayerPoFxCallbacks;
+
+ //
+ // Pointer to the driver layer's context for power framework callbacks
+ //
+ PVOID DriverLayerPoFxContext;
+
+ //
+ // Pointer to the information that is tracked by the power framework helper
+ // library for each component
+ //
+ PPOFX_COMPONENT_INFO ComponentInfo;
+
+ //
+ // POHANDLE representing the registration with the power framework
+ //
+ POHANDLE PoHandle;
+
+ //
+ // Array of power IRP minor functions that the driver layer is interested in
+ // preprocessing.
+ //
+ PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO
+ DriverLayerPowerIrpPreprocessInfo;
+
+ //
+ // The driver layer's settings for the device
+ //
+ HELPER_DEVICE_INIT DeviceInitSettings;
+
+ //
+ // Whether or not we should call PoFxReportDevicePoweredOn from our next
+ // EvtDeviceD0Entry callback
+ //
+ BOOLEAN ShouldReportDevicePoweredOn;
+
+#if PFH_S0IDLE_SUPPORTED
+ //
+ // Whether or not we invoked WdfDeviceStopIdle during device start so that
+ // the device remains in D0 until the power framework permits it to go to Dx
+ //
+ BOOLEAN StopIdleInvokedOnDeviceStart;
+
+ //
+ // Work item that is queued in response to device-power-required callback.
+ // When the work item callback is invoked, we make a blocking call to
+ // WdfDeviceStopIdle in order to bring the device to D0. This blocking call
+ // cannot be made within the device-power-required callback because it can
+ // be invoked at dispatch level. Therefore, we make this call at passive
+ // level from a work item callback.
+ //
+ WDFWORKITEM PowerRequiredWorkItem;
+#endif
+
+} POFX_DEVICE_CONTEXT, *PPOFX_DEVICE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(POFX_DEVICE_CONTEXT, HelperGetDeviceContext)
+
+//
+// The following structure represents the power framework helper library's
+// component queue context space.
+//
+typedef struct _POFX_QUEUE_CONTEXT {
+ //
+ // The driver layer's settings for the component queue
+ //
+ HELPER_QUEUE_INIT QueueInitSettings;
+} POFX_QUEUE_CONTEXT, *PPOFX_QUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(POFX_QUEUE_CONTEXT, HelperGetQueueContext)
+
+//
+// Power framework helper library's KMDF callbacks
+//
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT _PfhEvtSelfManagedIoInit;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH _PfhEvtSelfManagedIoFlush;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART _PfhEvtSelfManagedIoRestart;
+
+EVT_WDF_DEVICE_D0_ENTRY _PfhEvtD0Entry;
+
+EVT_WDFDEVICE_WDM_IRP_PREPROCESS _PfhEvtWdmPowerIrpPreprocess;
+
+EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE _PfhEvtRequestCanceledOnComponentQueue;
+
+//
+// Power framework helper library's power framework callbacks
+//
+PO_FX_COMPONENT_IDLE_STATE_CALLBACK _PfhComponentIdleStateCallback;
+PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK _PfhComponentActiveConditionCallback;
+PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK _PfhComponentIdleConditionCallback;
+PO_FX_DEVICE_POWER_REQUIRED_CALLBACK _PfhDevicePowerRequiredCallback;
+PO_FX_DEVICE_POWER_NOT_REQUIRED_CALLBACK _PfhDevicePowerNotRequiredCallback;
+
+//
+// Routines used by source files within the power framework helper library
+//
+PHELPER_DEVICE_INIT
+GetDeviceInitSettings(
+ _In_ WDFOBJECT Initializer
+ );
+
+VOID
+UnregisterWithPowerFrameworkWorker(
+ _In_ WDFDEVICE Device
+ );
+
+BOOLEAN
+IsDeviceInitialized(
+ _In_ WDFDEVICE Device
+ );
+
+BOOLEAN
+IsQueueInitialized(
+ _In_ WDFQUEUE Queue
+ );
+
+BOOLEAN
+ArePowerFrameworkSettingsAvailable(
+ _In_ WDFDEVICE Device
+ );
+
+NTSTATUS
+CopyAndUpdateMinorFunctionsArray(
+ _In_ WDFOBJECT Initializer,
+ _In_reads_opt_(NumMinorFunctions) PUCHAR MinorFunctions,
+ _In_ ULONG NumMinorFunctions,
+ _Out_ WDFMEMORY * MinorFunctionsMemory,
+ _Outptr_result_buffer_(*UpdatedNumMinorFunctions) PUCHAR *UpdatedMinorFunctions,
+ _Out_ PULONG UpdatedNumMinorFunctions
+ );
+
+NTSTATUS
+CopyMinorFunctionsArray(
+ _In_ WDFDEVICE Device,
+ _In_ WDFMEMORY SourceMemory,
+ _Out_ WDFMEMORY * DestinationMemory
+ );
+
+#include "s0idle.h"
+
+//
+// Define the tracing flags.
+//
+// The (0,0,0,0,0) GUID below is a dummy. The driver layer's GUID is the one
+// that gets used.
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ WdfPoFxTraceControl, (0,0,0,0,0), \
+ WPP_DEFINE_BIT(WDFPOFX_ALL_INFO) \
+ )
+
+#define WPP_FLAG_LEVEL_LOGGER(flag, level) \
+ WPP_LEVEL_LOGGER(flag)
+
+#define WPP_FLAG_LEVEL_ENABLED(flag, level) \
+ (WPP_LEVEL_ENABLED(flag) && \
+ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC Trace{FLAG=WDFPOFX_ALL_INFO}(LEVEL, MSG, ...);
+// end_wpp
+//
+
+#endif // _WDFPOFXPRIV_H_
diff --git a/pofx/WDF/Driver/MultiComp/lib/component.c b/pofx/WDF/Driver/MultiComp/lib/component.c
new file mode 100644
index 00000000..b0e55f1f
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/component.c
@@ -0,0 +1,562 @@
+/*++
+
+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:
+
+ component.c
+
+Abstract:
+ This module contains routines that implement power management for a
+ component of the device
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "WdfPoFxPriv.h"
+#include "component.tmh"
+
+VOID
+AcquirePowerReferenceForRequest(
+ _In_ WDFQUEUE Queue
+ )
+/*++
+Routine description:
+ This routine acquires a power reference on behalf of a request, if the
+ request is being forwarded to a component queue. If the request is not being
+ forwarded to a component queue, then this routine does nothing.
+
+Arguments:
+ Queue - Handle to the KMDF queue object to which the request is being
+ forwarded
+
+Return value:
+ None
+--*/
+{
+ PPOFX_QUEUE_CONTEXT qCtx = NULL;
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ ULONG component;
+
+ //
+ // Get the queue context
+ //
+ qCtx = HelperGetQueueContext(Queue);
+ if (NULL == qCtx) {
+ //
+ // The request is not being forwarded to a component queue. So there is
+ // no need to take a power reference at this time.
+ //
+ return;
+ }
+
+ //
+ // Get the component on which the power reference needs to be taken
+ //
+ component = qCtx->QueueInitSettings.Component;
+
+ //
+ // Get the device that the queue is associated with
+ //
+ device = WdfIoQueueGetDevice(Queue);
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Take the power reference
+ //
+ PoFxActivateComponent(devCtx->PoHandle, component, 0 /* Flags */);
+ return;
+}
+
+VOID
+ReleasePowerReferenceForRequest(
+ _In_ WDFREQUEST Request
+ )
+/*++
+Routine description:
+ This routine releases a power reference on behalf of a request, if a power
+ reference had been taken previously. If no power reference had been taken
+ previously for this request, then this routine does nothing.
+
+Arguments:
+ Request - Handle to the KMDF request object on behalf of which the power
+ reference needs to be released
+
+Return value:
+ None
+--*/
+{
+ WDFQUEUE queue = NULL;
+ PPOFX_QUEUE_CONTEXT qCtx = NULL;
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ ULONG component;
+
+ //
+ // Get the queue that the request is associated with
+ //
+ queue = WdfRequestGetIoQueue(Request);
+ if (NULL == queue) {
+ return;
+ }
+
+ //
+ // Get the queue context
+ //
+ qCtx = HelperGetQueueContext(queue);
+ if (NULL == qCtx) {
+ //
+ // The request is currently not associated with a component queue. So
+ // no power reference has been taken on behalf of the request and hence
+ // there is no power reference to release at this time.
+ //
+ return;
+ }
+
+ //
+ // Get the component on which the power reference has been taken on behalf
+ // of this request
+ //
+ component = qCtx->QueueInitSettings.Component;
+
+ //
+ // Get the device that the queue is associated with
+ //
+ device = WdfIoQueueGetDevice(queue);
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Release the power reference that was previously taken
+ //
+ PoFxIdleComponent(devCtx->PoHandle, component, 0 /* Flags */);
+
+ return;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+PfhForwardRequestToQueue(
+ _In_ WDFREQUEST Request,
+ _In_ WDFQUEUE Queue
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+
+ //
+ // If the request currently has a power reference on a component, then
+ // release the power reference.
+ //
+ ReleasePowerReferenceForRequest(Request);
+
+ //
+ // If the destination queue requires a power reference on a component, then
+ // take the power reference now.
+ //
+ AcquirePowerReferenceForRequest(Queue);
+
+ //
+ // Queue the request to the caller-specified queue
+ //
+ status = WdfRequestForwardToIoQueue(Request, Queue);
+ if (FALSE == NT_SUCCESS(status)) {
+ //
+ // If the queue has not been purged or drained, forwarding a request to
+ // a queue should always succeeded.
+ //
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfRequestForwardToIoQueue failed with %!status!.",
+ status);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ return;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+PfhCompleteRequest(
+ _In_ WDFREQUEST Request,
+ _In_ NTSTATUS Status,
+ _In_ ULONG_PTR Information
+ )
+// See comments in WdfPoFx.h
+{
+ //
+ // If the request currently has a power reference on a component, then
+ // release the power reference.
+ //
+ ReleasePowerReferenceForRequest(Request);
+
+ //
+ // Complete the request
+ //
+ WdfRequestCompleteWithInformation(Request, Status, Information);
+}
+
+VOID
+_PfhEvtRequestCanceledOnComponentQueue(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request
+ )
+/*++
+Routine Description:
+
+ This routine is invoked when an IO request is canceled while it is in a
+ component queue
+
+Arguments:
+
+ Queue - Handle to the framework queue object for the component queue
+
+ Request - Handle to the framework request object for the request being
+ canceled
+
+Return Value:
+
+ None
+
+--*/
+{
+ PPOFX_QUEUE_CONTEXT qCtx = NULL;
+ PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE evtIoCanceledOnQueue;
+
+ if (FALSE == IsQueueInitialized(Queue)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializeComponentQueueSettings has not yet been "
+ "called for WDFQUEUE %p.",
+ Queue);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Get the queue context
+ //
+ qCtx = HelperGetQueueContext(Queue);
+
+ evtIoCanceledOnQueue = qCtx->QueueInitSettings.EvtIoCanceledOnQueue;
+ if (NULL != evtIoCanceledOnQueue) {
+ //
+ // The driver layer supplied a canceled-on-queue callback, so invoke it
+ //
+ evtIoCanceledOnQueue(Queue, Request);
+
+ } else {
+ //
+ // Just complete the request
+ //
+ PfhCompleteRequest(Request, STATUS_CANCELLED, 0 /* Information */);
+ }
+ return;
+}
+
+VOID
+ComponentActive(
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx,
+ _In_ ULONG Component
+ )
+/*++
+Routine Description:
+
+ In this routine, we perform operations that are needed when a component
+ becomes active.
+
+Arguments:
+
+ DevCtx - Pointer to our context space for the device object
+
+ Component - The component that has become active
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Mark the component as active
+ //
+ DevCtx->ComponentInfo[Component].IsActive = TRUE;
+
+ if (NULL != DevCtx->ComponentInfo[Component].Queue) {
+ //
+ // Start the component-specific queue
+ //
+ WdfIoQueueStart(DevCtx->ComponentInfo[Component].Queue);
+ }
+
+ return;
+}
+
+VOID
+ComponentIdle(
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx,
+ _In_ ULONG Component
+ )
+/*++
+Routine Description:
+
+ In this routine, we perform operations that are needed when a component
+ becomes idle.
+
+Arguments:
+
+ DevCtx - Pointer to our context space for the device object
+
+ Component - The component that has become idle
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG queueRequests;
+
+ //
+ // Mark the component as idle
+ //
+ DevCtx->ComponentInfo[Component].IsActive = FALSE;
+
+ if (NULL != DevCtx->ComponentInfo[Component].Queue) {
+ //
+ // NOTE: Given that the component is idle, there shouldn't be any
+ // outstanding requests sitting in the component queue. There may be
+ // some driver-owned requests, but they would all have dropped their
+ // power references by now and would be about to complete. We also know
+ // that no new requests will get added to the queue while this callback
+ // is running. The reason is described below.
+ //
+ // We do not add any new request to this queue until the
+ // PoFxActivateComponent call for that request has returned. If
+ // PoFxActivateComponent is called on another thread while this callback
+ // is running or about to run, then the power framework makes sure
+ // that PoFxActivateComponent does not return until this callback has
+ // finished running. Therefore we know that no new request would get
+ // added to this queue while we are attempting to stop the queue
+ // within this callback.
+ //
+ WdfIoQueueGetState(DevCtx->ComponentInfo[Component].Queue,
+ &queueRequests,
+ NULL /* DriverRequests */);
+ if (0 != queueRequests) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Expected the queue for component %d to have no "
+ "requests, but there are currently %d requests in the queue.",
+ Component,
+ queueRequests);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Stop the component-specific queue.
+ //
+ // No need for synchronous stop. Given that the component is idle,
+ // there anyway shouldn't be any outstanding requests in sitting in
+ // the queue. As explained above, there can be up to one outstanding
+ // request that is delivered to the driver layer, but that would
+ // also be just about to complete. We stop this queue only to
+ // prevent new requests that get added to the queue from being
+ // dispatched to the driver layer until the component becomes active
+ // again.
+ //
+ WdfIoQueueStop(DevCtx->ComponentInfo[Component].Queue,
+ NULL, // StopComplete
+ NULL // Context
+ );
+ }
+
+ return;
+}
+
+VOID
+_PfhComponentActiveConditionCallback(
+ _In_ PVOID Context,
+ _In_ ULONG Component
+ )
+/*++
+Routine Description:
+
+ The power framework invokes this routine to notify us that one of our
+ components has become active.
+
+Arguments:
+
+ Context - Context that we passed in to the power framework
+
+ Component - Index of component that has become active or idle
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK
+ componentActiveConditionCallback = NULL;
+
+ //
+ // Get the handle to the framework device object
+ //
+ device = (WDFDEVICE) Context;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Component is active
+ //
+ ComponentActive(devCtx, Component);
+
+ //
+ // If the driver layer supplied a component-active-condition callback,
+ // invoke it
+ //
+ componentActiveConditionCallback =
+ devCtx->DriverLayerPoFxCallbacks.ComponentActiveConditionCallback;
+ if (NULL != componentActiveConditionCallback) {
+ componentActiveConditionCallback(devCtx->DriverLayerPoFxContext,
+ Component);
+ }
+
+ return;
+}
+
+VOID
+_PfhComponentIdleConditionCallback(
+ _In_ PVOID Context,
+ _In_ ULONG Component
+ )
+/*++
+Routine Description:
+
+ The power framework invokes this routine to notify us that one of our
+ components has become idle.
+
+Arguments:
+
+ Context - Context that we passed in to the power framework
+
+ Component - Index of component that has become active or idle
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK
+ componentIdleConditionCallback = NULL;
+
+ //
+ // Get the handle to the framework device object
+ //
+ device = (WDFDEVICE) Context;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Component is idle
+ //
+ ComponentIdle(devCtx, Component);
+
+ //
+ // If the driver layer supplied a component-idle-condition callback, invoke
+ // it
+ //
+ componentIdleConditionCallback =
+ devCtx->DriverLayerPoFxCallbacks.ComponentIdleConditionCallback;
+ if (NULL != componentIdleConditionCallback) {
+ componentIdleConditionCallback(devCtx->DriverLayerPoFxContext,
+ Component);
+ } else {
+ //
+ // Complete the transition to idle
+ //
+ PoFxCompleteIdleCondition(devCtx->PoHandle, Component);
+ }
+
+ return;
+}
+
+VOID
+_PfhComponentIdleStateCallback(
+ _In_ PVOID Context,
+ _In_ ULONG Component,
+ _In_ ULONG State
+ )
+/*++
+Routine Description:
+
+ The power framework invokes this routine to change the F-state of one of our
+ components.
+
+Arguments:
+
+ Context - Context that we passed in to the power framework
+
+ Component - Index of component for which the F-state change is to be made
+
+ State - The new F-state to transition the component to
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+ PPO_FX_COMPONENT_IDLE_STATE_CALLBACK componentIdleStateCallback = NULL;
+ //
+ // Get the handle to the framework device object
+ //
+ device = (WDFDEVICE) Context;
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // If the driver layer supplied a component-idle-state callback, invoke it
+ //
+ componentIdleStateCallback =
+ devCtx->DriverLayerPoFxCallbacks.ComponentIdleStateCallback;
+ if (NULL != componentIdleStateCallback) {
+ componentIdleStateCallback(devCtx->DriverLayerPoFxContext,
+ Component,
+ State);
+ } else {
+ //
+ // Complete the idle state transition
+ //
+ PoFxCompleteIdleState(devCtx->PoHandle, Component);
+ }
+}
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;
+}
diff --git a/pofx/WDF/Driver/MultiComp/lib/init.c b/pofx/WDF/Driver/MultiComp/lib/init.c
new file mode 100644
index 00000000..780434b5
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/init.c
@@ -0,0 +1,1336 @@
+/*++
+
+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:
+
+ init.c
+
+Abstract:
+ This module contains routines that are used to initialize the power
+ framework helper library
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "WdfPoFxPriv.h"
+#include "init.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, GetDeviceInitSettings)
+#pragma alloc_text(PAGE, PfhInitializerCreate)
+#pragma alloc_text(PAGE, CopyAndUpdateMinorFunctionsArray)
+#pragma alloc_text(PAGE, PfhAssignWdmPowerIrpPreProcessCallback)
+#pragma alloc_text(PAGE, PfhInterceptWdfPnpPowerEventCallbacks)
+#pragma alloc_text(PAGE, PfhSetPoHandleAvailabilityCallbacks)
+#pragma alloc_text(PAGE, CopyMinorFunctionsArray)
+#pragma alloc_text(PAGE, PfhInitializeDeviceSettings)
+#pragma alloc_text(PAGE, PfhInitializePowerFrameworkSettings)
+#endif
+
+PHELPER_DEVICE_INIT
+GetDeviceInitSettings(
+ _In_ WDFOBJECT Initializer
+ )
+/*++
+Routine description:
+ This routine gets a pointer to the location in the initializer object's
+ context space where we store the driver layer's device object settings.
+
+Arguments:
+ Initializer - Handle to the initializer object that is being used to
+ initialize our device object settings.
+
+Return value:
+ Pointer to a HELPER_DEVICE_INIT structure where the driver layer's device
+ object settings are stored.
+--*/
+{
+ PHELPER_INIT initContext = NULL;
+
+ PAGED_CODE();
+
+ initContext = HelperGetInitContext(Initializer);
+
+ if ((initContext->InitType != HelperInitTypeNone) &&
+ (initContext->InitType != HelperInitTypeDevice)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Cannot get device initialization settings for "
+ "initializer object %p because it is currently being used to "
+ "initialize a different object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ return NULL;
+ }
+
+ if (initContext->InitType == HelperInitTypeNone) {
+ initContext->InitType = HelperInitTypeDevice;
+ }
+
+ return &(initContext->u.DeviceInit);
+}
+
+PHELPER_QUEUE_INIT
+GetQueueInitSettings(
+ _In_ WDFOBJECT Initializer
+ )
+/*++
+Routine description:
+ This routine gets a pointer to the location in the initializer object's
+ context space where we store the driver layer's queue object settings.
+
+Arguments:
+ Initializer - Handle to the initializer object that is being used to
+ initialize our queue object settings.
+
+Return value:
+ Pointer to a HELPER_QUEUE_INIT structure where the driver layer's queue
+ object settings are stored.
+--*/
+{
+ PHELPER_INIT initContext = NULL;
+
+ initContext = HelperGetInitContext(Initializer);
+
+ if ((initContext->InitType != HelperInitTypeNone) &&
+ (initContext->InitType != HelperInitTypeQueue)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Cannot get queue initialization settings for "
+ "initializer object %p because it is currently being used to "
+ "initialize a different object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ return NULL;
+ }
+
+ if (initContext->InitType == HelperInitTypeNone) {
+ initContext->InitType = HelperInitTypeQueue;
+ }
+
+ return &(initContext->u.QueueInit);
+}
+
+BOOLEAN
+IsDeviceInitialized(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine description:
+ This routine determines whether we have initialized our settings for the
+ given device object.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+Return value:
+ TRUE if we have initialized our settings for the device object, FALSE
+ otherwise.
+--*/
+{
+ PPOFX_DEVICE_CONTEXT devCtx;
+ devCtx = HelperGetDeviceContext(Device);
+ return (NULL != devCtx);
+}
+
+BOOLEAN
+ArePowerFrameworkSettingsAvailable(
+ _In_ WDFDEVICE Device
+ )
+/*++
+Routine description:
+ This routine determines whether the driver layer has provided us with its
+ power framework settings for the given device object.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+Return value:
+ TRUE if we the driver layer has provided us with its power framework
+ settings for the device object, FALSE otherwise.
+--*/
+{
+ PPOFX_DEVICE_CONTEXT devCtx;
+ devCtx = HelperGetDeviceContext(Device);
+ return ((NULL != devCtx) && (NULL != devCtx->PoFxDeviceInfo));
+}
+
+BOOLEAN
+IsQueueInitialized(
+ _In_ WDFQUEUE Queue
+ )
+/*++
+Routine description:
+ This routine determines whether we have initialized our settings for the
+ given queue object.
+
+Arguments:
+ Queue - Handle to the KMDF queue object
+
+Return value:
+ TRUE if we have initialized our settings for the queue object, FALSE
+ otherwise.
+--*/
+{
+ PPOFX_QUEUE_CONTEXT qCtx;
+ qCtx = HelperGetQueueContext(Queue);
+ return (NULL != qCtx);
+}
+
+VOID
+ResetInitializer(
+ _In_ WDFOBJECT Initializer
+ )
+/*++
+Routine description:
+ This routine prepares the given initializer object for initializing a new
+ KMDF object.
+
+Arguments:
+ Initializer - Handle to the initializer object
+
+Return value:
+ None
+--*/
+{
+ PHELPER_INIT initContext = NULL;
+
+ //
+ // We want to make sure that when the initializer context is zeroed, the
+ // default S0-idle power management configuration for the device is
+ // PfhS0IdleNotSupported.
+ //
+ C_ASSERT(0 == PfhS0IdleNotSupported);
+
+ //
+ // Reset the initializer context
+ //
+ initContext = HelperGetInitContext(Initializer);
+ RtlZeroMemory(initContext, sizeof(*initContext));
+ initContext->InitType = HelperInitTypeNone;
+
+ return;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PfhInitializerCreate(
+ _Out_ WDFOBJECT * Initializer
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ WDFOBJECT initializer = NULL;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+
+ PAGED_CODE();
+
+ //
+ // Create an initializer object
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, HELPER_INIT);
+ status = WdfObjectCreate(&objectAttributes, &initializer);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfObjectCreate failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // Initialize context
+ //
+ ResetInitializer(initializer);
+
+ *Initializer = initializer;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+NTSTATUS
+CopyAndUpdateMinorFunctionsArray(
+ _In_ WDFOBJECT Initializer,
+ _In_reads_opt_(NumMinorFunctions) PUCHAR MinorFunctions,
+ _In_ ULONG NumMinorFunctions,
+ _Out_ WDFMEMORY * MinorFunctionsMemory,
+ _Outptr_result_buffer_(*UpdatedNumMinorFunctions) PUCHAR *UpdatedMinorFunctions,
+ _Out_ PULONG UpdatedNumMinorFunctions
+ )
+/*++
+Routine description:
+ This routine takes an array of power IRP minor functions and makes a copy of
+ it. If the input array does not include IRP_MN_SET_POWER as one of the minor
+ functions, the copy of the array made by this routine is expanded to include
+ IRP_MN_SET_POWER too. This enables us to register a WDM pre-process callback
+ for IRP_MN_SET_POWER, regardless of whether the driver layer is interested
+ in that minor function.
+
+Arguments:
+ Initializer - Handle to the initializer object
+
+ MinorFunctions - Caller-initialized array of minor functions that the driver
+ layer is interested in for the IRP_MJ_POWER major function.
+
+ NumMinorFunctions - The number of minor functions in the MinorFunctions
+ array
+
+ MinorFunctionsMemory - Pointer to a location that receives a handle to the
+ memory object created by this routine to store a copy of the minor
+ functions
+
+ UpdatedMinorFunctions - Pointer to a location that receives an array of
+ minor functions that the driver layer is interested in, plus
+ IRP_MN_SET_POWER if it was not present in the original array
+
+ UpdatedNumMinorFunctions - Pointer to a location that receives the number of
+ minor functions in the UpdatedMinorFunctions array
+
+Return value:
+ An NTSTATUS value representing success or failure of the function.
+--*/
+{
+ NTSTATUS status;
+ BOOLEAN driverLayerPreprocessesSetPower = FALSE;
+ UCHAR setPowerMinorFunction;
+ ULONG i;
+ ULONG driverLayerMinorFunctions = 0;
+ ULONG extraMinorFunctions = 0;
+ ULONG totalMinorFunctions = 0;
+ ULONG totalMinorFunctionsSize = 0;
+ ULONG memorySize = 0;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ WDFMEMORY memory = NULL;
+ PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO memoryBuffer = NULL;
+ ULONG minorFunctionsOffset;
+ ULONG minorFunctionsSize;
+ ULONG extraMinorFunctionOffset;
+
+ PAGED_CODE();
+
+ //
+ // Check if the driver layer needs to preprocess IRP_MN_SET_POWER
+ //
+ if ((NULL != MinorFunctions) && (0 != NumMinorFunctions)) {
+
+ driverLayerMinorFunctions = NumMinorFunctions;
+
+ for (i=0; i < NumMinorFunctions; i++) {
+ if (IRP_MN_SET_POWER == MinorFunctions[i]) {
+ driverLayerPreprocessesSetPower = TRUE;
+ break;
+ }
+ }
+ }
+
+ //
+ // If the driver layer does not preprocess IRP_MN_SET_POWER, then we need to
+ // update the minor functions array with an extra entry for IRP_MN_SET_POWER
+ //
+ extraMinorFunctions = driverLayerPreprocessesSetPower ? 0 : 1;
+
+ //
+ // Allocate memory to store a copy of the minor functions array
+ //
+ status = RtlULongAdd(driverLayerMinorFunctions,
+ extraMinorFunctions,
+ &totalMinorFunctions);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute total minor functions count for "
+ "power IRP preprocessing. RtlUlongAdd failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ ASSERT(totalMinorFunctions > 0);
+
+ status = RtlULongMult(sizeof(MinorFunctions[0]),
+ totalMinorFunctions,
+ &totalMinorFunctionsSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed to store the "
+ "functions array. RtlULongMult failed with %!status!.",
+ status);
+ goto exit;
+ }
+ status = RtlULongAdd(sizeof(POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO),
+ totalMinorFunctionsSize,
+ &memorySize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed to store the "
+ "minor functions array and count. RtlUlongAdd failed with "
+ "%!status!.",
+ status);
+ goto exit;
+ }
+ if (0 == memorySize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to set memorySize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Initializer; // auto-delete when parent
+ // deleted
+ #pragma prefast(suppress:28160, "memorySize > 0")
+ status = WdfMemoryCreate(&objectAttributes,
+ NonPagedPool,
+ 0, // PoolTag
+ memorySize,
+ &memory,
+ (PVOID*) &memoryBuffer);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to allocate memory to store the minor functions"
+ " array and count. WdfMemoryCreate failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // We'll remember only the minor functions that the driver layer is
+ // interested in. If we add IRP_MN_SET_POWER to that list, we won't need to
+ // remember that beyond initialization time.
+ //
+ memoryBuffer->NumMinorFunctions = driverLayerMinorFunctions;
+
+ //
+ // Copy the minor functions array
+ //
+ minorFunctionsOffset =
+ FIELD_OFFSET(POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO, MinorFunctions);
+ minorFunctionsSize = driverLayerMinorFunctions *
+ sizeof(MinorFunctions[0]); // already performed
+ // intsafe math above
+ // won't overflow
+ if (driverLayerMinorFunctions > 0) {
+ if (0 == minorFunctionsSize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to set minorFunctionsSize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+ #pragma prefast(suppress:28160, "minorFunctionsSize > 0")
+ status = WdfMemoryCopyFromBuffer(memory,
+ minorFunctionsOffset,
+ memoryBuffer->MinorFunctions,
+ minorFunctionsSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to copy driver layer's minor functions "
+ "array. WdfMemoryCopyFromBuffer failed with %!status!.",
+ status);
+ goto exit;
+ }
+ }
+
+ if (extraMinorFunctions > 0) {
+
+ ASSERT(extraMinorFunctions == 1);
+
+ //
+ // Add an extra minor function for IRP_MN_SET_POWER since it was not in
+ // the driver layer's list.
+ // NOTE: This minor function is added at the end and is not reflected in
+ // memoryBuffer.NumMinorFunctions.
+ //
+ extraMinorFunctionOffset =
+ minorFunctionsOffset + minorFunctionsSize;// already performed intsafe
+ // math above so this won't
+ // overflow
+ setPowerMinorFunction = IRP_MN_SET_POWER;
+ status = WdfMemoryCopyFromBuffer(memory,
+ extraMinorFunctionOffset,
+ &setPowerMinorFunction,
+ sizeof(setPowerMinorFunction));
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to add an extra minor function "
+ "(IRP_MN_SET_POWER) to the minor functions array. "
+ "WdfMemoryCopyFromBuffer failed with %!status!.",
+ status);
+ goto exit;
+ }
+ }
+
+ *MinorFunctionsMemory = memory;
+ *UpdatedMinorFunctions = memoryBuffer->MinorFunctions;
+ *UpdatedNumMinorFunctions =
+ totalMinorFunctions;// Do not use memoryBuffer.NumMinorFunctions
+ // here because it does not include the extra
+ // minor function that we might have added.
+
+ //
+ // If we added an extra minor function, it is present in the buffer but not
+ // reflected in memoryBuffer.NumMinorFunctions
+ //
+ ASSERT((memoryBuffer->NumMinorFunctions + extraMinorFunctions) ==
+ totalMinorFunctions);
+
+ status = STATUS_SUCCESS;
+
+exit:
+ if (FALSE == NT_SUCCESS(status)) {
+ if (NULL != memory) {
+ WdfObjectDelete(memory);
+ }
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PfhAssignWdmPowerIrpPreProcessCallback(
+ _In_ WDFOBJECT Initializer,
+ _In_ PWDFDEVICE_INIT DeviceInit,
+ _In_opt_ PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmPowerIrpPreprocess,
+ _In_reads_opt_(NumMinorFunctions) PUCHAR MinorFunctions,
+ _In_ ULONG NumMinorFunctions
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ WDFMEMORY minorFunctionsMemory = NULL;
+ ULONG numMinorFunctions = 0;
+ PUCHAR minorFunctions = NULL;
+ PHELPER_DEVICE_INIT deviceInitSettings = NULL;
+
+ PAGED_CODE();
+
+ deviceInitSettings = GetDeviceInitSettings(Initializer);
+
+ if (deviceInitSettings->PowerIrpPreprocessCallbackAssigned) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhAssignWdmPowerIrpPreProcessCallback has already"
+ " been called on initialier %p. It should not be called again "
+ "before the initializer has been used to initialize a KMDF device"
+ " object. %!status!.",
+ Initializer,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Copy the minor functions array and, if needed, update it to include
+ // IRP_MN_SET_POWER.
+ //
+ status = CopyAndUpdateMinorFunctionsArray(Initializer,
+ MinorFunctions,
+ NumMinorFunctions,
+ &minorFunctionsMemory,
+ &minorFunctions,
+ &numMinorFunctions);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ //
+ // Assign the WDM preprocess callback
+ //
+ status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
+ DeviceInit,
+ _PfhEvtWdmPowerIrpPreprocess,
+ IRP_MJ_POWER,
+ minorFunctions,
+ numMinorFunctions
+ );
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfDeviceInitAssignWdmIrpPreprocessCallback failed "
+ "with %!status!.",
+ status);
+ goto exit;
+ }
+
+ deviceInitSettings->PowerIrpPreprocessMinorFunctions = minorFunctionsMemory;
+ deviceInitSettings->EvtDeviceWdmPowerIrpPreprocess =
+ EvtDeviceWdmPowerIrpPreprocess;
+ deviceInitSettings->PowerIrpPreprocessCallbackAssigned = TRUE;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ if (FALSE == NT_SUCCESS(status)) {
+ if (NULL != minorFunctionsMemory) {
+ WdfObjectDelete(minorFunctionsMemory);
+ }
+ }
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+PfhInterceptWdfPnpPowerEventCallbacks(
+ _In_ WDFOBJECT Initializer,
+ _Inout_ PWDF_PNPPOWER_EVENT_CALLBACKS DriverLayerPnpPowerCallbacks
+ )
+// See comments in WdfPoFx.h
+{
+ PHELPER_DEVICE_INIT deviceInitSettings = NULL;
+
+ PAGED_CODE();
+
+ deviceInitSettings = GetDeviceInitSettings(Initializer);
+
+ if (deviceInitSettings->PnpPowerEventCallbacksIntercepted) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInterceptWdfPnpPowerEventCallbacks has already been"
+ " called on initialier %p. It should not be called again before "
+ "the initializer has been used to initialize a KMDF device "
+ "object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Save the driver layer's callbacks that we are going to replace
+ //
+ deviceInitSettings->EvtDeviceSelfManagedIoInit =
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoInit;
+ deviceInitSettings->EvtDeviceSelfManagedIoFlush =
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoFlush;
+ deviceInitSettings->EvtDeviceSelfManagedIoRestart =
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoRestart;
+ deviceInitSettings->EvtDeviceD0Entry =
+ DriverLayerPnpPowerCallbacks->EvtDeviceD0Entry;
+
+ //
+ // Replace the driver layer's callbacks with our own
+ //
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoInit =
+ _PfhEvtSelfManagedIoInit;
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoFlush =
+ _PfhEvtSelfManagedIoFlush;
+ DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoRestart =
+ _PfhEvtSelfManagedIoRestart;
+ DriverLayerPnpPowerCallbacks->EvtDeviceD0Entry =
+ _PfhEvtD0Entry;
+
+ deviceInitSettings->PnpPowerEventCallbacksIntercepted = TRUE;
+
+ return;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+PfhSetPoHandleAvailabilityCallbacks(
+ _In_ WDFOBJECT Initializer,
+ _In_ PPFH_CALLBACK_POHANDLE_AVAILABLE PfhCallbackPoHandleAvailable,
+ _In_ PPFH_CALLBACK_POHANDLE_UNAVAILABLE PfhCallbackPoHandleUnavailable
+ )
+// See comments in WdfPoFx.h
+{
+ PHELPER_DEVICE_INIT deviceInitSettings = NULL;
+
+ PAGED_CODE();
+
+ deviceInitSettings = GetDeviceInitSettings(Initializer);
+
+ if (deviceInitSettings->PoHandleAvailabilityCallbacksSet) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhSetPoHandleAvailabilityCallbacks has already been "
+ "called on initialier %p. It should not be called again before "
+ "the initializer has been used to initialize a KMDF device "
+ "object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Save the driver layer's callbacks
+ //
+ deviceInitSettings->PfhCallbackPoHandleAvailable =
+ PfhCallbackPoHandleAvailable;
+ deviceInitSettings->PfhCallbackPoHandleUnavailable =
+ PfhCallbackPoHandleUnavailable;
+
+ deviceInitSettings->PoHandleAvailabilityCallbacksSet = TRUE;
+ return;
+}
+
+NTSTATUS
+CopyMinorFunctionsArray(
+ _In_ WDFDEVICE Device,
+ _In_ WDFMEMORY SourceMemory,
+ _Out_ WDFMEMORY * DestinationMemory
+ )
+/*++
+Routine description:
+ This routine creates a new memory object to store the array of power IRP
+ minor functions that the driver layer is interested in. The array is
+ currently stored in a memory object that we had created as a child of the
+ initializer object that was being used to initialize the device object. Now
+ that the initialization of the device object is about to complete, we need
+ to make a copy of the contents of that memory object. Once the device object
+ initialization is complete, the driver layer is free to delete the
+ initializer object, which will result in the original memory object also
+ getting delete. That is why we copy the contents to a new memory object.
+
+Arguments:
+ Device - Handle to the KMDF device object
+
+ SourceMemory - Handle to the memory object that contains the array of power
+ IRP minor functions that the driver layer is interested in
+
+ DestinationMemory - Pointer to a location that receives a handle to a new
+ memory object created by this routine. The new memory object contains a
+ copy of the a
+
+Return value:
+ An NTSTATUS value representing success or failure of the function.
+--*/
+{
+ NTSTATUS status;
+ PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO powerIrpPreprocessInfo = NULL;
+ size_t powerIrpPreprocessInfoSize;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ WDFMEMORY memory = NULL;
+
+ PAGED_CODE();
+
+ //
+ // Get the source memory buffer
+ //
+ powerIrpPreprocessInfo = WdfMemoryGetBuffer(SourceMemory,
+ &powerIrpPreprocessInfoSize);
+ if (0 == powerIrpPreprocessInfoSize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to get powerIrpPreprocessInfoSize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // Create a new memory object to hold a copy of the buffer
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Device; // auto-delete when parent deleted
+ status = WdfMemoryCreate(&objectAttributes,
+ NonPagedPool,
+ 0, // PoolTag
+ powerIrpPreprocessInfoSize,
+ &memory,
+ NULL // Buffer
+ );
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to allocate memory for the driver layer's minor"
+ " functions array. WdfMemoryCreate failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // Copy the buffer into the new memory object
+ //
+ status = WdfMemoryCopyFromBuffer(memory,
+ 0, // DestinationOffset
+ powerIrpPreprocessInfo,
+ powerIrpPreprocessInfoSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ *DestinationMemory = memory;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PfhInitializeDeviceSettings(
+ _In_ WDFDEVICE Device,
+ _In_ WDFOBJECT Initializer
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PHELPER_DEVICE_INIT deviceInitSettings = NULL;
+ WDFMEMORY memory = NULL;
+
+ PAGED_CODE();
+
+ deviceInitSettings = GetDeviceInitSettings(Initializer);
+
+ if (IsDeviceInitialized(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializeDeviceSettings has already been called "
+ "for WDFDEVICE %p. It should not be called again. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ if (FALSE == deviceInitSettings->PowerIrpPreprocessCallbackAssigned) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhAssignWdmPowerIrpPreProcessCallback has not yet "
+ "been called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ if (FALSE == deviceInitSettings->PnpPowerEventCallbacksIntercepted) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInterceptWdfPnpPowerEventCallbacks has not yet been"
+ " called for WDFDEVICE %p. %!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Allocate our context for this device
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes,
+ POFX_DEVICE_CONTEXT);
+ status = WdfObjectAllocateContext((WDFOBJECT) Device,
+ &objectAttributes,
+ (PVOID*) &devCtx);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfObjectAllocateContext failed with %!status!",
+ status);
+ goto exit;
+ }
+
+ //
+ // Copy the device init settings
+ //
+ devCtx->DeviceInitSettings = *deviceInitSettings;
+
+ //
+ // Copy the minor functions array into a new memory object that is a child
+ // of the device object. The array is currently in a memory object that is
+ // a child of the initializer object. The initializer object can be deleted
+ // by the driver layer any time after initialization is complete, so we need
+ // to make a copy now.
+ //
+ status = CopyMinorFunctionsArray(
+ Device,
+ devCtx->DeviceInitSettings.PowerIrpPreprocessMinorFunctions,
+ &memory
+ );
+ if (FALSE == NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ //
+ // Perform initialization specific to S0-idle support (if enabled)
+ //
+ INITIALIZE_DEVICE_SETTINGS_FOR_S0_IDLE(Device, devCtx);
+
+ //
+ // In our device context, replace the pointer to the initializer's memory
+ // object with a pointer to the new memory object that we just created.
+ //
+ devCtx->DeviceInitSettings.PowerIrpPreprocessMinorFunctions = memory;
+
+ //
+ // For convenient access, also save the memory object's buffer in our device
+ // context.
+ //
+ devCtx->DriverLayerPowerIrpPreprocessInfo = WdfMemoryGetBuffer(
+ memory,
+ NULL // BufferSize
+ );
+
+ //
+ // By default, we do not need to call PoFxReportDevicePoweredOn from our
+ // EvtDeviceD0Entry callback. We only need to call it in the
+ // EvtDeviceD0Entry callback that is invoked right after we receive an S0
+ // IRP.
+ //
+ devCtx->ShouldReportDevicePoweredOn = FALSE;
+
+ //
+ // The initializer can now be used to initialize some other object
+ //
+ ResetInitializer(Initializer);
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PfhInitializePowerFrameworkSettings(
+ _In_ WDFDEVICE Device,
+ _In_ PPO_FX_DEVICE PoFxDeviceInfo
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ PPOFX_DEVICE_CONTEXT devCtx;
+ ULONG i;
+ ULONG pofxExtraComponentsSize;
+ ULONG pofxDeviceInfoSize;
+ WDFMEMORY memory = NULL;
+ ULONG idleStatesSize;
+ PVOID idleStates = NULL;
+ PPO_FX_DEVICE poFxDeviceInfo = NULL;
+ PPOFX_COMPONENT_INFO componentInfo = NULL;
+ ULONG componentInfoSize;
+
+ PAGED_CODE();
+
+ 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;
+ }
+
+ if (ArePowerFrameworkSettingsAvailable(Device)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializePowerFrameworkSettings has already been "
+ "called for WDFDEVICE %p. It should not be called again. "
+ "%!status!.",
+ Device,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(Device);
+
+ //
+ // Allocate memory to store power framework settings
+ //
+ status = RtlULongMult(sizeof(PO_FX_COMPONENT),
+ (PoFxDeviceInfo->ComponentCount - 1),
+ &pofxExtraComponentsSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed for extra "
+ "components. RtlULongMult failed with %!status!.",
+ status);
+ goto exit;
+ }
+ status = RtlULongAdd(sizeof(PO_FX_DEVICE),
+ pofxExtraComponentsSize,
+ &pofxDeviceInfoSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed for power "
+ "framework settings. RtlUlongAdd failed with %!status!.",
+ status);
+ goto exit;
+ }
+ if (0 == pofxDeviceInfoSize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to set pofxDeviceInfoSize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Device; // auto-delete when parent deleted
+ status = WdfMemoryCreate(&objectAttributes,
+ NonPagedPool,
+ 0, // PoolTag
+ pofxDeviceInfoSize,
+ &memory,
+ (PVOID*) &poFxDeviceInfo);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to allocate memory for power framework "
+ "settings. WdfMemoryCreate failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ devCtx->PoFxDeviceInfo = poFxDeviceInfo;
+
+ //
+ // Copy power framework settings
+ //
+ status = WdfMemoryCopyFromBuffer(memory,
+ 0, // DestinationOffset
+ PoFxDeviceInfo,
+ pofxDeviceInfoSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to copy power framework settings. "
+ "WdfMemoryCopyFromBuffer failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ //
+ // Save the driver layer's callbacks and replace them with our own
+ //
+ devCtx->DriverLayerPoFxCallbacks.ComponentIdleStateCallback =
+ devCtx->PoFxDeviceInfo->ComponentIdleStateCallback;
+ devCtx->DriverLayerPoFxCallbacks.ComponentActiveConditionCallback =
+ devCtx->PoFxDeviceInfo->ComponentActiveConditionCallback;
+ devCtx->DriverLayerPoFxCallbacks.ComponentIdleConditionCallback =
+ devCtx->PoFxDeviceInfo->ComponentIdleConditionCallback;
+ devCtx->DriverLayerPoFxCallbacks.DevicePowerRequiredCallback =
+ devCtx->PoFxDeviceInfo->DevicePowerRequiredCallback;
+ devCtx->DriverLayerPoFxCallbacks.DevicePowerNotRequiredCallback =
+ devCtx->PoFxDeviceInfo->DevicePowerNotRequiredCallback;
+ devCtx->PoFxDeviceInfo->ComponentIdleStateCallback =
+ _PfhComponentIdleStateCallback;
+ devCtx->PoFxDeviceInfo->ComponentActiveConditionCallback =
+ _PfhComponentActiveConditionCallback;
+ devCtx->PoFxDeviceInfo->ComponentIdleConditionCallback =
+ _PfhComponentIdleConditionCallback;
+ devCtx->PoFxDeviceInfo->DevicePowerRequiredCallback =
+ _PfhDevicePowerRequiredCallback;
+ devCtx->PoFxDeviceInfo->DevicePowerNotRequiredCallback =
+ _PfhDevicePowerNotRequiredCallback;
+
+ //
+ // Save the driver layer's context and replace it with our own
+ //
+ devCtx->DriverLayerPoFxContext = devCtx->PoFxDeviceInfo->DeviceContext;
+ devCtx->PoFxDeviceInfo->DeviceContext = (PVOID) Device;
+
+ //
+ // Store the idle states for each component
+ //
+ for (i=0; i < devCtx->PoFxDeviceInfo->ComponentCount; i++) {
+
+ status = RtlULongMult(sizeof(PO_FX_COMPONENT_IDLE_STATE),
+ PoFxDeviceInfo->Components[i].IdleStateCount,
+ &idleStatesSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed for idle "
+ "states for component %d. RtlUlongMult failed with "
+ "%!status!.",
+ i,
+ status);
+ goto exit;
+ }
+ if (0 == idleStatesSize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to set idleStatesSize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Device;//auto-delete when parent deleted
+ status = WdfMemoryCreate(&objectAttributes,
+ NonPagedPool,
+ 0, // PoolTag
+ idleStatesSize,
+ &memory,
+ &idleStates);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to allocate memory for idle states for "
+ "component %d. WdfMemoryCreate failed with %!status!.",
+ i,
+ status);
+ goto exit;
+ }
+
+ status = WdfMemoryCopyFromBuffer(
+ memory,
+ 0, // DestinationOffset
+ devCtx->PoFxDeviceInfo->Components[i].IdleStates,
+ idleStatesSize
+ );
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to copy idle states for component %d. "
+ "WdfMemoryCopyFromBuffer failed with %!status!.",
+ i,
+ status);
+ goto exit;
+ }
+ devCtx->PoFxDeviceInfo->Components[i].IdleStates = idleStates;
+ }
+
+ //
+ // Allocate memory to store our private, per-component information
+ //
+ status = RtlULongMult(sizeof(POFX_COMPONENT_INFO),
+ devCtx->PoFxDeviceInfo->ComponentCount,
+ &componentInfoSize);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to compute buffer size needed for storing "
+ "private, per-component information. RtlULongMult failed with "
+ "%!status!.",
+ status);
+ goto exit;
+ }
+ if (0 == componentInfoSize) {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to set componentInfoSize. Failed with %!status!.",
+ status);
+ goto exit;
+ }
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Device; // auto-delete when parent deleted
+ status = WdfMemoryCreate(&objectAttributes,
+ NonPagedPool,
+ 0, // PoolTag
+ componentInfoSize,
+ &memory,
+ (PVOID*) &componentInfo);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Unable to allocate memory for storing private, per-"
+ "component information. WdfMemoryCreate failed with %!status!.",
+ status);
+ goto exit;
+ }
+ RtlZeroMemory(componentInfo, componentInfoSize);
+ devCtx->ComponentInfo = componentInfo;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+PfhInterceptComponentQueueConfig(
+ _In_ WDFOBJECT Initializer,
+ _Inout_ PWDF_IO_QUEUE_CONFIG DriverLayerQueueConfig
+ )
+// See comments in WdfPoFx.h
+{
+ PHELPER_QUEUE_INIT queueInitSettings = NULL;
+
+ queueInitSettings = GetQueueInitSettings(Initializer);
+
+ if (queueInitSettings->ComponentQueueConfigIntercepted) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInterceptComponentQueueConfig has already been "
+ "called on initialier %p. It should not be called again before "
+ "the initializer has been used to initialize a KMDF queue "
+ "object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Save the driver layer's callbacks that we are going to replace
+ //
+ queueInitSettings->EvtIoCanceledOnQueue =
+ DriverLayerQueueConfig->EvtIoCanceledOnQueue;
+
+ //
+ // Replace the driver layer's callbacks with our own
+ //
+ DriverLayerQueueConfig->EvtIoCanceledOnQueue =
+ _PfhEvtRequestCanceledOnComponentQueue;
+
+ queueInitSettings->ComponentQueueConfigIntercepted = TRUE;
+
+ return;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+PfhSetComponentForComponentQueue(
+ _In_ WDFOBJECT Initializer,
+ _In_ ULONG Component
+ )
+// See comments in WdfPoFx.h
+{
+ PHELPER_QUEUE_INIT queueInitSettings = NULL;
+
+ queueInitSettings = GetQueueInitSettings(Initializer);
+
+ if (queueInitSettings->ComponentSet) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhSetComponentForComponentQueue has already been "
+ "called on initialier %p. It should not be called again before "
+ "the initializer has been used to initialize a KMDF queue "
+ "object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ queueInitSettings->Component = Component;
+
+ queueInitSettings->ComponentSet = TRUE;
+
+ return;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+PfhInitializeComponentQueueSettings(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFOBJECT Initializer
+ )
+// See comments in WdfPoFx.h
+{
+ NTSTATUS status;
+ WDFDEVICE device = NULL;
+ ULONG component;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ PPOFX_DEVICE_CONTEXT devCtx;
+ PPOFX_QUEUE_CONTEXT qCtx;
+ PHELPER_QUEUE_INIT queueInitSettings = NULL;
+
+ queueInitSettings = GetQueueInitSettings(Initializer);
+
+ if (IsQueueInitialized(Queue)) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInitializeComponentQueueSettings has already been "
+ "called for WDFQUEUE %p. It should not be called again. "
+ "%!status!.",
+ Queue,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ device = WdfIoQueueGetDevice(Queue);
+ 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 (FALSE == queueInitSettings->ComponentQueueConfigIntercepted) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhInterceptComponentQueueConfig has not yet been "
+ "called for WDFQUEUE %p. %!status!.",
+ Queue,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ if (FALSE == queueInitSettings->ComponentSet) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhSetComponentForComponentQueue has not yet been "
+ "called for WDFQUEUE %p. %!status!.",
+ Queue,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Validate the component number
+ //
+ component = queueInitSettings->Component;
+ if (component >= devCtx->PoFxDeviceInfo->ComponentCount) {
+ status = STATUS_INVALID_PARAMETER;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Component number %d is invalid. Component count is %d."
+ " %!status!.",
+ component,
+ devCtx->PoFxDeviceInfo->ComponentCount,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Allocate our context for this queue
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes,
+ POFX_QUEUE_CONTEXT);
+ status = WdfObjectAllocateContext((WDFOBJECT) Queue,
+ &objectAttributes,
+ (PVOID*) &qCtx);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfObjectAllocateContext failed with %!status!",
+ status);
+ goto exit;
+ }
+
+ if (NULL != devCtx->ComponentInfo[component].Queue) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - Component %d has already been associated with WDFQUEUE"
+ " %p. Associating a component with more than one queue is not "
+ "supported. %!status!.",
+ component,
+ devCtx->ComponentInfo[component].Queue,
+ status);
+ WdfVerifierDbgBreakPoint();
+ goto exit;
+ }
+
+ //
+ // Copy the queue init settings
+ //
+ qCtx->QueueInitSettings = *queueInitSettings;
+
+ //
+ // The initializer can now be used to initialize some other object
+ //
+ ResetInitializer(Initializer);
+
+ //
+ // Save the queue handle in our private component information
+ //
+ devCtx->ComponentInfo[component].Queue = Queue;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
diff --git a/pofx/WDF/Driver/MultiComp/lib/s0idle.c b/pofx/WDF/Driver/MultiComp/lib/s0idle.c
new file mode 100644
index 00000000..59ab1bd3
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/s0idle.c
@@ -0,0 +1,471 @@
+/*++
+
+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:
+
+ s0idle.c
+
+Abstract:
+ This module contains routines that are used to implement support for
+ S0-idle power management. Note the use of the compile-time switch
+ PFH_S0IDLE_SUPPORTED to control whether or not S0-idle power management
+ support is implemented in the power framework helper library. Drivers that
+ do not require S0-idle power management support should set the
+ PFH_S0IDLE_SUPPORTED compile-time switch to 0 in order to reduce the
+ code size of the power framework helper library.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#if PFH_S0IDLE_SUPPORTED
+
+#include "WdfPoFxPriv.h"
+#include "s0idle.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, PfhSetS0IdleConfiguration)
+#pragma alloc_text(PAGE, InitializeDeviceSettingsForS0Idle)
+#pragma alloc_text(PAGE, _PowerRequiredPassiveHandler)
+#endif
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+PfhSetS0IdleConfiguration(
+ _In_ WDFOBJECT Initializer,
+ _In_ PFH_S0IDLE_CONFIG S0IdleConfig
+ )
+// See comments in WdfPoFx.h
+{
+ PHELPER_DEVICE_INIT deviceInitSettings = NULL;
+
+ PAGED_CODE();
+
+ deviceInitSettings = GetDeviceInitSettings(Initializer);
+
+ if (deviceInitSettings->S0IdleConfigSet) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - PfhSetS0IdleConfiguration has already been called on "
+ "initialier %p. It should not be called again before the "
+ "initializer has been used to initialize a KMDF device object.",
+ Initializer);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // Save the driver layer's S0-idle configuration
+ //
+ deviceInitSettings->S0IdleConfig = S0IdleConfig;
+
+ deviceInitSettings->S0IdleConfigSet = TRUE;
+ return;
+}
+
+NTSTATUS
+InitializeDeviceSettingsForS0Idle(
+ _In_ WDFDEVICE Device,
+ _Inout_ PPOFX_DEVICE_CONTEXT DevCtx
+ )
+/*++
+Routine Description:
+ In this routine we initialize our S0-idle power management related settings
+ for a device.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+ DevCtx - Pointer to our context space for the device object
+
+Return Value:
+
+ An NTSTATUS value representing success or failure of the function.
+--*/
+{
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES objectAttributes;
+ WDF_WORKITEM_CONFIG workItemConfig;
+
+ PAGED_CODE();
+
+ //
+ // Create a work item that we'll queue in response to the device-power-
+ // required callback. This is only needed if S0-idle power management is
+ // supported. Also, queuing a work item can cause pageable data to be
+ // accessed, so we do this only if the device is not in the paging path.
+ // Therefore, we create the work item only if we know that the device will
+ // never be in the paging path.
+ //
+ if (PfhS0IdleSupportedPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig) {
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
+ objectAttributes.ParentObject = Device;//auto-delete when device deleted
+
+ WDF_WORKITEM_CONFIG_INIT(&workItemConfig, _PowerRequiredPassiveHandler);
+ workItemConfig.AutomaticSerialization = FALSE;
+
+ status = WdfWorkItemCreate(&workItemConfig,
+ &objectAttributes,
+ &(DevCtx->PowerRequiredWorkItem));
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfWorkItemCreate failed with %!status!",
+ status);
+ goto exit;
+ }
+ }
+
+
+ //
+ // Initialize StopIdleInvokedOnDeviceStart to FALSE so that when the device
+ // is started, we invoke WdfDeviceStopIdle to prevent device idling until
+ // the power framework permits it.
+ //
+ DevCtx->StopIdleInvokedOnDeviceStart = FALSE;
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+NTSTATUS
+StopDeviceIdleOnDeviceStart(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ )
+/*++
+Routine Description:
+ This routine is invoked during device start. In this routine, we invoke
+ WdfDeviceStopIdle in order to prevent the device from going to Dx as a
+ result of S0-idle power management. We do this only if S0-idle power
+ management is enabled and then only in the following cases:
+ 1. the device is being started for the first time after creation
+ 2. the device is being started for the first time after being disabled
+ (applicable to PDOs only)
+
+ When WdfDeviceStopIdle is called KMDF increments its power idle reference
+ count. Device idling can occur only when the power idle reference count
+ drops to 0. Thus by calling WdfDeviceStopIdle, we prevent device idling
+ until we make a balancing call to WdfDeviceResumeIdle to decrement the power
+ idle reference count.
+
+ When a device is disabled, KMDF resets the power idle reference count of the
+ device to 0. This is the reason we need to call WdfDeviceStopIdle in case #2
+ above.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+ DevCtx - Pointer to our context space for the device object
+
+Return Value:
+
+ An NTSTATUS value representing success or failure of the function.
+
+--*/
+{
+ NTSTATUS status;
+
+ if (DevCtx->StopIdleInvokedOnDeviceStart) {
+ //
+ // This is neither the first device start after creation nor the first
+ // device start after it was disabled. So nothing to do here.
+ //
+ status = STATUS_SUCCESS;
+ goto exit;
+ }
+
+ DevCtx->StopIdleInvokedOnDeviceStart = TRUE;
+
+ //
+ // If S0-idle power management is supported, prevent device idling until the
+ // power framework permits.
+ //
+ if ((PfhS0IdleSupportedPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig) ||
+ (PfhS0IdleSupportedNotPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig)) {
+ //
+ // We are currently in the process of entering D0. Therefore we specify
+ // 'FALSE' for the WaitForD0 parameter in the WdfDeviceDeviceStopIdle
+ // call below. Specifying 'TRUE' would result in the deadlock because we
+ // can't block waiting for D0 while we are in the process of entering
+ // D0. However, the call to WdfDeviceStopIdle will ensure that once we
+ // enter D0, we will remain in D0 until WdfDeviceResumeIdle is called.
+ //
+ status = WdfDeviceStopIdle(Device, FALSE /* WaitForD0 */);
+ if (FALSE == NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfDeviceStopIdle failed for WDFDEVICE %p. "
+ "%!status!.",
+ Device,
+ status);
+ goto exit;
+ }
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+ return status;
+}
+
+VOID
+DevicePowerRequiredForS0Idle(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ )
+/*++
+Routine Description:
+
+ In this routine we perform actions that are necessary in response to the
+ PO_FX_DEVICE_POWER_REQUIRED_CALLBACK callback when S0-idle power management
+ support is enabled for the device.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+ DevCtx - Pointer to our context space for the device object
+
+Return Value:
+
+ None
+
+--*/
+{
+ PPO_FX_DEVICE_POWER_REQUIRED_CALLBACK devicePowerRequiredCallback = NULL;
+ PDEVICE_OBJECT wdmDeviceObject = NULL;
+
+ //
+ // If the driver layer supplied a device-power-required callback, invoke it
+ //
+ devicePowerRequiredCallback =
+ DevCtx->DriverLayerPoFxCallbacks.DevicePowerRequiredCallback;
+ if (NULL != devicePowerRequiredCallback) {
+ devicePowerRequiredCallback(DevCtx->DriverLayerPoFxContext);
+ }
+
+ if (PfhS0IdleNotSupported == DevCtx->DeviceInitSettings.S0IdleConfig) {
+ //
+ // S0-idle power management is not supported. This means that the device
+ // always remains in D0, unless there is a system sleep transition,
+ // resource rebalance or device removal. In other words, the device
+ // never leaves D0 because of S0-idle. So we can immediately report to
+ // the power framework that the device is powered on.
+ //
+ PoFxReportDevicePoweredOn(DevCtx->PoHandle);
+
+ } else if (PfhS0IdleSupportedPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig) {
+ //
+ // S0-idle power management is supported and the device is not in the
+ // paging path. This means that we can access pageable data during the
+ // power transition.
+ //
+ // We need to bring the device to D0 and invoke
+ // PoFxReportDevicePoweredOn when the device is in D0. In order to
+ // achieve this we need to make a blocking call to WdfDeviceStopIdle,
+ // which causes KMDF to bring the device to D0.
+ //
+ // We cannot make a blocking call here because:
+ // * Device-power-required can be invoked at dispatch level
+ // * Even if device-power-required is invoked at passive level, it
+ // might get invoked in the context of an I/O dispatch routine of a
+ // power-managed queue. KMDF does not support blocking calls to
+ // WdfDeviceStopIdle from within the context of an I/O dispatch
+ // routine of a power-managed queue because it can lead to a
+ // deadlock in some situations.
+ // Therefore we queue a system work item for making the blocking call to
+ // WdfDeviceStopIdle.
+ //
+ // !!! IMPORTANT NOTE !!!
+ //
+ // Queuing a system work item can cause pageable data to be accessed.
+ // Therefore, we can do it only if we know that the device is not in the
+ // paging path and that we can safely access pageable data during power
+ // transitions.
+ //
+
+ //
+ // Verify that the DO_POWER_PAGABLE flag is set in the device object
+ //
+ wdmDeviceObject = WdfDeviceWdmGetDeviceObject(Device);
+ if (0 == (wdmDeviceObject->Flags & DO_POWER_PAGABLE)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WDFDEVICE %p is in the paging path, but "
+ "PfhSetNotPowerPageable has not been invoked for it.",
+ Device);
+ WdfVerifierDbgBreakPoint();
+ }
+
+ //
+ // As described in the above comments, we queue a work item to bring the
+ // device to D0.
+ //
+ WdfWorkItemEnqueue(DevCtx->PowerRequiredWorkItem);
+
+ } else {
+ //
+ // !!! IMPORTANT NOTE !!!
+ //
+ // S0-idle power management is supported and the device might be in the
+ // paging path. This means that we cannot access pageable data during
+ // the power transition. As described in the comments above, queueing a
+ // system work item to bring the device to D0 can cause pageable data to
+ // be accessed.
+ //
+ // Therefore, the current implementation of the power framework helper
+ // library does not automatically bring the device to D0 in response to
+ // a device-power-required callback, if the device is in the paging path
+ // and cannot access pageable data during power transitions. In such
+ // cases the driver layer should supply its own device-power-required
+ // callback. In this callback, it should queue work to its own dedicated
+ // worker thread (instead of a system work item) to make a blocking call
+ // to WdfDeviceStopIdle. When WdfDeviceStopIdle returns, the device is
+ // guaranteed to be in D0 so the driver can call
+ // PoFxReportDevicePoweredOn at that point.
+ //
+ ASSERT(PfhS0IdleSupportedNotPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig);
+
+ DO_NOTHING();
+ }
+
+ return;
+}
+
+VOID
+DevicePowerNotRequiredForS0Idle(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ )
+/*++
+Routine Description:
+
+ In this routine we perform actions that are necessary in response to the
+ PO_FX_DEVICE_POWER_NOT_REQUIRED_CALLBACK callback when S0-idle power
+ management support is enabled for the device.
+
+Arguments:
+
+ Device - Handle to the KMDF device object
+
+ DevCtx - Pointer to our context space for the device object
+
+Return Value:
+
+ None
+
+--*/
+{
+ PPO_FX_DEVICE_POWER_NOT_REQUIRED_CALLBACK
+ devicePowerNotRequiredCallback = NULL;
+
+ //
+ // If the driver layer supplied a device-power-not-required callback, invoke
+ // it
+ //
+ devicePowerNotRequiredCallback =
+ DevCtx->DriverLayerPoFxCallbacks.DevicePowerNotRequiredCallback;
+ if (NULL != devicePowerNotRequiredCallback) {
+ devicePowerNotRequiredCallback(DevCtx->DriverLayerPoFxContext);
+ }
+
+ if ((PfhS0IdleSupportedPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig) ||
+ (PfhS0IdleSupportedNotPowerPageable ==
+ DevCtx->DeviceInitSettings.S0IdleConfig)) {
+ //
+ // If S0-idle power management is supported, enable KMDF to power down
+ // the device to Dx.
+ //
+ WdfDeviceResumeIdle(Device);
+ }
+
+ return;
+}
+
+VOID
+_PowerRequiredPassiveHandler(
+ _In_ WDFWORKITEM WorkItem
+ )
+/*++
+Routine Description:
+
+ This is the callback function invoked at passive level in the context of a
+ system worker thread when we queue a work item in response to the device-
+ power-required callback.
+
+Arguments:
+
+ WorkItem - Handle to the KMDF work item object
+
+Return Value:
+
+ None
+
+--*/
+{
+ NTSTATUS status;
+ WDFDEVICE device = NULL;
+ PPOFX_DEVICE_CONTEXT devCtx = NULL;
+
+ PAGED_CODE();
+
+ //
+ // Get the handle to the KMDF device object
+ //
+ device = WdfWorkItemGetParentObject(WorkItem);
+
+ //
+ // Get the device context
+ //
+ devCtx = HelperGetDeviceContext(device);
+
+ //
+ // Make a blocking call to WdfDeviceStopIdle in order to get KMDF to bring
+ // the device to D0 and/or keep it in D0.
+ //
+ status = WdfDeviceStopIdle(device, TRUE /*WaitForD0*/);
+ if (FALSE == NT_SUCCESS(status)) {
+ //
+ // The call to WdfDeviceStopIdle failed. However, we need to call
+ // PoFxReportDevicePoweredOn regardless of success or failure because
+ // we need to unblock the power framework which is waiting for us to
+ // make this call. In case of failure, KMDF would have already declared
+ // the device to be in a failed state and initiated a PNP removal.
+ //
+ Trace(TRACE_LEVEL_ERROR,
+ "%!FUNC! - WdfDeviceStopIdle failed for WDFDEVICE %p. "
+ "%!status!.",
+ device,
+ status);
+
+ //
+ // Fall through to PoFxReportDevicePoweredOn call below
+ // || || ||
+ // || || ||
+ // \/ \/ \/
+ //
+ }
+
+ //
+ // Inform the power framework that the device is now powered on
+ //
+ PoFxReportDevicePoweredOn(devCtx->PoHandle);
+ return;
+}
+
+#endif // PFH_S0IDLE_SUPPORTED \ No newline at end of file
diff --git a/pofx/WDF/Driver/MultiComp/lib/s0idle.h b/pofx/WDF/Driver/MultiComp/lib/s0idle.h
new file mode 100644
index 00000000..0ad10327
--- /dev/null
+++ b/pofx/WDF/Driver/MultiComp/lib/s0idle.h
@@ -0,0 +1,113 @@
+/*++
+
+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:
+
+ s0idle.h
+
+Abstract:
+ Private header file that enables the power framework library to be
+ conditionally compiled either with or without S0-idle power management
+ support, based on the value of the PFH_S0IDLE_SUPPORTED compile-time
+ switch.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#if !defined(_S0IDLE_H_)
+#define _S0IDLE_H_
+
+EVT_WDF_WORKITEM _PowerRequiredPassiveHandler;
+
+#if PFH_S0IDLE_SUPPORTED
+
+//
+// The power framework library is compiled with S0-idle power management support
+//
+NTSTATUS
+InitializeDeviceSettingsForS0Idle(
+ _In_ WDFDEVICE Device,
+ _Inout_ PPOFX_DEVICE_CONTEXT DevCtx
+ );
+
+NTSTATUS
+StopDeviceIdleOnDeviceStart(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ );
+
+VOID
+DevicePowerRequiredForS0Idle(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ );
+
+VOID
+DevicePowerNotRequiredForS0Idle(
+ _In_ WDFDEVICE Device,
+ _In_ PPOFX_DEVICE_CONTEXT DevCtx
+ );
+
+#define INITIALIZE_DEVICE_SETTINGS_FOR_S0_IDLE(_Device, _DevCtx) \
+ InitializeDeviceSettingsForS0Idle(_Device, _DevCtx)
+
+#define STOP_DEVICE_IDLE_ON_DEVICE_START(_Status, _Device, _DevCtx, _ExitLabel)\
+{ \
+ _Status = StopDeviceIdleOnDeviceStart(_Device, _DevCtx); \
+ if (FALSE == NT_SUCCESS(_Status)) { \
+ goto _ExitLabel; \
+ } \
+}
+
+//
+// For PDOs, if the device is restarted after being disabled, we need to
+// prevent device idle until the power framework permits it. Therefore, we
+// reset the StopIdleInvokedOnDeviceStart value here, so that a subsequent
+// restart causes us to invoke WdfDeviceStopIdle to prevent device idling.
+//
+#define SELF_MANAGED_IO_FLUSH_FOR_S0_IDLE(_DevCtx) \
+{ \
+ _DevCtx->StopIdleInvokedOnDeviceStart = FALSE; \
+}
+
+#define DEVICE_POWER_REQUIRED_FOR_S0_IDLE(_Device, _DevCtx) \
+ DevicePowerRequiredForS0Idle(_Device,_DevCtx)
+
+#define DEVICE_POWER_NOT_REQUIRED_FOR_S0_IDLE(_Device, _DevCtx) \
+ DevicePowerNotRequiredForS0Idle(_Device, _DevCtx)
+
+#else // PFH_S0IDLE_SUPPORTED
+
+
+//
+// The power framework library is compiled without S0-idle power management
+// support
+//
+#define INITIALIZE_DEVICE_SETTINGS_FOR_S0_IDLE(_Device, _DevCtx) (0)
+#define STOP_DEVICE_IDLE_ON_DEVICE_START(_Status, _Device, _DevCtx, _ExitLabel)\
+ (0)
+#define SELF_MANAGED_IO_FLUSH_FOR_S0_IDLE(_DevCtx) (0)
+
+//
+// The current implementation does not support S0-idle. It assumes that the
+// device always remains in D0 unless there is a system sleep transition,
+// resource rebalance or device removal. Therefore, we call
+// PoFxReportDevicePoweredOn immediately.
+//
+#define DEVICE_POWER_REQUIRED_FOR_S0_IDLE(_Device, _DevCtx) \
+ PoFxReportDevicePoweredOn(_DevCtx->PoHandle)
+
+#define DEVICE_POWER_NOT_REQUIRED_FOR_S0_IDLE(_Device, _DevCtx) (0)
+
+#endif // PFH_S0IDLE_SUPPORTED
+
+#endif // _S0IDLE_H_