diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /pofx/WDF/Driver/SingleComp | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'pofx/WDF/Driver/SingleComp')
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/HwSim.c | 265 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/HwSim.h | 74 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj | 176 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters | 37 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/SingleComponentFStateSample.inx | 105 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/driver.c | 1243 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/driver.h | 150 | ||||
| -rw-r--r-- | pofx/WDF/Driver/SingleComp/include.h | 3 |
8 files changed, 2053 insertions, 0 deletions
diff --git a/pofx/WDF/Driver/SingleComp/HwSim.c b/pofx/WDF/Driver/SingleComp/HwSim.c new file mode 100644 index 00000000..26f8faf0 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/HwSim.c @@ -0,0 +1,265 @@ +/*++ + +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: + + HwSim.c + +Abstract: + This module implements a simple hardware simulator that simulates reading of + data from the device's components. In this sample, the "data" that is read + is simply the bitwise complement of the component number. In other words, + the data for component number 'X' is simply '~X'. + + The hardware simulator also verifies that when a component is read, the + device is in D0 and the component is in F0. If not, it breaks into the + debugger. + +Environment: + + Kernel mode + +--*/ + +#include "include.h" +#include "HwSim.h" +#include "HwSim.tmh" + +NTSTATUS +HwSimInitialize( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + This routine initializes the hardware simulator + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES objectAttributes; + PHWSIM_CONTEXT devCtx; + + // + // Allocate our context for this device + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, + HWSIM_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; + } + + devCtx->FirstD0Entry = TRUE; + + status = STATUS_SUCCESS; + +exit: + return status; +} + +VOID +HwSimD0Entry( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + This routine simulates the device entering D0 + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + None + +--*/ +{ + PHWSIM_CONTEXT devCtx; + + devCtx = HwSimGetDeviceContext(Device); + + if (devCtx->FirstD0Entry) { + devCtx->FirstD0Entry = FALSE; + + // + // On the first D0 entry component is in F0 state + // + devCtx->ComponentFState = 0; + } + + devCtx->DevicePoweredOn = TRUE; + + return; +} + +VOID +HwSimD0Exit( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + This routine simulates the device exiting D0 + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + None + +--*/ +{ + PHWSIM_CONTEXT devCtx; + + devCtx = HwSimGetDeviceContext(Device); + + devCtx->DevicePoweredOn = FALSE; + + return; +} + +VOID +HwSimFStateChange( + _In_ WDFDEVICE Device, + _In_ ULONG State + ) +/*++ +Routine Description: + + This routine simulates a component changing its F-state + +Arguments: + + Device - Handle to the framework device object + + State - New F-state for the component + +Return Value: + + None + +--*/ +{ + PHWSIM_CONTEXT devCtx; + + devCtx = HwSimGetDeviceContext(Device); + + // + // Verify that the device is powered on + // + if (FALSE == devCtx->DevicePoweredOn) { + // + // This means that our driver is handling an F state transition while + // device is not in D0. + // + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - Expected device to be powered on, but it was not."); + + WdfVerifierDbgBreakPoint(); + } + + ASSERT(devCtx->DevicePoweredOn); + + // + // Put the component in the requested F-state + // + devCtx->ComponentFState = State; + + // + // For an actual hardware, save any hardware state on Fx transition + // and restore state on F0 transition. + // + + return; +} + +ULONG +HwSimReadComponent( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + This routine simulates the reading of data from a component + +Arguments: + + Device - Handle to the framework device object + + Component - Component from which data is being read + +Return Value: + + A ULONG value representing the data that was read from the component + +--*/ +{ + ULONG componentData; + PHWSIM_CONTEXT devCtx; + ULONG component = 0; + + devCtx = HwSimGetDeviceContext(Device); + + // + // Verify that the device is powered on + // + if (FALSE == devCtx->DevicePoweredOn) { + // + // This means that our driver is attempting to read from the component + // while the device is not powered on. + // + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - Expected device to be powered on, but it was not."); + + WdfVerifierDbgBreakPoint(); + } + + // + // Verify that the component is in F0 + // + if (0 != devCtx->ComponentFState) { + // + // This means that our driver is attempting to read from the component + // while the component is not in F0. + // + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - Expected component to be in F0, but it was in F%d.", + devCtx->ComponentFState); + + WdfVerifierDbgBreakPoint(); + } + + ASSERT(devCtx->DevicePoweredOn); + ASSERT(0 == devCtx->ComponentFState); + + // + // In this sample, component data is just a bit-wise complement of the + // component number. + // + componentData = ~component; + return componentData; +} diff --git a/pofx/WDF/Driver/SingleComp/HwSim.h b/pofx/WDF/Driver/SingleComp/HwSim.h new file mode 100644 index 00000000..a43223fb --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/HwSim.h @@ -0,0 +1,74 @@ +/*++ + +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: + + HwSim.h + +Abstract: + Header file for the hardware simulation module of the KMDF sample driver for + a single-component device. + +Environment: + + Kernel mode + +--*/ + +#pragma once + +NTSTATUS +HwSimInitialize( + _In_ WDFDEVICE Device + ); + +VOID +HwSimD0Entry( + _In_ WDFDEVICE Device + ); + +VOID +HwSimD0Exit( + _In_ WDFDEVICE Device + ); + +VOID +HwSimFStateChange( + _In_ WDFDEVICE Device, + _In_ ULONG State + ); + +ULONG +HwSimReadComponent( + _In_ WDFDEVICE Device + ); + +// +// This structure represents the hardware simulation module's device context +// space +// +typedef struct _HWSIM_CONTEXT { + // + // F-state of the component + // + ULONG ComponentFState; + + // + // The following member tracks whether or not the device is in D0 + // + BOOLEAN DevicePoweredOn; + + // + // The following member tracks whether or not we have previously entered the + // D0 state for this device + // + BOOLEAN FirstD0Entry; +} HWSIM_CONTEXT, *PHWSIM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HWSIM_CONTEXT, HwSimGetDeviceContext) diff --git a/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj new file mode 100644 index 00000000..3f0b05c0 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj @@ -0,0 +1,176 @@ +<?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>{17F25816-A09C-44DF-99A3-16D0FF5FCD66}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{D3CED862-FD94-4428-9E76-0D63654856A3}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</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="driver.c; HwSim.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppScanConfigurationData>driver.h</WppScanConfigurationData> + </ClCompile> + <Inf Include=".\SingleComponentFStateSample.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\SingleComponentFStateSample.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SingleComponentFStateDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SingleComponentFStateDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SingleComponentFStateDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SingleComponentFStateDriver</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </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/SingleComp/SingleComponentFStateDriver.vcxproj.Filters b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters new file mode 100644 index 00000000..a8eba88d --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/SingleComponentFStateDriver.vcxproj.Filters @@ -0,0 +1,37 @@ +<?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>{C09CD711-AD25-4CEA-8535-7051049866B9}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{8C669253-AA2C-4BA8-970C-BE8E4A5BEB6C}</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>{2086162C-ED1C-4446-9A17-03967584AA37}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{ACF33661-8D77-4D77-ACD7-ABC80DD52BE0}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="HwSim.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\SingleComponentFStateSample.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\SingleComponentFStateSample.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/pofx/WDF/Driver/SingleComp/SingleComponentFStateSample.inx b/pofx/WDF/Driver/SingleComp/SingleComponentFStateSample.inx new file mode 100644 index 00000000..1c555f11 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/SingleComponentFStateSample.inx @@ -0,0 +1,105 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +;Module Name: +; SingleComponentFStateSample.INF +; +;Abstract: +; INF file for installing SingleComponentFStateSample Driver +; +;Installation Notes: +; Using Devcon: Type "devcon install SingleComponentFStateSample.inf root\SingleComponentFStateDevice" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +SingleComponentFStateDriver.sys = 1,, + +;***************************************** +; SingleComponentFStateDevice Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +; Decorated model section take precedence over undecorated +; ones on XP and later. +[Standard.NT$ARCH$] +%SingleComponentFStateDevice.DeviceDesc%=SingleComponentFStateDevice, root\SingleComponentFStateDevice + +[SingleComponentFStateDevice.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +SingleComponentFStateDriver.sys + + +;-------------- Service installation +[SingleComponentFStateDevice.NT.Services] +AddService = SingleComponentFStateSvc,%SPSVCINST_ASSOCSERVICE%, SingleComponentFStateSvc_Service_Inst + +; -------------- SingleComponentFStateDevice driver install sections +[SingleComponentFStateSvc_Service_Inst] +DisplayName = %SingleComponentFStateSvc.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\SingleComponentFStateDriver.sys + +; +;--- SingleComponentFStateDevice Coinstaller installation ------ +; + +[DestinationDirs] +SingleComponentFStateDevice_CoInstaller_CopyFiles = 11 + +[SingleComponentFStateDevice.NT.CoInstallers] +AddReg=SingleComponentFStateDevice_CoInstaller_AddReg +CopyFiles=SingleComponentFStateDevice_CoInstaller_CopyFiles + +[SingleComponentFStateDevice_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[SingleComponentFStateDevice_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[SingleComponentFStateDevice.NT.Wdf] +KmdfService = SingleComponentFStateSvc, SingleComponentFStateDevice_wdfsect +[SingleComponentFStateDevice_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample SingleComponentFStateDevice Installation Disk #1" +SingleComponentFStateDevice.DeviceDesc = "Single comp F State Device" +SingleComponentFStateSvc.SVCDESC = "Single comp F State Service" +ClassName = "Sample Device" diff --git a/pofx/WDF/Driver/SingleComp/driver.c b/pofx/WDF/Driver/SingleComp/driver.c new file mode 100644 index 00000000..cd7b6dd1 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/driver.c @@ -0,0 +1,1243 @@ +/*++ + +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: + + Driver.c + +Abstract: + This module implements a KMDF sample driver for a single-component device. + The driver uses the power framework to manage the power state of the + component that represents device. + + The device used in this sample is a root-enumerated device whose components + are simulated entirely in software. The simulation of the components is + implemented in HwSim.h and HwSim.c. + + This driver works only on Win8 and above. + +Environment: + + Kernel mode + +--*/ + +#include "include.h" +#include "hwsim.h" + +#include <initguid.h> +#include "AppInterface.h" + +#include "driver.tmh" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, SingleCompEvtDriverCleanup) +#pragma alloc_text (PAGE, SingleCompEvtDeviceAdd) +#pragma alloc_text (PAGE, SingleCompEvtDeviceD0Exit) +#pragma alloc_text (PAGE, AssignS0IdleSettings) +#pragma alloc_text (PAGE, AssignPowerFrameworkSettings) +#pragma alloc_text (PAGE, SingleCompWdmEvtDeviceWdmPostPoFxRegisterDevice) +#pragma alloc_text (PAGE, SingleCompWdmEvtDeviceWdmPrePoFxUnregisterDevice) +#endif + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Driver initialization entry point. This entry point is called directly by + the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path to the + driver-specific key in the registry. + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attributes; + + WPP_INIT_TRACING(DriverObject, RegistryPath); + + // + // Initiialize driver config to control the attributes that are global to + // the driver. Note that framework by default provides a driver unload + // routine. If DriverEntry creates any resources that require clean-up in + // driver unload, you can manually override the default by supplying a + // pointer to the EvtDriverUnload callback in the config structure. In + // general xxx_CONFIG_INIT macros are provided to initialize most commonly + // used members. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = SingleCompEvtDriverCleanup; + WDF_DRIVER_CONFIG_INIT( + &config, + SingleCompEvtDeviceAdd + ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + &attributes, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (FALSE == NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + WPP_CLEANUP(DriverObject); + } + + return status; +} + +VOID +SingleCompEvtDriverCleanup( + _In_ WDFOBJECT Driver + ) +{ + PAGED_CODE(); + + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER) Driver)); +} + +NTSTATUS +SingleCompEvtDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the KMDF in response to AddDevice call from + the PnP manager. + +Arguments: + + Driver - Handle to the KMDF driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + NTSTATUS status; + WDFDEVICE device; + WDF_IO_QUEUE_CONFIG queueConfig; + FDO_DATA *fdoContext = NULL; + ULONG queueIndex = 0; + WDF_OBJECT_ATTRIBUTES objectAttributes; + WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Driver); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, FDO_DATA); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); + pnpCallbacks.EvtDeviceD0Entry = SingleCompEvtDeviceD0Entry; + pnpCallbacks.EvtDeviceD0Exit = SingleCompEvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); + + status = WdfDeviceCreate(&DeviceInit, &objectAttributes, &device); + if (!NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceCreate failed with %!status!.", + status); + goto exit; + } + + fdoContext = FdoGetContext(device); + + // + // Our initial state is active + // + fdoContext->IsActive = TRUE; + + // + // Create three power-managed queues, one each for read, write and IOCTL + // requests. The handles to these power-managed queues are stored in an + // array in the device object context space. When the component becomes idle + // we need to stop our power-managed queues. When the component becomes + // active we need to start them. In those situations, we go through this + // array of power-managed queues and stop or start each queue as + // appropriate. Handles to non-power-managed queues should not be stored in + // this array. + // + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, + WdfIoQueueDispatchParallel); + queueConfig.EvtIoDeviceControl = SingleCompEvtIoDeviceControl; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &(fdoContext->Queues[queueIndex])); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfIoQueueCreate for IoDeviceControl failed with %!status!.", + status); + goto exit; + } + + status = WdfDeviceConfigureRequestDispatching(device, + fdoContext->Queues[queueIndex], + WdfRequestTypeDeviceControl); + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceConfigureRequestDispatching for " + "WdfRequestTypeDeviceControl failed with %!status!.", + status); + goto exit; + } + + ++queueIndex; + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, + WdfIoQueueDispatchParallel); + queueConfig.EvtIoRead = SingleCompEvtIoRead; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &(fdoContext->Queues[queueIndex])); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfIoQueueCreate for IoRead failed with %!status!.", + status); + goto exit; + } + + status = WdfDeviceConfigureRequestDispatching(device, + fdoContext->Queues[queueIndex], + WdfRequestTypeRead); + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceConfigureRequestDispatching for " + "WdfRequestTypeRead failed with %!status!.", + status); + goto exit; + } + + ++queueIndex; + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, + WdfIoQueueDispatchParallel); + queueConfig.EvtIoWrite = SingleCompEvtIoWrite; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &(fdoContext->Queues[queueIndex])); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfIoQueueCreate for IoWrite failed with %!status!.", + status); + goto exit; + } + + status = WdfDeviceConfigureRequestDispatching(device, + fdoContext->Queues[queueIndex], + WdfRequestTypeWrite); + if (FALSE == NT_SUCCESS (status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceConfigureRequestDispatching for " + "WdfRequestTypeWrite failed with %!status!.", + status); + goto exit; + } + + ++queueIndex; + + ASSERT(queueIndex == QUEUE_COUNT); + + status = AssignS0IdleSettings(device); + if (!NT_SUCCESS(status)) { + goto exit; + } + + // + // If you need to talk to hardware to figure out what F-states are + // applicable this can be done in EvtSelfManagedIoInit + // (but no later than that). EvtSelfManagedIoInit gets invoked after + // EvtPrepareHardware so you'd have chance to initialize your hardware. + // + status = AssignPowerFrameworkSettings(device); + if (!NT_SUCCESS(status)) { + goto exit; + } + + // + // Create a device interface so that applications can open a handle to this + // device. + // + status = WdfDeviceCreateDeviceInterface(device, + &GUID_DEVINTERFACE_POWERFX, + NULL /* ReferenceString */); + if (FALSE == NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceCreateDeviceInterface failed with %!status!.", + status); + goto exit; + } + + // + // Initialize the hardware simulator + // + status = HwSimInitialize(device); + if (FALSE == NT_SUCCESS(status)) { + goto exit; + } +exit: + return status; +} + +NTSTATUS +SingleCompEvtDeviceD0Entry( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ +Routine Description: + + KMDF calls this routine when the device has entered D0. + +Arguments: + + Device - Handle to the framework device object + + PreviousState - Previous device power state + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + UNREFERENCED_PARAMETER(PreviousState); + + HwSimD0Entry(Device); + + return STATUS_SUCCESS; +} + +NTSTATUS +SingleCompEvtDeviceD0Exit( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState + ) +/*++ +Routine Description: + + KMDF calls this routine when the device is about to leave D0. + +Arguments: + + Device - Handle to the framework device object + + TargetState - Device power state that the device is about to enter + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(TargetState); + + HwSimD0Exit(Device); + + return STATUS_SUCCESS; +} + +NTSTATUS +SingleCompWdmEvtDeviceWdmPostPoFxRegisterDevice( + _In_ WDFDEVICE Device, + _In_ POHANDLE PoHandle + ) +/*++ +Routine Description: + + KMDF calls this routine after it has registered with the Power Framework + and supplies the registration handle that driver can use directly. + +Arguments: + + Device - Handle to the framework device object + + PoHandle - Handle of registration with Power Framework. + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + FDO_DATA *fdoContext = NULL; + + PAGED_CODE(); + + // + // Get the device context + // + fdoContext = FdoGetContext(Device); + + // + // Save the POHANDLE + // + fdoContext->PoHandle = PoHandle; + + // + // Set latency and residency hints so that the power framework chooses lower + // powered F-states when we are idle. + // The values used here are for illustration purposes only. The driver + // should use values that are appropriate for its device. + // + PoFxSetComponentLatency( + PoHandle, + 0, // Component + (WDF_ABS_TIMEOUT_IN_MS(DEEPEST_FSTATE_LATENCY_IN_MS) + 1) + ); + PoFxSetComponentResidency( + PoHandle, + 0, // Component + (WDF_ABS_TIMEOUT_IN_SEC(DEEPEST_FSTATE_RESIDENCY_IN_SEC) + 1) + ); + + return STATUS_SUCCESS; +} + +VOID +SingleCompWdmEvtDeviceWdmPrePoFxUnregisterDevice( + _In_ WDFDEVICE Device, + _In_ POHANDLE PoHandle + ) +/*++ +Routine Description: + + KMDF calls this routine when it is about to unregister with the Power + Framework. After returning from this routine driver must not use the + supplied registration handle anymore. + +Arguments: + + Device - Handle to the framework device object + + PoHandle - Handle of registration with Power Framework. + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + FDO_DATA *fdoContext = NULL; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(PoHandle); + + // + // Get the device context + // + fdoContext = FdoGetContext(Device); + + // + // Reset the POHANDLE + // + fdoContext->PoHandle = NULL; + + return; +} + +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +AssignS0IdleSettings( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + Helper function to assign S0 idle settings for the device + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + NTSTATUS status; + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS powerPolicy; + + PAGED_CODE(); + + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&powerPolicy, + IdleCannotWakeFromS0); + powerPolicy.IdleTimeoutType = SystemManagedIdleTimeout; + + status = WdfDeviceAssignS0IdleSettings(Device, &powerPolicy); + if (FALSE == NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceAssignS0IdleSettings failed with %!status!.", + status); + } + return status; +} + +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +AssignPowerFrameworkSettings( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + Helper function to assign Power Framework related settings for the device + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + An NTSTATUS value representing success or failure of the function. + +--*/ +{ + NTSTATUS status; + WDF_POWER_FRAMEWORK_SETTINGS poFxSettings; + PO_FX_COMPONENT component; + PO_FX_COMPONENT_IDLE_STATE idleStates[FSTATE_COUNT]; + + // + // Note that we initialize the 'idleStates' array below based on the + // assumption that MAX_FSTATE_COUNT is 4. + // If we increase the value of MAX_FSTATE_COUNT, we need to initialize those + // additional F-states below. If we decrease the value of MAX_FSTATE_COUNT, + // we need to remove the corresponding initializations below. + // + C_ASSERT(FSTATE_COUNT == 4); + + PAGED_CODE(); + + // + // Initialization + // + RtlZeroMemory(&component, sizeof(component)); + RtlZeroMemory(idleStates, sizeof(idleStates)); + + // + // The transition latency and residency requirement values used here are for + // illustration purposes only. The driver should use values that are + // appropriate for its device. + // + + // + // F0 + // + idleStates[0].TransitionLatency = 0; + idleStates[0].ResidencyRequirement = 0; + idleStates[0].NominalPower = 0; + + // + // F1 + // + idleStates[1].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(200); + idleStates[1].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(3); + idleStates[1].NominalPower = 0; + + // + // F2 + // + idleStates[2].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(400); + idleStates[2].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(6); + idleStates[2].NominalPower = 0; + + // + // F3 + // + idleStates[3].TransitionLatency = + WDF_ABS_TIMEOUT_IN_MS(DEEPEST_FSTATE_LATENCY_IN_MS); + idleStates[3].ResidencyRequirement = + WDF_ABS_TIMEOUT_IN_SEC(DEEPEST_FSTATE_RESIDENCY_IN_SEC); + idleStates[3].NominalPower = 0; + + // + // Component 0 (the only component) + // + component.IdleStateCount = FSTATE_COUNT; + component.IdleStates = idleStates; + + WDF_POWER_FRAMEWORK_SETTINGS_INIT(&poFxSettings); + + poFxSettings.EvtDeviceWdmPostPoFxRegisterDevice = + SingleCompWdmEvtDeviceWdmPostPoFxRegisterDevice; + poFxSettings.EvtDeviceWdmPrePoFxUnregisterDevice = + SingleCompWdmEvtDeviceWdmPrePoFxUnregisterDevice; + + poFxSettings.Component = &component; + poFxSettings.ComponentActiveConditionCallback = + SingleCompWdmActiveConditionCallback; + poFxSettings.ComponentIdleConditionCallback = + SingleCompWdmIdleConditionCallback; + poFxSettings.ComponentIdleStateCallback = + SingleCompWdmIdleStateCallback; + poFxSettings.PoFxDeviceContext = (PVOID) Device; + + status = WdfDeviceWdmAssignPowerFrameworkSettings(Device, &poFxSettings); + if (FALSE == NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfDeviceWdmAssignPowerFrameworkSettings failed with " + "%!status!.", + status); + } + return status; +} + +_IRQL_requires_same_ +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +F0Entry( + _In_ WDFDEVICE Device + ) +/*++ +Routine Description: + + Helper function invoked when component (representing the whole device) is + requested to enter F0. + +Arguments: + + Device - Handle to the framework device object + +Return Value: + + BOOLEAN indicating whether F0 transition has completed. + +--*/ +{ + // + // Change the F-state of the component + // This includes hardware-specific operations such as: + // * enabling DMA capabilities associated with the component + // * enabling interrupts associated with the component + // * restoring component state + // + // + HwSimFStateChange(Device, 0); + return TRUE; +} + +_IRQL_requires_same_ +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +F0Exit( + _In_ WDFDEVICE Device, + _In_ ULONG State + ) +/*++ +Routine Description: + + Helper function invoked when component (representing the whole device) is + requested to exit F0. + +Arguments: + + Device - Handle to the framework device object + State - The new F-state to be entered + +Return Value: + + BOOLEAN indicating whether Fx transition has completed. + +--*/ +{ + // + // Change the F-state of the component + // This includes hardware-specific operations such as: + // * disabling DMA capabilities associated with the component + // * disabling interrupts associated with the component + // * saving component state + // + HwSimFStateChange(Device, State); + return TRUE; +} + +VOID +SingleCompWdmIdleStateCallback( + _In_ PVOID Context, + _In_ ULONG Component, + _In_ ULONG State + ) +/*++ +Routine Description: + + This callback is invoked by Power Framework to notify driver about any + F-state transition. + +Arguments: + + Context - Context supplied to Power Framework. KMDF supplies WDFDEVICE as + the context while registering with Power Framework. Hence Context + contains the KMDF device object. + + Component - Component for which F state transition is requested. Since we + have only one component this value is always 0. + +Return Value: + + BOOLEAN indicating whether Fx transition has completed. + +--*/ +{ + WDFDEVICE device = NULL; + FDO_DATA *fdoContext = NULL; + BOOLEAN transitionComplete = TRUE; + + // + // We have only component 0 + // + if (0 != Component) { + Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); + ASSERT(FALSE); + } + + // + // Get the device + // + device = (WDFDEVICE) Context; + + // + // Get the device context + // + fdoContext = FdoGetContext(device); + + // + // Note the new F-state + // + switch (State) { + case 0: { + transitionComplete = F0Entry(device); + } + break; + + // + // PEP may make us go to any of the F-states directly, hence we execute + // F0Exit code for all of the Fx states. + // + // Transition to any Fx state happens from F0 (and not another + // Fx state) + // + default: { + ASSERT(State < FSTATE_COUNT); + + transitionComplete = F0Exit(device, State); + } + break; + } + + if (transitionComplete) { + PoFxCompleteIdleState(fdoContext->PoHandle, 0 /* Component */); + } +} + +VOID +SingleCompEvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ +Routine Description: + + Callback invoked by WDFQUEUE for a Device Io Control request. + +Arguments: + + Queue - Device I/O control queue + + Request - Device I/O control request + + OutputBufferLength - Output buffer length for the I/O control + + InputBufferLength - Input buffer length for the I/O control + + IoControlCode - I/O control code + +--*/ +{ + NTSTATUS status; + PPOWERFX_READ_COMPONENT_INPUT inputBuffer = NULL; + PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL; + WDFDEVICE device = NULL; + ULONG componentData; + ULONG_PTR information = 0; + FDO_DATA *fdoContext = NULL; + + // + // When we complete the request, make sure we don't get the I/O manager to + // copy any more data to the client address space than what we write to the + // output buffer. The only data that we write to the output buffer is the + // component data and the C_ASSERT below ensures that the output buffer does + // not have room to contain anything other than that. + // + C_ASSERT(sizeof(componentData) == sizeof(*outputBuffer)); + + // + // This is a power-managed queue. So our queue stop/start logic should have + // ensured that we are in the active condition when a request is dispatched + // from this queue. + // + device = WdfIoQueueGetDevice(Queue); + fdoContext = FdoGetContext(device); + if (FALSE == fdoContext->IsActive) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - IOCTL %d was dispatched from WDFQUEUE %p when the " + "component was not in an active condition.", + IOCTL_POWERFX_READ_COMPONENT, + Queue); + WdfVerifierDbgBreakPoint(); + } + + // + // Validate Ioctl code + // + if (IOCTL_POWERFX_READ_COMPONENT != IoControlCode) { + status = STATUS_NOT_SUPPORTED; + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! -Unsupported IoControlCode. Expected: %d. Actual: %d." + " %!status!.", + IOCTL_POWERFX_READ_COMPONENT, + IoControlCode, + status); + goto exit; + } + + // + // Validate input buffer length + // + if (InputBufferLength != sizeof(*inputBuffer)) { + status = STATUS_INVALID_PARAMETER; + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! -Invalid output buffer size. Expected: %d. Actual: %I64u." + " %!status!.", + sizeof(*inputBuffer), + InputBufferLength, + status); + goto exit; + } + + // + // Validate output buffer length + // + if (OutputBufferLength != sizeof(*outputBuffer)) { + status = STATUS_INVALID_PARAMETER; + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! -Invalid input buffer size. Expected: %d. Actual: %I64u." + " %!status!.", + sizeof(*outputBuffer), + OutputBufferLength, + status); + goto exit; + } + + // + // Get the output buffer + // + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(*outputBuffer), + (PVOID*) &outputBuffer, + NULL // Length + ); + if (FALSE == NT_SUCCESS(status)) { + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! - WdfRequestRetrieveOutputBuffer failed with %!status!.", + status); + goto exit; + } + + // + // Read the data from the component + // + componentData = HwSimReadComponent(device); + outputBuffer->ComponentData = componentData; + information = sizeof(*outputBuffer); + + status = STATUS_SUCCESS; + +exit: + // + // Complete the request + // + WdfRequestCompleteWithInformation(Request, status, information); + return; +} + +// +// Read and write queues are only for illustration purposes - on how to stop +// multiple queues. Currently app doesn't send Read/Write to the driver. +// +VOID +SingleCompEvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength + ) +/*++ +Routine Description: + + Callback invoked by WDFQUEUE for a read request. + +Arguments: + + Queue - Read queue + + Request - Read request + + OutputBufferLength - Length of read + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(OutputBufferLength); + + status = STATUS_NOT_SUPPORTED; + + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! -Reads are currently not supported: %!status!.", + status); + + WdfRequestComplete(Request, status); +} + +VOID +SingleCompEvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t InputBufferLength + ) +/*++ +Routine Description: + + Callback invoked by WDFQUEUE for a write request. + +Arguments: + + Queue - Write queue + + Request - Write request + + InputBufferLength - Length of write + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(InputBufferLength); + + status = STATUS_NOT_SUPPORTED; + + Trace(TRACE_LEVEL_ERROR, + "%!FUNC! -Writes are currently not supported: %!status!.", + status); + + WdfRequestComplete(Request, status); +} + +VOID +SingleCompWdmActiveConditionCallback( + _In_ PVOID Context, + _In_ ULONG Component + ) +/*++ +Routine Description: + + This callback is invoked by Power Framework to notify driver that one of its + components has become active. + +Arguments: + + Context - Context that we supplied when calling + WdfDeviceWdmAssignPowerFrameworkSettings. + + Component - Component that have become active. Since we have only one + component this value is always 0. + +Return Value: + + None + +--*/ +{ + WDFDEVICE device; + FDO_DATA *fdoContext = NULL; + UCHAR i = 0; + + // + // We have only component 0 + // + if (0 != Component) { + Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); + ASSERT(FALSE); + } + + // + // Get the device + // + device = (WDFDEVICE) Context; + + // + // Get the device context + // + fdoContext = FdoGetContext(device); + + // + // Mark ourselves as active + // + fdoContext->IsActive = TRUE; + + // + // Start power-managed queues + // + for (i = 0; i < QUEUE_COUNT; i++) { + WdfIoQueueStart(fdoContext->Queues[i]); + } + + return; +} + +VOID +SingleCompWdmIdleConditionCallback( + _In_ PVOID Context, + _In_ ULONG Component + ) +/*++ +Routine Description: + This callback is invoked by Power Framework to notify driver that one of its + components has become idle. + +Arguments: + + Context - Context that we supplied when calling + WdfDeviceWdmAssignPowerFrameworkSettings. + + Component - Component that have become idle. Since we have only one + component this value is always 0. + +Return Value: + + None + +--*/ +{ + WDFDEVICE device; + FDO_DATA *fdoContext = NULL; + UCHAR i = 0; + + // + // We have only component 0 + // + if (0 != Component) { + Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); + ASSERT(FALSE); + } + + // + // Get the device + // + device = (WDFDEVICE) Context; + + // + // Get the device context + // + fdoContext = FdoGetContext(device); + + // + // Initialize the count of queues to be stopped. + // + // Until we complete this idle transition there cannot be other idle + // transitions, which is only where we use this count. Thus nothing races + // with it. + // + // If you have other code that stops/starts queues, it may be simpler + // to queue a work-item from this callback which stops all the queues + // synchronously. Synchronous queue stop cannot be done from here since + // this callback may be called at DISPATCH_LEVEL. + // + fdoContext->QueueStopCount = QUEUE_COUNT; + + // + // Stop power-managed queues + // + for (i = 0; i < QUEUE_COUNT; i++) { +#pragma warning(suppress: 6387) // passing NULL Context parameter is safe in this instance + WdfIoQueueStop(fdoContext->Queues[i], + SingleCompEvtQueueStopComplete, + NULL /* Context */); + } + + // + // The idle transition will complete asynchronously. We'll call + // PoFxCompleteIdleCondition to complete it when all the queues have been + // stopped. + // + // IMPORTANT NOTE + // ============== + // Given that the idle transition does not complete until all the power- + // managed queues have been stopped, it is extremely important for the + // driver to ensure that stopping of power-managed queues is reasonably + // quick. If the driver fails to ensure this, the power framework can remain + // stuck in the idle transition for a long time, which could hamper its + // ability to put the component in a low-power F-state. This could + // negatively impact any power savings that can be gained via component + // power management. + // + // In order to ensure that idle transitions can complete quickly, the driver + // should quickly process any requests that are dispatched to it via a + // power-managed queue. If the driver forwards a request (that was received + // via a power-managed queue) to an I/O target that might keep the request + // pending for a long time, then the driver should cancel the request when + // the component idle condition callback is invoked. This is because the + // power-managed queue cannot be stopped while the request is pending in the + // I/O target. + // + return; +} + +VOID +SingleCompEvtQueueStopComplete( + _In_ WDFQUEUE Queue, + _In_ WDFCONTEXT Context + ) +/*++ +Routine Description: + + Callback invoked by KMDF when stop transiton of the supplied queue has + completed. + +Arguments: + + Queue - Queue whose stop transition has completed + + Context - The context we supply while calling WdfIoQueueStop. + +Return value: + None +--*/ +{ + PFDO_DATA fdoContext; + WDFDEVICE device; + + UNREFERENCED_PARAMETER(Context); + + device = WdfIoQueueGetDevice(Queue); + + fdoContext = WdfObjectGetTypedContext(device, FDO_DATA); + + if (0 == InterlockedDecrement(&(fdoContext->QueueStopCount))) { + // + // All the queues have been stopped. Mark ourselves as idle and complete + // the idle transition. + // + fdoContext->IsActive = FALSE; + PoFxCompleteIdleCondition(fdoContext->PoHandle, 0 /* Component */); + } +} diff --git a/pofx/WDF/Driver/SingleComp/driver.h b/pofx/WDF/Driver/SingleComp/driver.h new file mode 100644 index 00000000..850657c0 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/driver.h @@ -0,0 +1,150 @@ +/*++ + +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: + + Driver.h + +Abstract: + Header file for the KMDF sample driver for a single-component device. + +Environment: + + Kernel mode + +--*/ + +#define QUEUE_COUNT 3 +#define FSTATE_COUNT 4 +#define DEEPEST_FSTATE_LATENCY_IN_MS 800 +#define DEEPEST_FSTATE_RESIDENCY_IN_SEC 12 + +// +// This structure represents the driver's device context space +// +typedef struct _FDO_DATA +{ + // + // Handle of registration with Power Framework + // + POHANDLE PoHandle; + + // + // Power-managed queues used for the device. + // We track them here so that we can stop/start them on active/idle + // transitions. + // + WDFQUEUE Queues[QUEUE_COUNT]; + + // + // Count of queues to be stopped. + // + // It is initialized to QUEUE_COUNT at the beginning of a transition to an + // idle condition. It is decremented everytime a queue completes stop + // transition. + // + // When this count reaches 0 we can transition device into an idle + // condition. + // + LONG QueueStopCount; + + // + // Tracks the active/idle state of the component + // + BOOLEAN IsActive; +} FDO_DATA, *PFDO_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, FdoGetContext) + +// +// Driver's KMDF callbacks +// + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD SingleCompEvtDeviceAdd; +EVT_WDF_OBJECT_CONTEXT_CLEANUP SingleCompEvtDriverCleanup; + +EVT_WDF_DEVICE_D0_ENTRY SingleCompEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT SingleCompEvtDeviceD0Exit; + + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL SingleCompEvtIoDeviceControl; +EVT_WDF_IO_QUEUE_IO_READ SingleCompEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE SingleCompEvtIoWrite; +EVT_WDF_IO_QUEUE_STATE SingleCompEvtQueueStopComplete; + +EVT_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE SingleCompWdmEvtDeviceWdmPostPoFxRegisterDevice; +EVT_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE SingleCompWdmEvtDeviceWdmPrePoFxUnregisterDevice; + +// +// Driver's power framework callbacks +// +PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK SingleCompWdmActiveConditionCallback; +PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK SingleCompWdmIdleConditionCallback; +PO_FX_COMPONENT_IDLE_STATE_CALLBACK SingleCompWdmIdleStateCallback; + +// +// Helper functions +// + +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +AssignS0IdleSettings( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +AssignPowerFrameworkSettings( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_same_ +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +F0Entry( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_same_ +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +F0Exit( + _In_ WDFDEVICE Device, + _In_ ULONG State + ); + +// +// Define the tracing flags. +// +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (f9eb5c3a,c292,4c69,8b52,ccf043c25ab0), \ + \ + WPP_DEFINE_BIT(MYDRIVER_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=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// diff --git a/pofx/WDF/Driver/SingleComp/include.h b/pofx/WDF/Driver/SingleComp/include.h new file mode 100644 index 00000000..d80fa458 --- /dev/null +++ b/pofx/WDF/Driver/SingleComp/include.h @@ -0,0 +1,3 @@ +#include <ntddk.h> +#include <wdf.h> +#include "driver.h"
\ No newline at end of file |
