summaryrefslogtreecommitdiff
path: root/gpio/samples/simdeviceumdf
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 /gpio/samples/simdeviceumdf
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'gpio/samples/simdeviceumdf')
-rw-r--r--gpio/samples/simdeviceumdf/GpioSampleUMDF.asl122
-rw-r--r--gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj282
-rw-r--r--gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters54
-rw-r--r--gpio/samples/simdeviceumdf/comsup.cpp344
-rw-r--r--gpio/samples/simdeviceumdf/comsup.h217
-rw-r--r--gpio/samples/simdeviceumdf/device.cpp1106
-rw-r--r--gpio/samples/simdeviceumdf/device.h365
-rw-r--r--gpio/samples/simdeviceumdf/dllsup.cpp151
-rw-r--r--gpio/samples/simdeviceumdf/driver.cpp222
-rw-r--r--gpio/samples/simdeviceumdf/driver.h151
-rw-r--r--gpio/samples/simdeviceumdf/exports.def10
-rw-r--r--gpio/samples/simdeviceumdf/internal.h96
-rw-r--r--gpio/samples/simdeviceumdf/queue.cpp529
-rw-r--r--gpio/samples/simdeviceumdf/queue.h211
-rw-r--r--gpio/samples/simdeviceumdf/simdeviceumdf.rc21
-rw-r--r--gpio/samples/simdeviceumdf/simdeviceumdfdriver.ctl1
-rw-r--r--gpio/samples/simdeviceumdf/simdeviceumdfdriver.inx78
17 files changed, 3960 insertions, 0 deletions
diff --git a/gpio/samples/simdeviceumdf/GpioSampleUMDF.asl b/gpio/samples/simdeviceumdf/GpioSampleUMDF.asl
new file mode 100644
index 00000000..7e52795f
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/GpioSampleUMDF.asl
@@ -0,0 +1,122 @@
+
+/*++
+
+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:
+
+ GpioSample.asl
+
+Abstract:
+
+ This sample ASL file describes a sample GPIO device and a sample peripheral
+ device which consumes IO and interrupt resources from the GPIO device. Please
+ note that:
+
+ 1. The memory and IO descriptor under the GPIO device are simply examples of
+ what can be described. They are commented out to illustrate this point. Actual
+ values will vary according to the platform specifications (e.g. GIC and memory)
+
+ 2. The sample ASL DSDT definition block defines only the components relevant
+ to demonstrate GPIO IO and interrupt resource usage. Rest of the DSDT will vary
+ according to platform specifications.
+
+ 3. The PNP IDs for the GPIO and peripheral device are for demonstration purposes
+ only. Actual values need to reflect those chosen for the actual GPIO or
+ peripheral device.
+
+--*/
+
+
+DefinitionBlock ("DSDT.AML", "DSDT", 0x02, "MSFT", "SAMPLE", 0x1) {
+
+ //
+ // System Bus
+ //
+
+ Scope (\_SB) {
+
+ //
+ // Sample GPIO device
+ //
+
+ Device(GPIO) {
+ Name (_ADR, 0)
+ Name (_HID, "TEST0001")
+ Name (_CID, "TEST0001")
+ Name(_UID, 4)
+
+ Method (_CRS, 0x0, NotSerialized) {
+ Name (RBUF, ResourceTemplate () {
+
+ //
+ // Interrupt resource. In this example, banks 0 & 1 share the same
+ // interrupt to the parent controller and similarly banks 2 & 3.
+ //
+ // N.B. The definition below is chosen for an arbitrary
+ // test platform. It needs to be changed to reflect the hardware
+ // configuration of the actual platform.
+ //
+
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared, , , ) {50}
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared, , , ) {50}
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared, , , ) {51}
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared, , , ) {51}
+
+ //
+ // Memory resource. The definition below is chosen for an arbitrary
+ // test platform. It needs to be changed to reflect the hardware
+ // configuration of the actual platform.
+ //
+
+ Memory32Fixed(ReadWrite, 0x00100000, 0x18)
+ })
+
+ Return (RBUF)
+ }
+
+ Method (_STA, 0x0, NotSerialized) {
+ Return(0xf)
+ }
+
+ //
+ // Sample peripheral device
+ //
+
+ Device (TDEV) {
+ Name (_ADR, 0)
+ Name (_HID, "TEST0004")
+ Name (_CID, "TEST0004")
+ Name (_UID, 1)
+
+ Method (_CRS, 0x0, NotSerialized) {
+ Name (RBUF, ResourceTemplate () {
+
+ //
+ // GPIO Interrupt Resources
+ //
+
+ GpioInt(Edge, ActiveHigh, Exclusive, PullUp, 0, "\\_SB.GPIO", 0, ResourceConsumer,, RawDataBuffer() {1}) {2}
+
+ //
+ // GPIO IO Resources
+ //
+
+ GpioIo(Exclusive, PullUp, 0, 0,, "\\_SB.GPIO",0, ResourceConsumer, , RawDataBuffer() {1}) {10}
+ })
+
+ Return (RBUF)
+ }
+
+ Method (_STA, 0x0, NotSerialized) {
+ Return(0xf)
+ }
+ }
+ }
+ }
+ }
diff --git a/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj
new file mode 100644
index 00000000..05a8bfe6
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj
@@ -0,0 +1,282 @@
+<?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>{D768CF1C-AE06-4C12-B11D-21C5D70082F7}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR>
+ <UMDF_VERSION_MINOR>11</UMDF_VERSION_MINOR>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <KMDF_VERSION_MINOR>11</KMDF_VERSION_MINOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{DF2D116B-B9CA-4AE1-BAD4-416349DA768D}</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>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</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">
+ <Inf Include="simdeviceUMDFDriver.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\simdeviceUMDFDriver.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>SimdeviceUMDF</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>SimdeviceUMDF</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>SimdeviceUMDF</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>SimdeviceUMDF</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION>
+ <NTDDI_VERSION>0x0A000000</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION>
+ <NTDDI_VERSION>0x0A000000</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION>
+ <NTDDI_VERSION>0x0A000000</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION>
+ <NTDDI_VERSION>0x0A000000</NTDDI_VERSION>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="comsup.cpp" />
+ <ClCompile Include="device.cpp" />
+ <ClCompile Include="dllsup.cpp" />
+ <ClCompile Include="driver.cpp" />
+ <ClCompile Include="queue.cpp" />
+ <ResourceCompile Include="SimdeviceUMDF.rc" />
+ </ItemGroup>
+ <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/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters
new file mode 100644
index 00000000..db8bda4d
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/SimdeviceUMDF.vcxproj.Filters
@@ -0,0 +1,54 @@
+<?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>{7B1D3759-D374-48F4-8ADD-07752C95369D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{A065C827-3D09-4244-997C-14744BF574C4}</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>{9EB984ED-A895-4F5D-97FD-C72ACA844DAD}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3940722F-AA7D-4F6A-8A19-3CD74FCBD352}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\simdeviceUMDFDriver.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="simdeviceUMDFDriver.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="comsup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllsup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="queue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="exports.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="SimdeviceUMDF.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/gpio/samples/simdeviceumdf/comsup.cpp b/gpio/samples/simdeviceumdf/comsup.cpp
new file mode 100644
index 00000000..ccafeeaf
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/comsup.cpp
@@ -0,0 +1,344 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ ComSup.cpp
+
+Abstract:
+
+ This module contains implementations for the functions and methods
+ used for providing COM support.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "internal.h"
+
+//
+// Implementation of CUnknown methods.
+//
+
+CUnknown::CUnknown(
+ VOID
+ ) : m_ReferenceCount(1)
+/*++
+
+ Routine Description:
+
+ Constructor for an instance of the CUnknown class. This simply initializes
+ the reference count of the object to 1. The caller is expected to
+ call Release() if it wants to delete the object once it has been allocated.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ None
+
+--*/
+{
+ // do nothing.
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CUnknown::QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ )
+/*++
+
+ Routine Description:
+
+ This method provides the basic support for query interface on CUnknown.
+ If the interface requested is IUnknown it references the object and
+ returns an interface pointer. Otherwise it returns an error.
+
+ Arguments:
+
+ InterfaceId - the IID being requested
+
+ Object - a location to store the interface pointer to return.
+
+ Return Value:
+
+ S_OK or E_NOINTERFACE
+
+--*/
+{
+ if (IsEqualIID(InterfaceId, __uuidof(IUnknown)))
+ {
+ *Object = QueryIUnknown();
+ return S_OK;
+ }
+ else
+ {
+ *Object = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+IUnknown *
+CUnknown::QueryIUnknown(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This helper method references the object and returns a pointer to the
+ object's IUnknown interface.
+
+ This allows other methods to convert a CUnknown pointer into an IUnknown
+ pointer without a typecast and without calling QueryInterface and dealing
+ with the return value.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ A pointer to the object's IUnknown interface.
+
+--*/
+{
+ AddRef();
+ return static_cast<IUnknown *>(this);
+}
+
+ULONG
+STDMETHODCALLTYPE
+CUnknown::AddRef(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method adds one to the object's reference count.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ The new reference count. The caller should only use this for debugging
+ as the object's actual reference count can change while the caller
+ examines the return value.
+
+--*/
+{
+ return InterlockedIncrement(&m_ReferenceCount);
+}
+
+ULONG
+STDMETHODCALLTYPE
+CUnknown::Release(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method subtracts one to the object's reference count. If the count
+ goes to zero, this method deletes the object.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ The new reference count. If the caller uses this value it should only be
+ to check for zero (i.e. this call caused or will cause deletion) or
+ non-zero (i.e. some other call may have caused deletion, but this one
+ didn't).
+
+--*/
+{
+ ULONG count = InterlockedDecrement(&m_ReferenceCount);
+
+ if (count == 0)
+ {
+ delete this;
+ }
+ return count;
+}
+
+//
+// Implementation of CClassFactory methods.
+//
+
+//
+// Define storage for the factory's static lock count variable.
+//
+
+LONG CClassFactory::s_LockCount = 0;
+
+IClassFactory *
+CClassFactory::QueryIClassFactory(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This helper method references the object and returns a pointer to the
+ object's IClassFactory interface.
+
+ This allows other methods to convert a CClassFactory pointer into an
+ IClassFactory pointer without a typecast and without dealing with the
+ return value QueryInterface.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ A referenced pointer to the object's IClassFactory interface.
+
+--*/
+{
+ AddRef();
+ return static_cast<IClassFactory *>(this);
+}
+
+HRESULT
+CClassFactory::QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ )
+/*++
+
+ Routine Description:
+
+ This method attempts to retrieve the requested interface from the object.
+
+ If the interface is found then the reference count on that interface (and
+ thus the object itself) is incremented.
+
+ Arguments:
+
+ InterfaceId - the interface the caller is requesting.
+
+ Object - a location to store the interface pointer.
+
+ Return Value:
+
+ S_OK or E_NOINTERFACE
+
+--*/
+{
+ //
+ // This class only supports IClassFactory so check for that.
+ //
+
+ if (IsEqualIID(InterfaceId, __uuidof(IClassFactory)))
+ {
+ *Object = QueryIClassFactory();
+ return S_OK;
+ }
+ else
+ {
+ //
+ // See if the base class supports the interface.
+ //
+
+ return CUnknown::QueryInterface(InterfaceId, Object);
+ }
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CClassFactory::CreateInstance(
+ _In_opt_ IUnknown * /* OuterObject */,
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ )
+/*++
+
+ Routine Description:
+
+ This COM method is the factory routine - it creates instances of the driver
+ callback class and returns the specified interface on them.
+
+ Arguments:
+
+ OuterObject - only used for aggregation, which our driver callback class
+ does not support.
+
+ InterfaceId - the interface ID the caller would like to get from our
+ new object.
+
+ Object - a location to store the referenced interface pointer to the new
+ object.
+
+ Return Value:
+
+ Status.
+
+--*/
+{
+ HRESULT hr;
+
+ PCSimdeviceDriver driver;
+
+ *Object = NULL;
+
+ hr = CSimdeviceDriver::CreateInstance(&driver);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = driver->QueryInterface(InterfaceId, Object);
+ driver->Release();
+ }
+
+ return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CClassFactory::LockServer(
+ _In_ BOOL Lock
+ )
+/*++
+
+ Routine Description:
+
+ This COM method can be used to keep the DLL in memory. However since the
+ driver's DllCanUnloadNow function always returns false, this has little
+ effect. Still it tracks the number of lock and unlock operations.
+
+ Arguments:
+
+ Lock - Whether the caller wants to lock or unlock the "server"
+
+ Return Value:
+
+ S_OK
+
+--*/
+{
+ if (Lock)
+ {
+ InterlockedIncrement(&s_LockCount);
+ }
+ else
+ {
+ InterlockedDecrement(&s_LockCount);
+ }
+ return S_OK;
+}
+
+
diff --git a/gpio/samples/simdeviceumdf/comsup.h b/gpio/samples/simdeviceumdf/comsup.h
new file mode 100644
index 00000000..550c04e0
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/comsup.h
@@ -0,0 +1,217 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ ComSup.h
+
+Abstract:
+
+ This module contains classes and functions use for providing COM support
+ code.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+//
+// Forward type declarations. They are here rather than in internal.h as
+// you only need them if you choose to use these support classes.
+//
+
+typedef class CUnknown *PCUnknown;
+typedef class CClassFactory *PCClassFactory;
+
+//
+// Base class to implement IUnknown. You can choose to derive your COM
+// classes from this class, or simply implement IUnknown in each of your
+// classes.
+//
+
+class CUnknown : public IUnknown
+{
+
+//
+// Private data members and methods. These are only accessible by the methods
+// of this class.
+//
+private:
+
+ //
+ // The reference count for this object. Initialized to 1 in the
+ // constructor.
+ //
+
+ LONG m_ReferenceCount;
+
+//
+// Protected data members and methods. These are accessible by the subclasses
+// but not by other classes.
+//
+protected:
+
+ //
+ // The constructor and destructor are protected to ensure that only the
+ // subclasses of CUnknown can create and destroy instances.
+ //
+
+ CUnknown(
+ VOID
+ );
+
+ //
+ // The destructor MUST be virtual. Since any instance of a CUnknown
+ // derived class should only be deleted from within CUnknown::Release,
+ // the destructor MUST be virtual or only CUnknown::~CUnknown will get
+ // invoked on deletion.
+ //
+ // If you see that your CMyDevice specific destructor is never being
+ // called, make sure you haven't deleted the virtual destructor here.
+ //
+
+ virtual
+ ~CUnknown(
+ VOID
+ )
+ {
+ // Do nothing
+ }
+
+//
+// Public Methods. These are accessible by any class.
+//
+public:
+
+ IUnknown *
+ QueryIUnknown(
+ VOID
+ );
+
+//
+// COM Methods.
+//
+public:
+
+ //
+ // IUnknown methods
+ //
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ AddRef(
+ VOID
+ );
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ Release(
+ VOID
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+};
+
+//
+// Class factory support class. Create an instance of this from your
+// DllGetClassObject method and modify the implementation to create
+// an instance of your driver event handler class.
+//
+
+class CClassFactory : public CUnknown, public IClassFactory
+{
+//
+// Private data members and methods. These are only accessible by the methods
+// of this class.
+//
+private:
+
+ //
+ // The lock count. This is shared across all instances of IClassFactory
+ // and can be queried through the public IsLocked method.
+ //
+
+ static LONG s_LockCount;
+
+//
+// Public Methods. These are accessible by any class.
+//
+public:
+
+ IClassFactory *
+ QueryIClassFactory(
+ VOID
+ );
+
+//
+// COM Methods.
+//
+public:
+
+ //
+ // IUnknown methods
+ //
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ AddRef(
+ VOID
+ )
+ {
+ return __super::AddRef();
+ }
+
+ __drv_arg(this, __drv_freesMem(object))
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ Release(
+ VOID
+ )
+ {
+ return __super::Release();
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+
+ //
+ // IClassFactory methods.
+ //
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ CreateInstance(
+ _In_opt_ IUnknown *OuterObject,
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ LockServer(
+ _In_ BOOL Lock
+ );
+};
+
diff --git a/gpio/samples/simdeviceumdf/device.cpp b/gpio/samples/simdeviceumdf/device.cpp
new file mode 100644
index 00000000..0ced0bd1
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/device.cpp
@@ -0,0 +1,1106 @@
+/*++
+
+Copyright (c) 1990-2010 Microsoft Corporation
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ This is a simple UMDF device driver that consumes GPIO pins for I/O and interrupt.
+
+
+Environment:
+
+ UMDF
+
+--*/
+
+//
+// Inlcude the below set of headers to get the CM_RESOURCE_ definitions
+//
+
+
+#include "internal.h"
+
+DEFINE_GUID (GUID_DEVINTERFACE_ECHO,
+ 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a);
+// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A}
+
+
+HRESULT
+CSimdevice::CreateInstance(
+ _In_ IWDFDriver *FxDriver,
+ _In_ IWDFDeviceInitialize * FxDeviceInit,
+ _Out_ PCSimdevice *Device
+ )
+/*++
+
+ Routine Description:
+
+ This method creates and initializs an instance of the driver's
+ device callback object.
+
+ Arguments:
+
+ FxDeviceInit - the settings for the device.
+
+ Device - a location to store the referenced pointer to the device object.
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ PCSimdevice device;
+ HRESULT hr;
+
+ //
+ // Allocate a new instance of the device class.
+ //
+
+ device = new CSimdevice();
+
+ if (NULL == device) {
+ return E_OUTOFMEMORY;
+ }
+
+ //
+ // Initialize the instance.
+ //
+
+ hr = device->Initialize(FxDriver, FxDeviceInit);
+
+ if (SUCCEEDED(hr)) {
+ *Device = device;
+ }
+ else {
+ device->Release();
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::Initialize(
+ _In_ IWDFDriver * FxDriver,
+ _In_ IWDFDeviceInitialize * FxDeviceInit
+ )
+
+/*++
+
+ Routine Description:
+
+ This method initializes the device callback object and creates the
+ partner device object.
+
+ The method should perform any device-specific configuration that:
+ * could fail (these can't be done in the constructor)
+ * must be done before the partner object is created -or-
+ * can be done after the partner object is created and which aren't
+ influenced by any device-level parameters the parent (the driver
+ in this case) might set.
+
+ Arguments:
+
+ FxDeviceInit - the settings for this device.
+
+ Return Value:
+
+ status.
+
+--*/
+{
+ IWDFDevice *fxDevice;
+ IWDFDeviceInitialize2 *fxDeviceInit2;
+ HRESULT hr;
+
+ //
+ // Configure things like the locking model before we go to create our
+ // partner device.
+ //
+
+ //
+ // Set no locking unless you need an automatic callbacks synchronization
+ //
+
+ FxDeviceInit->SetLockingConstraint(None);
+
+ //
+ // Create a new FX device object and assign the new callback object to
+ // handle any device level events that occur.
+ //
+
+ //
+ // Set retrieval mode to direct I/O. This needs to be done before the call
+ // to CreateDevice.
+ //
+
+ FxDeviceInit->QueryInterface(IID_PPV_ARGS(&fxDeviceInit2));
+
+ if (fxDeviceInit2 == NULL) {
+ hr = E_FAIL;
+ return hr;
+ }
+
+ fxDeviceInit2->SetIoTypePreference(WdfDeviceIoBufferRetrievalDeferred,
+ WdfDeviceIoDirect,
+ WdfDeviceIoDirect);
+
+ SAFE_RELEASE(fxDeviceInit2);
+
+ //
+ // QueryIUnknown references the IUnknown interface that it returns
+ // (which is the same as referencing the device). We pass that to
+ // CreateDevice, which takes its own reference if everything works.
+ //
+
+ {
+ IUnknown *unknown = this->QueryIUnknown();
+
+ hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice);
+
+ unknown->Release();
+ }
+
+ //
+ // If that succeeded then set our FxDevice member variable.
+ //
+
+ if (SUCCEEDED(hr)) {
+ m_FxDevice = fxDevice;
+
+ //
+ // Drop the reference we got from CreateDevice. Since this object
+ // is partnered with the framework object they have the same
+ // lifespan - there is no need for an additional reference.
+ //
+
+ fxDevice->Release();
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::Configure(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method is called after the device callback object has been initialized
+ and returned to the driver. It would setup the device's queues and their
+ corresponding callback objects.
+
+ Arguments:
+
+ FxDevice - the framework device object for which we're handling events.
+
+ Return Value:
+
+ status
+
+--*/
+{
+ PCSimdeviceQueue defaultQueue;
+
+ HRESULT hr;
+
+ hr = CSimdeviceQueue::CreateInstance(m_FxDevice, &defaultQueue);
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = defaultQueue->Configure();
+
+ if (SUCCEEDED(hr)) {
+ //
+ // In case of success store defaultQueue in our member
+ // The reference is transferred to m_DefaultQueue
+ //
+
+ m_Queue = defaultQueue;
+ }
+ else {
+ //
+ // In case of failure release the reference
+ //
+
+ defaultQueue->Release();
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_ECHO,
+ NULL);
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ )
+/*++
+
+ Routine Description:
+
+ This method is called to get a pointer to one of the object's callback
+ interfaces.
+
+ Since the sample driver doesn't support any of the device events, this
+ method simply calls the base class's BaseQueryInterface.
+
+ If the sample is extended to include device event interfaces then this
+ method must be changed to check the IID and return pointers to them as
+ appropriate.
+
+ Arguments:
+
+ InterfaceId - the interface being requested
+
+ Object - a location to store the interface pointer if successful
+
+ Return Value:
+
+ S_OK or E_NOINTERFACE
+
+--*/
+{
+ HRESULT hr;
+
+ if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackSelfManagedIo))) {
+ *Object = QueryIPnpCallbackSelfManagedIo();
+ hr = S_OK;
+ } else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackHardware2))) {
+ *Object = QueryIPnpCallbackHardware2();
+ hr = S_OK;
+ } else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallback))) {
+ *Object = QueryIPnpCallback();
+ hr = S_OK;
+ } else {
+ hr = CUnknown::QueryInterface(InterfaceId, Object);
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::OnSelfManagedIoInit(
+ _In_ IWDFDevice * pWdfDevice
+ )
+/*++
+
+ Routine Description:
+
+ This method is called to allow driver to initialize any resources
+ that driver might need to process I/O.
+
+ Echo driver needs a thread to process completions. We initialize
+ this thread here
+
+ Arguments:
+
+ pWdfDevice - framework device object for which to initialze resources
+
+ Return Value:
+
+ S_OK in case of success
+ HRESULT correponding to error returned by CreateThread, in case of failure
+
+--*/
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+
+
+ m_ThreadHandle = CreateThread( NULL, // Default Security Attrib.
+ 0, // Initial Stack Size,
+ CSimdeviceQueue::CompletionThread, // Thread Func
+ (LPVOID)m_Queue, // Arg to Thread Func is Queue
+ 0, // Creation Flags
+ NULL ); // Don't need the Thread Id.
+
+ if (m_ThreadHandle == NULL) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ return hr;
+}
+
+void
+CSimdevice::OnSelfManagedIoCleanup(
+ _In_ IWDFDevice * pWdfDevice
+ )
+/*++
+
+ Routine Description:
+
+ This method is called to allow driver to cleanup any resources
+ that driver allocated to process I/O.
+
+ It is critical that, in this routine driver wait for all of the
+ threads which it created to exit. Otherwise those threads could
+ continue to execute when framework unloads the driver which
+ would lead to a crash.
+
+ Echo driver created a thread to handle completions. We wait for
+ that thread to exit in this routine
+
+ Arguments:
+
+ pWdfDevice - framework device object for which to cleanup resources
+
+ Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Kill the thread and
+ // wait for the thread to die.
+ //
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+
+ if (m_ThreadHandle) {
+
+ //
+ // Ask queue to set terminate flag which will make
+ // the thread exit
+ //
+
+ m_Queue->SetExitThread();
+
+ //
+ // Wait for the thread to exit
+ //
+
+ WaitForSingleObject(m_ThreadHandle, INFINITE);
+
+ //
+ // Close the thread handle
+ //
+
+ CloseHandle(m_ThreadHandle);
+ m_ThreadHandle = NULL;
+ }
+
+ //
+ // Release the reference we took on the queue callback object
+ // to keep it alive until the thread exits
+ //
+
+ SAFE_RELEASE(m_Queue);
+}
+
+
+HRESULT
+CSimdevice::OnPrepareHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesRaw,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by WUDF to initialize hardware resources (e.g. interrupts,
+ IO resources)
+
+Arguments:
+
+ pWdfDevice - pointer to an IWDFDevice object for the device
+
+ pWdfResourcesRaw - Supplies a pointer to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ pWdfResourcesTranslated - Supplies a pointer to a collection of framework
+ resource objects. This collection identifies the translated
+ (system-physical) hardware resources that have been assigned to the
+ device. The resources appear from the CPU's point of view.
+
+Return Value:
+
+ HRESULT
+
+--*/
+{
+
+ ULONG i;
+ HRESULT hr = S_OK;
+ ULONG ConnectionCount = 0;
+ BOOLEAN fInterruptFound = FALSE;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorTranslated;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw;
+
+ //
+ // Parse the resource list and save the resource information.
+ //
+
+ for (i=0; i < pWdfResourcesTranslated->GetCount(); i++) {
+
+ DescriptorTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)pWdfResourcesTranslated->GetDescriptor(i);
+ DescriptorRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)pWdfResourcesRaw->GetDescriptor(i);
+
+ if(DescriptorTranslated == NULL) {
+ return E_FAIL;
+ }
+
+ switch (DescriptorTranslated->Type) {
+
+ //
+ // One or more GPIO IO resources are expected. In this implementation of the sample
+ // driver, however, only the first IO resource will be used (see OnD0Entry).
+ //
+
+ case CmResourceTypeConnection:
+
+ //
+ // Check against expected connection type for a GPIO IO descriptor
+ //
+
+ if ((DescriptorTranslated->u.Connection.Class ==
+ CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
+ (DescriptorTranslated->u.Connection.Type ==
+ CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {
+
+ if (ConnectionCount >= MAX_CONNECTIONS) {
+ break;
+ }
+
+ //
+ // Store GPIO IO resource connection ID in the device extension
+ //
+
+ this->GetDeviceExtension()->ConnectionId[ConnectionCount].LowPart =
+ DescriptorTranslated->u.Connection.IdLowPart;
+
+ this->GetDeviceExtension()->ConnectionId[ConnectionCount].HighPart =
+ DescriptorTranslated->u.Connection.IdHighPart;
+ }
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ //
+ // Connect the first interrupt resource we find
+ //
+
+ if (fInterruptFound == FALSE) {
+ hr = this->SimdeviceConnectInterrupt(
+ pWdfDevice,
+ DescriptorRaw,
+ DescriptorTranslated);
+
+ if (SUCCEEDED(hr)) {
+ fInterruptFound = TRUE;
+ }
+ }
+ default:
+
+ //
+ // Ignore all other descriptors
+ //
+
+ break;
+ }
+ }
+
+ return hr;
+
+}
+
+HRESULT
+CSimdevice::OnReleaseHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ )
+/*++
+
+
+Routine Description:
+
+ This method is called by WUDF to uninitialize the hardware.
+
+Parameters:
+
+ pWdfDevice - pointer to an IWDFDevice object for the device
+
+ pWdfResourcesTranslated - pointer to the translated resource list
+
+Return Values:
+ status
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(pWdfResourcesTranslated);
+
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::OnD0Entry(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE previousState
+ )
+
+/*++
+
+Routine Description:
+
+This method is called after a new device enters the system
+
+Parameters:
+
+ pWdfDevice - pointer to a device object
+
+ previousState - previous WDF power state
+
+Return Values:
+ status
+
+--*/
+{
+
+ PDEVICE_EXTENSION DevExt;
+ HRESULT hr = S_OK;
+ BYTE Data;
+ NTSTATUS Status;
+ NTSTATUS Status1;
+ WCHAR ReadStringBuffer[100];
+ WCHAR WriteStringBuffer[100];
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(previousState);
+
+ DevExt = GetDeviceExtension();
+
+ Status = StringCbPrintfW(&ReadStringBuffer[0],
+ sizeof(ReadStringBuffer),
+ L"\\\\.\\RESOURCE_HUB\\%0*I64x",
+ (size_t)(sizeof(LARGE_INTEGER) * 2),
+ DevExt->ConnectionId[0].QuadPart);
+
+ Status = StringCbPrintfW(&WriteStringBuffer[0],
+ sizeof(WriteStringBuffer),
+ L"\\\\.\\RESOURCE_HUB\\%0*I64x",
+ (size_t)(sizeof(LARGE_INTEGER) * 2),
+ DevExt->ConnectionId[0].QuadPart);
+
+ //
+ // Connect the first GPIO IO descriptor we find (in OnPrepareHardware) for read and write operations
+ //
+
+ Data = 0xDB;
+ Status = STATUS_SUCCESS;
+ Status1 = TestReadWrite(pWdfDevice, &WriteStringBuffer[0], FALSE, &Data, sizeof(Data), NULL);
+ if (!NT_SUCCESS(Status1)) {
+ Status = Status1;
+ }
+
+ Data = 0;
+ Status1 = TestReadWrite(pWdfDevice, &ReadStringBuffer[0], TRUE, &Data, sizeof(Data), NULL);
+ if (!NT_SUCCESS(Status1)) {
+ Status = Status1;
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::OnD0Exit(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+
+/*++
+
+Routine Description:
+
+This method is called when a device exit D0
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+ TargetState - target D-state
+
+Return Values:
+ status
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(TargetState);
+
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::TestReadWrite(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ PWSTR RequestString,
+ _In_ BOOLEAN ReadOperation,
+ _Inout_updates_bytes_(Size) UCHAR *Data,
+ _In_ ULONG Size,
+ _Inout_opt_ IWDFRemoteTarget *IoTargetOut
+ )
+
+/*++
+
+Routine Description:
+
+ This is a utility routine to test read or write on a set of GPIO pins.
+
+Arguments:
+
+ pWdfDevice - Supplies a pointer to the framework device object.
+
+ RequestString - Supplies a pointer to the unicode string to be opened.
+
+ ReadOperation - Supplies a boolean that identifies whether read (TRUE) or
+ write (FALSE) should be performed.
+
+ Data - Supplies a pointer containing the buffer that should be read from
+ or written to.
+
+ Size - Supplies the size of the data buffer in bytes.
+
+ IoTargetOut - Supplies a pointer that receives the IOTARGET created by
+ UMDF.
+
+Return Value:
+
+ HRESULT
+
+--*/
+
+{
+
+ IWDFMemory *pOutputMemory = NULL;
+ IWDFMemory *pInputMemory = NULL;
+ IRequestCallbackRequestCompletion *pICallback = NULL;
+ IWDFIoRequest *pIoRequest = NULL;
+ IWDFRemoteTarget *pRemoteTarget = NULL;
+ UMDF_IO_TARGET_OPEN_PARAMS OpenParams;
+ DWORD DesiredAccess;
+ HRESULT hr = S_OK;
+ IWDFRequestCompletionParams * FxComplParams = NULL;
+ IWDFDriver *pWdfDriver = NULL;
+
+ UNREFERENCED_PARAMETER(IoTargetOut);
+
+ if (ReadOperation != FALSE) {
+ DesiredAccess = FILE_GENERIC_READ;
+
+ } else {
+ DesiredAccess = FILE_GENERIC_WRITE;
+ }
+
+ //
+ // QueryIUnknown references the IUnknown interface that it returns
+ // (which is the same as referencing the CMyRemoteTarget). We pass that
+ // to the various Create* calls, which take their own reference if
+ // everything works.
+ //
+
+ IUnknown * unknown = this->QueryIUnknown();
+
+
+ IWDFDevice2 *pWdfDevice2 = NULL;
+ hr = pWdfDevice->QueryInterface(IID_PPV_ARGS(&pWdfDevice2));
+
+ // Create the IoTarget
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice2->CreateRemoteTarget(
+ unknown,
+ NULL,
+ &pRemoteTarget);
+ }
+
+ //
+ // Determine whether the request is a read or write
+ //
+
+ OpenParams.dwCreationDisposition = OPEN_EXISTING;
+ OpenParams.dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
+ OpenParams.dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->OpenFileByName(RequestString,
+ DesiredAccess,
+ &OpenParams);
+ }
+
+ //
+ //Create a new IO request
+ //
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice->CreateRequest(NULL, pWdfDevice, &pIoRequest);
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = this->QueryInterface(__uuidof(IRequestCallbackRequestCompletion), (PVOID*)&pICallback);
+
+ //
+ //Set completion callback
+ //
+
+ if (SUCCEEDED(hr)){
+ pIoRequest->SetCompletionCallback(pICallback, NULL);
+ }
+
+ pWdfDevice->GetDriver(&pWdfDriver);
+
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(Data,
+ Size,
+ NULL, // no object event callback
+ pIoRequest, // request object as parent
+ &pInputMemory);
+
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(Data,
+ Size,
+ NULL, // no object event callback
+ pIoRequest, // request object as parent
+ &pOutputMemory);
+
+ //
+ //Format IO request
+ //
+
+ if (ReadOperation != FALSE){
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->FormatRequestForIoctl(pIoRequest,
+ IOCTL_GPIO_READ_PINS,
+ NULL,
+ NULL,
+ NULL,
+ pOutputMemory,
+ NULL);
+ }
+ }
+ else {
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->FormatRequestForIoctl(pIoRequest,
+ IOCTL_GPIO_WRITE_PINS,
+ NULL,
+ pInputMemory,
+ NULL,
+ pOutputMemory,
+ NULL);
+ }
+ }
+
+ //
+ //Send down the request
+ //
+ if (SUCCEEDED(hr)) {
+ hr = pIoRequest->Send(pRemoteTarget,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
+ 0); //No timeout
+ }
+
+ if (SUCCEEDED(hr)) {
+
+ //
+ //Get IWDFRequestCompletionParams interface and then get completion status.
+ //
+
+ pIoRequest->GetCompletionParams(&FxComplParams);
+ hr = FxComplParams->GetCompletionStatus();
+ }
+
+ if(FAILED(hr)) {
+ pIoRequest->DeleteWdfObject();
+ pIoRequest = NULL;
+ }
+ }
+
+ //
+ // Clean-up
+ //
+
+ if (pWdfDevice2 != NULL) {
+ SAFE_RELEASE(pWdfDevice2);
+ }
+
+ if (pWdfDriver != NULL) {
+ SAFE_RELEASE(pWdfDriver);
+ }
+
+ if (pRemoteTarget != NULL) {
+ pRemoteTarget->Close();
+ }
+
+ return hr;
+}
+
+
+void
+CSimdevice::OnSurpriseRemoval(
+ _In_ IWDFDevice* pWdfDevice
+ )
+
+/*++
+
+Routine Description:
+
+This method is called when a device is surprise removed
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+}
+
+
+HRESULT
+CSimdevice::OnQueryRemove(
+ _In_ IWDFDevice* pWdfDevice
+ )
+/*++
+
+Routine Description:
+
+This method is called when a device processes the query remove IRP
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ HRESULT
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::OnQueryStop(
+ _In_ IWDFDevice* pWdfDevice
+ )
+/*++
+
+Routine Description:
+
+This method is called when a device processes the query stop IRP
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ HRESULT
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::SimdeviceConnectInterrupt(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR RawResource,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedResource
+ )
+
+/*++
+
+Routine Description:
+
+ This is a utility routine to create an interrupt descriptor from the interrupt resource
+ acquired from OnPrepareHardware and connect the device ISR routine.
+Arguments:
+
+ pWdfDevice - Supplies a pointer to the framework device object.
+
+ pWdfResourcesRaw - Supplies a pointer to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ pWdfResourcesTranslated - Supplies a pointer to a collection of framework
+ resource objects. This collection identifies the translated
+ (system-physical) hardware resources that have been assigned to the
+ device. The resources appear from the CPU's point of view.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IWDFDevice3 * pIWDFDevice3 = NULL;
+ IWDFInterrupt * spInterrupt = NULL;
+ HRESULT hr = S_OK;
+
+ if (pWdfDevice == NULL) {
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice->QueryInterface(IID_PPV_ARGS(&pIWDFDevice3));
+ }
+
+ if (SUCCEEDED(hr)) {
+
+ //
+ // Create interrupt
+ //
+
+ WUDF_INTERRUPT_CONFIG config;
+ WUDF_INTERRUPT_CONFIG_INIT(
+ &config,
+ &CSimdevice::OnInterruptIsr,
+ &CSimdevice::OnInterruptWorkItem);
+
+ config.InterruptRaw = RawResource;
+ config.InterruptTranslated = TranslatedResource;
+
+ hr = pIWDFDevice3->CreateInterrupt(&config, &spInterrupt);
+ }
+
+ //
+ // Associate the device context with the interrupt
+ //
+
+ if (SUCCEEDED(hr)) {
+ hr = spInterrupt->AssignContext(NULL, (void*)this);
+ }
+
+ return hr;
+}
+
+BOOLEAN
+CSimdevice::OnInterruptIsr(
+ _In_ IWDFInterrupt* pInterrupt,
+ _In_ ULONG MessageID,
+ _In_ ULONG Reserved
+ )
+
+/* ++
+
+Routine Description:
+
+ This method is called when an interrupt occurs. It determines if the
+ driver owns the interrupt and queues a work item to defer processing
+ of the data.
+
+ Arguments:
+
+ pInterrupt - pointer to the interrupt object
+ MessageID - interrupt message ID
+ Reserved -
+
+Return Values:
+ TRUE if interrupt recognized, else FALSE.
+
+-- */
+
+{
+
+ UNREFERENCED_PARAMETER(MessageID);
+ UNREFERENCED_PARAMETER(Reserved);
+
+ IWDFDevice* pWdfDevice = NULL;
+ CSimdevice* pMyDevice = NULL;
+ HRESULT hr;
+
+ hr = pInterrupt->RetrieveContext((void**)&pMyDevice);
+
+ if (FAILED(hr)) {
+ pWdfDevice = pInterrupt->GetDevice();
+ pWdfDevice->SetPnpState(WdfPnpStateFailed, WdfTrue);
+ pWdfDevice->CommitPnpState();
+ }
+
+ //
+ // The sample driver always returns TRUE (e.g. claiming the interrupt)
+ // from its ISR. In reality, the driver needs to do whatever necessary to
+ // quiesce the interrupt before claiming the interrupt.
+ // If additional work needs to be done at , schedule a work item (as we do here).
+ //
+
+ pInterrupt->QueueWorkItemForIsr();
+
+ return TRUE;
+}
+
+VOID
+CSimdevice::OnInterruptWorkItem(
+ _In_ IWDFInterrupt* pInterrupt,
+ _In_ IWDFObject* AssociatedObject
+ )
+
+/* ++
+
+Routine Description:
+
+ This method is called on behalf of an interrupt to defer processing.
+ It retrieves latest data and posts it.
+
+Arguments:
+ pInterrupt - pointer to the interrupt object
+ AssociatedObject - pointer to the associated object
+
+Return Values:
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(AssociatedObject);
+
+ IWDFDevice* pWdfDevice = NULL;
+ CSimdevice* pMyDevice;
+ HRESULT hr;
+
+ hr = pInterrupt->RetrieveContext((void**)&pMyDevice);
+
+ if (FAILED(hr)) {
+ pWdfDevice = pInterrupt->GetDevice();
+ pWdfDevice->SetPnpState(WdfPnpStateFailed, WdfTrue);
+ pWdfDevice->CommitPnpState();
+ }
+
+
+ //
+ // The sample driver does nothing in the work item routine. The real driver
+ // can add code here to accomplish all that is required to complete the serving
+ // of the interrupt
+ //
+
+ return;
+}
+
+
diff --git a/gpio/samples/simdeviceumdf/device.h b/gpio/samples/simdeviceumdf/device.h
new file mode 100644
index 00000000..e0ceb68c
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/device.h
@@ -0,0 +1,365 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Device.h
+
+Abstract:
+
+ This module contains the type definitions for the UMDF Echo sample
+ driver's device callback class.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+#include "queue.h"
+
+#define MAX_CONNECTIONS (4)
+#define MAX_RESOURCES (10)
+
+
+//
+// The device extension for the device object
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ CSimdevice* MyDevice;
+
+ IWDFDevice* Device;
+ IWDFDevice3* Device3;
+
+ IWDFCmResourceList* CmResourceList;
+
+ LARGE_INTEGER ConnectionId[MAX_CONNECTIONS];
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+//
+// Class for the simdevice driver.
+//
+
+class CSimdevice :
+ public CUnknown,
+ public IPnpCallbackSelfManagedIo,
+ public IPnpCallbackHardware2,
+ public IPnpCallback
+{
+
+//
+// Private data members.
+//
+private:
+
+ IWDFDevice *m_FxDevice;
+
+ //
+ // Completion Thread handle used by queue callback object
+ //
+ HANDLE m_ThreadHandle;
+
+ //
+ // Our queue callback object
+ // Strong reference - since we pass it to the thread we create
+ //
+ CSimdeviceQueue *m_Queue;
+
+ //
+ // device data
+ //
+ DEVICE_EXTENSION m_DevExtension;
+
+//
+// Private methods.
+//
+
+private:
+
+ CSimdevice(
+ VOID
+ )
+ {
+ m_FxDevice = NULL;
+ ZeroMemory(&m_DevExtension, sizeof(DEVICE_EXTENSION));
+ }
+
+ HRESULT
+ Initialize(
+ _In_ IWDFDriver *FxDriver,
+ _In_ IWDFDeviceInitialize *FxDeviceInit
+ );
+
+ IPnpCallbackSelfManagedIo *
+ QueryIPnpCallbackSelfManagedIo(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IPnpCallbackSelfManagedIo *>(this);
+ }
+
+ IPnpCallback *
+ QueryIPnpCallback(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IPnpCallback *>(this);
+ }
+
+ IPnpCallbackHardware2 *
+ QueryIPnpCallbackHardware2(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IPnpCallbackHardware2 *>(this);
+ }
+
+
+//
+// Public methods
+//
+public:
+
+ //
+ // The factory method used to create an instance of this driver.
+ //
+
+ static
+ HRESULT
+ CreateInstance(
+ _In_ IWDFDriver *FxDriver,
+ _In_ IWDFDeviceInitialize *FxDeviceInit,
+ _Out_ PCSimdevice *Device
+ );
+
+ HRESULT
+ Configure(
+ VOID
+ );
+
+//
+// COM methods
+//
+public:
+
+ //
+ // IUnknown methods.
+ //
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ AddRef(
+ VOID
+ )
+ {
+ return __super::AddRef();
+ }
+
+ __drv_arg(this, __drv_freesMem(object))
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ Release(
+ VOID
+ )
+ {
+ return __super::Release();
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+
+ //
+ // IPnpCallbackSelfManagedIo methods
+ //
+
+ //
+ // We implement this interface to create and tear down
+ // our completion thread
+ //
+ // It is critical that we wait for all the threads we create
+ // to exit during OnSelfManagedIoCleanup, otherwise thread
+ // may continue to execute when framework unloads the driver,
+ // leading to a crash
+ //
+ // We don't manage any I/O separate from the queue, so apart
+ // from OnSelfManagedIoInit and OnSelfManagedIoCleanup, other
+ // methods have token implementations
+ //
+
+ virtual
+ void
+ STDMETHODCALLTYPE
+ OnSelfManagedIoCleanup(
+ _In_ IWDFDevice * pWdfDevice
+ );
+
+ virtual
+ void
+ STDMETHODCALLTYPE
+ OnSelfManagedIoFlush(
+ _In_ IWDFDevice * pWdfDevice
+ )
+ {
+ UNREFERENCED_PARAMETER( pWdfDevice );
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnSelfManagedIoInit(
+ _In_ IWDFDevice * pWdfDevice
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnSelfManagedIoSuspend(
+ _In_ IWDFDevice * pWdfDevice
+ )
+ {
+ UNREFERENCED_PARAMETER( pWdfDevice );
+
+ return S_OK;
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnSelfManagedIoRestart(
+ _In_ IWDFDevice * pWdfDevice
+ )
+ {
+ UNREFERENCED_PARAMETER( pWdfDevice );
+
+ return S_OK;
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnSelfManagedIoStop(
+ _In_ IWDFDevice * pWdfDevice
+ )
+ {
+ UNREFERENCED_PARAMETER( pWdfDevice );
+
+ return S_OK;
+ }
+
+ //
+ // IPnpCallback
+ //
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnD0Entry(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE previousState
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnD0Exit(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE previousState
+ );
+
+ virtual
+ void
+ STDMETHODCALLTYPE
+ OnSurpriseRemoval(
+ _In_ IWDFDevice* pWdfDevice
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnQueryRemove(
+ _In_ IWDFDevice* pWdfDevice
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnQueryStop(
+ _In_ IWDFDevice* pWdfDevice
+ );
+
+ //
+ // IPnpCallbackHardware2
+ //
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnPrepareHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesRaw,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ );
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnReleaseHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ );
+
+ HRESULT
+ SimdeviceConnectInterrupt(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR RawResource,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedResource
+ );
+
+ static WUDF_INTERRUPT_ISR OnInterruptIsr;
+ static WUDF_INTERRUPT_WORKITEM OnInterruptWorkItem;
+
+ IWDFDevice *
+ GetFxDevice(
+ VOID
+ )
+ {
+ return m_FxDevice;
+ }
+
+ PDEVICE_EXTENSION
+ GetDeviceExtension(
+ VOID
+ )
+ {
+ return &m_DevExtension;
+ }
+
+ HRESULT
+ TestReadWrite(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ PWSTR RequestString,
+ _In_ BOOLEAN ReadOperation,
+ _Inout_updates_bytes_(Size) UCHAR *Data,
+ _In_ ULONG Size,
+ _Inout_opt_ IWDFRemoteTarget *IoTargetOut
+ );
+
+};
+
diff --git a/gpio/samples/simdeviceumdf/dllsup.cpp b/gpio/samples/simdeviceumdf/dllsup.cpp
new file mode 100644
index 00000000..7b0ea74d
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/dllsup.cpp
@@ -0,0 +1,151 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ dllsup.cpp
+
+Abstract:
+
+ This module contains the implementation of the sample UMDF Driver's
+ entry point and its exported functions for providing COM support.
+
+ This module can be copied without modification to a new UMDF driver. It
+ depends on some of the code in comsup.cpp & comsup.h to handle DLL
+ registration and creating the first class factory.
+
+ This module is dependent on the following defines:
+
+ MYDRIVER_CLASS_ID - A GUID encoded in struct format used to
+ initialize the driver's ClassID.
+
+ These are defined in internal.h for the sample. If you choose
+ to use a different primary include file, you should ensure they are
+ defined there as well.
+
+
+Environment:
+
+ WDF User-Mode Driver Framework (WDF:UMDF)
+
+--*/
+
+#include "internal.h"
+
+const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID;
+
+BOOL
+WINAPI
+DllMain(
+ HINSTANCE ModuleHandle,
+ DWORD Reason,
+ PVOID /* Reserved */
+ )
+/*++
+
+ Routine Description:
+
+ This is the entry point and exit point for the I/O trace driver. This
+ does very little as the I/O trace driver has minimal global data.
+
+ This method initializes tracing.
+
+ Arguments:
+
+ ModuleHandle - the DLL handle for this module.
+
+ Reason - the reason this entry point was called.
+
+ Reserved - unused
+
+ Return Value:
+
+ TRUE
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(ModuleHandle);
+ UNREFERENCED_PARAMETER(Reason);
+
+ return TRUE;
+}
+
+_Check_return_
+STDAPI
+DllGetClassObject(
+ _In_ REFCLSID ClassId,
+ _In_ REFIID InterfaceId,
+ _Outptr_ LPVOID *Interface
+ )
+/*++
+
+ Routine Description:
+
+ This routine is called by COM in order to instantiate the
+ driver callback object and do an initial query interface on it.
+
+ This method only creates an instance of the driver's class factory, as this
+ is the minimum required to support UMDF.
+
+ Arguments:
+
+ ClassId - the CLSID of the object being "gotten"
+
+ InterfaceId - the interface the caller wants from that object.
+
+ Interface - a location to store the referenced interface pointer
+
+ Return Value:
+
+ S_OK if the function succeeds or error indicating the cause of the
+ failure.
+
+--*/
+{
+ PCClassFactory factory;
+
+ HRESULT hr = S_OK;
+
+ *Interface = NULL;
+
+ //
+ // If the CLSID doesn't match that of our "coclass" (defined in the IDL
+ // file) then we can't create the object the caller wants. This may
+ // indicate that the COM registration is incorrect, and another CLSID
+ // is referencing this drvier.
+ //
+
+ if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false)
+ {
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ //
+ // Create an instance of the class factory for the caller.
+ //
+
+ factory = new CClassFactory();
+
+ if (NULL == factory)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+ //
+ // Query the object we created for the interface the caller wants. After
+ // that we release the object. This will drive the reference count to
+ // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed).
+ // In the later case the object is automatically deleted.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = factory->QueryInterface(InterfaceId, Interface);
+ factory->Release();
+ }
+
+ return hr;
+}
+
diff --git a/gpio/samples/simdeviceumdf/driver.cpp b/gpio/samples/simdeviceumdf/driver.cpp
new file mode 100644
index 00000000..09f47062
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/driver.cpp
@@ -0,0 +1,222 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Driver.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF Sample's
+ core driver callback object.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "internal.h"
+//#include "driver.tmh"
+
+HRESULT
+CSimdeviceDriver::CreateInstance(
+ _Out_ PCSimdeviceDriver *Driver
+ )
+/*++
+
+ Routine Description:
+
+ This static method is invoked in order to create and initialize a new
+ instance of the driver class. The caller should arrange for the object
+ to be released when it is no longer in use.
+
+ Arguments:
+
+ Driver - a location to store a referenced pointer to the new instance
+
+ Return Value:
+
+ S_OK if successful, or error otherwise.
+
+--*/
+{
+ PCSimdeviceDriver driver;
+ HRESULT hr;
+
+ //
+ // Allocate the callback object.
+ //
+
+ driver = new CSimdeviceDriver();
+
+ if (NULL == driver)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ //
+ // Initialize the callback object.
+ //
+
+ hr = driver->Initialize();
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // Store a pointer to the new, initialized object in the output
+ // parameter.
+ //
+
+ *Driver = driver;
+ }
+ else
+ {
+
+ //
+ // Release the reference on the driver object to get it to delete
+ // itself.
+ //
+
+ driver->Release();
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdeviceDriver::Initialize(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method is called to initialize a newly created driver callback object
+ before it is returned to the creator. Unlike the constructor, the
+ Initialize method contains operations which could potentially fail.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ None
+
+--*/
+{
+ return S_OK;
+}
+
+HRESULT
+CSimdeviceDriver::QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Interface
+ )
+/*++
+
+ Routine Description:
+
+ This method returns a pointer to the requested interface on the callback
+ object..
+
+ Arguments:
+
+ InterfaceId - the IID of the interface to query/reference
+
+ Interface - a location to store the interface pointer.
+
+ Return Value:
+
+ S_OK if the interface is supported.
+ E_NOINTERFACE if it is not supported.
+
+--*/
+{
+ if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry)))
+ {
+ *Interface = QueryIDriverEntry();
+ return S_OK;
+ }
+ else
+ {
+ return CUnknown::QueryInterface(InterfaceId, Interface);
+ }
+}
+
+HRESULT
+CSimdeviceDriver::OnDeviceAdd(
+ _In_ IWDFDriver *FxWdfDriver,
+ _In_ IWDFDeviceInitialize *FxDeviceInit
+ )
+/*++
+
+ Routine Description:
+
+ The FX invokes this method when it wants to install our driver on a device
+ stack. This method creates a device callback object, then calls the Fx
+ to create an Fx device object and associate the new callback object with
+ it.
+
+ Arguments:
+
+ FxWdfDriver - the Fx driver object.
+
+ FxDeviceInit - the initialization information for the device.
+
+ Return Value:
+
+ status
+
+--*/
+{
+ HRESULT hr;
+
+ PCSimdevice device = NULL;
+
+ //
+ // TODO: Do any per-device initialization (reading settings from the
+ // registry for example) that's necessary before creating your
+ // device callback object here. Otherwise you can leave such
+ // initialization to the initialization of the device event
+ // handler.
+ //
+
+ //
+ // Create a new instance of our device callback object
+ //
+
+ hr = CSimdevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device);
+
+ //
+ // TODO: Change any per-device settings that the object exposes before
+ // calling Configure to let it complete its initialization.
+ //
+
+ //
+ // If that succeeded then call the device's construct method. This
+ // allows the device to create any queues or other structures that it
+ // needs now that the corresponding fx device object has been created.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = device->Configure();
+ }
+
+ //
+ // Release the reference on the device callback object now that it's been
+ // associated with an fx device object.
+ //
+
+ if (NULL != device)
+ {
+ device->Release();
+ }
+
+ return hr;
+}
+
diff --git a/gpio/samples/simdeviceumdf/driver.h b/gpio/samples/simdeviceumdf/driver.h
new file mode 100644
index 00000000..a8f464be
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/driver.h
@@ -0,0 +1,151 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Driver.h
+
+Abstract:
+
+ This module contains the type definitions for the UMDF sample's
+ driver callback class.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+//
+// This class handles driver events for the sample. In particular
+// it supports the OnDeviceAdd event, which occurs when the driver is called
+// to setup per-device handlers for a new device stack.
+//
+
+class CSimdeviceDriver : public CUnknown, public IDriverEntry
+{
+//
+// Private data members.
+//
+private:
+
+//
+// Private methods.
+//
+private:
+
+ //
+ // Returns a refernced pointer to the IDriverEntry interface.
+ //
+
+ IDriverEntry *
+ QueryIDriverEntry(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IDriverEntry*>(this);
+ }
+
+ HRESULT
+ Initialize(
+ VOID
+ );
+
+//
+// Public methods
+//
+public:
+
+ //
+ // The factory method used to create an instance of this driver.
+ //
+
+ static
+ HRESULT
+ CreateInstance(
+ _Out_ PCSimdeviceDriver *Driver
+ );
+
+//
+// COM methods
+//
+public:
+
+ //
+ // IDriverEntry methods
+ //
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnInitialize(
+ _In_ IWDFDriver *FxWdfDriver
+ )
+ {
+ UNREFERENCED_PARAMETER( FxWdfDriver );
+
+ return S_OK;
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ OnDeviceAdd(
+ _In_ IWDFDriver *FxWdfDriver,
+ _In_ IWDFDeviceInitialize *FxDeviceInit
+ );
+
+ virtual
+ VOID
+ STDMETHODCALLTYPE
+ OnDeinitialize(
+ _In_ IWDFDriver *FxWdfDriver
+ )
+ {
+ UNREFERENCED_PARAMETER( FxWdfDriver );
+
+ return;
+ }
+
+ //
+ // IUnknown methods.
+ //
+ // We have to implement basic ones here that redirect to the
+ // base class becuase of the multiple inheritance.
+ //
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ AddRef(
+ VOID
+ )
+ {
+ return __super::AddRef();
+ }
+
+ __drv_arg(this, __drv_freesMem(object))
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ Release(
+ VOID
+ )
+ {
+ return __super::Release();
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+};
+
diff --git a/gpio/samples/simdeviceumdf/exports.def b/gpio/samples/simdeviceumdf/exports.def
new file mode 100644
index 00000000..45a4fb2b
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/exports.def
@@ -0,0 +1,10 @@
+; Echo.def : Declares the module parameters.
+
+;
+; TODO: Change the library name here to match your binary name.
+;
+
+LIBRARY "SimdeviceUMDF.DLL"
+
+EXPORTS
+ DllGetClassObject PRIVATE
diff --git a/gpio/samples/simdeviceumdf/internal.h b/gpio/samples/simdeviceumdf/internal.h
new file mode 100644
index 00000000..4cc79b71
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/internal.h
@@ -0,0 +1,96 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Internal.h
+
+Abstract:
+
+ This module contains the local type definitions for the UMDF Echo
+ driver sample.
+
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+#ifndef _INTERNAL_H_
+#define _INTERNAL_H_
+
+#pragma once
+
+#define UMDF_USING_NTSTATUS
+
+#include <windows.h>
+#include <winternl.h>
+#include <ntstatus.h>
+#include <strsafe.h>
+#include <gpio.h>
+
+_Analysis_mode_(_Analysis_code_type_user_driver_); // Macro letting the compiler know this is not a kernel driver (this will help surpress needless warnings)
+
+// Common WPD, UMDF, and WDM headers
+#include <devioctl.h>
+#include <initguid.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+//
+// Include the WUDF DDI
+//
+#include "wudfddi.h"
+
+//
+// Use specstrings for in/out annotation of function parameters.
+//
+
+#include "specstrings.h"
+
+//
+// Forward definitions of classes in the other header files.
+//
+
+typedef class CSimdeviceDriver *PCSimdeviceDriver;
+typedef class CSimdevice *PCSimdevice;
+typedef class CSimdeviceQueue *PCSimdeviceQueue;
+
+//
+// Include the type specific headers.
+//
+
+#include "comsup.h"
+#include "driver.h"
+#include "device.h"
+#include "queue.h"
+
+__forceinline
+#ifdef _PREFAST_
+__declspec(noreturn)
+#endif
+VOID
+WdfTestNoReturn(
+ VOID
+ )
+{
+ // do nothing.
+}
+
+#define WUDF_TEST_DRIVER_ASSERT(p) \
+{ \
+ if ( !(p) ) \
+ { \
+ DebugBreak(); \
+ WdfTestNoReturn(); \
+ } \
+}
+
+#define MYDRIVER_CLASS_ID {0x7ab7dcf5, 0xd1d4, 0x4085, {0x95, 0x47, 0x1d, 0xb9, 0x68, 0xcc, 0xa7, 0x20}}
+
+
+#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }}
+#endif
diff --git a/gpio/samples/simdeviceumdf/queue.cpp b/gpio/samples/simdeviceumdf/queue.cpp
new file mode 100644
index 00000000..4b66a25f
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/queue.cpp
@@ -0,0 +1,529 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ queue.cpp
+
+Abstract:
+
+ This file implements the I/O queue interface and performs
+ the read/write/ioctl operations.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+
+#include "internal.h"
+
+//
+// IUnknown implementation
+//
+
+//
+// Queue destructor.
+// Free up the buffer, wait for thread to terminate and
+// delete critical section.
+//
+
+
+CSimdeviceQueue::~CSimdeviceQueue(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+ IUnknown implementation of Release
+
+Arguments:
+
+
+Return Value:
+
+ ULONG (reference count after Release)
+
+--*/
+{
+ if (m_Buffer) {
+ delete [] m_Buffer;
+ }
+
+ if (m_InitCritSec) {
+ ::DeleteCriticalSection(&m_Crit);
+ }
+}
+
+
+//
+// Initialize
+HRESULT
+CSimdeviceQueue::CreateInstance(
+ _In_ IWDFDevice *FxDevice,
+ _Out_ PCSimdeviceQueue *Queue
+ )
+/*++
+
+Routine Description:
+
+
+ CreateInstance creates an instance of the queue object.
+
+Arguments:
+
+ ppUkwn - OUT parameter is an IUnknown interface to the queue object
+
+Return Value:
+
+ HRESULT indicating success or failure
+
+--*/
+{
+ CSimdeviceQueue *pMyQueue = new CSimdeviceQueue;
+ HRESULT hr;
+
+ if (pMyQueue == NULL) {
+ return E_OUTOFMEMORY;
+ }
+
+ hr = pMyQueue->Initialize(FxDevice);
+
+ if (SUCCEEDED(hr))
+ {
+ *Queue = pMyQueue;
+ }
+ else
+ {
+ pMyQueue->Release();
+ }
+ return hr;
+}
+
+HRESULT
+CSimdeviceQueue::Initialize(
+ _In_ IWDFDevice *FxDevice
+ )
+{
+ IWDFIoQueue *fxQueue;
+ HRESULT hr;
+
+ //
+ // Initialize the critical section before we continue
+ //
+
+ if (!InitializeCriticalSectionAndSpinCount(&m_Crit,0x80000400)) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto Exit;
+ }
+ m_InitCritSec = TRUE;
+
+ //
+ // Create the framework queue
+ //
+
+ {
+ IUnknown *unknown = QueryIUnknown();
+ hr = FxDevice->CreateIoQueue(unknown,
+ TRUE,
+ WdfIoQueueDispatchSequential,
+ TRUE,
+ FALSE,
+ &fxQueue);
+ unknown->Release();
+ }
+
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+ m_FxQueue = fxQueue;
+
+ fxQueue->Release();
+
+Exit:
+ return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CSimdeviceQueue::QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ )
+/*++
+
+Routine Description:
+
+
+ Query Interface
+
+Arguments:
+
+ Follows COM specifications
+
+Return Value:
+
+ HRESULT indicating success or failure
+
+--*/
+{
+ HRESULT hr;
+
+
+ if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) {
+ *Object = QueryIQueueCallbackWrite();
+ hr = S_OK;
+ } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackRead))) {
+ *Object = QueryIQueueCallbackRead();
+ hr = S_OK;
+ } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDeviceIoControl))) {
+ *Object = QueryIQueueCallbackDeviceIoControl();
+ hr = S_OK;
+ } else {
+ hr = CUnknown::QueryInterface(InterfaceId, Object);
+ }
+
+ return hr;
+}
+
+VOID
+STDMETHODCALLTYPE
+CSimdeviceQueue::OnDeviceIoControl(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ ULONG ControlCode,
+ _In_ SIZE_T InputBufferSizeInBytes,
+ _In_ SIZE_T OutputBufferSizeInBytes
+ )
+/*++
+
+Routine Description:
+
+
+ DeviceIoControl dispatch routine
+
+Arguments:
+
+ pWdfQueue - Framework Queue instance
+ pWdfRequest - Framework Request instance
+ ControlCode - IO Control Code
+ InputBufferSizeInBytes - Length of input buffer
+ OutputBufferSizeInBytes - Length of output buffer
+
+ Always succeeds DeviceIoIoctl
+Return Value:
+
+ VOID
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(pWdfQueue);
+ UNREFERENCED_PARAMETER(ControlCode);
+ UNREFERENCED_PARAMETER(InputBufferSizeInBytes);
+ UNREFERENCED_PARAMETER(OutputBufferSizeInBytes);
+
+ pWdfRequest->Complete(S_OK);
+ return;
+}
+
+VOID
+STDMETHODCALLTYPE
+CSimdeviceQueue::OnWrite(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ SIZE_T BytesToWrite
+ )
+/*++
+
+Routine Description:
+
+
+ Write dispatch routine
+ IQueueCallbackWrite
+
+Arguments:
+
+ pWdfQueue - Framework Queue instance
+ pWdfRequest - Framework Request instance
+ BytesToWrite - Length of bytes in the write buffer
+
+ Allocate and copy data to local buffer
+Return Value:
+
+ VOID
+
+--*/
+{
+
+ HRESULT hr;
+ IWDFMemory* pRequestMemory = NULL;
+ IWDFIoRequest2 * pWdfRequest2 = NULL;
+
+ UNREFERENCED_PARAMETER(pWdfQueue);
+
+ //
+ // Handle Zero length writes.
+ //
+
+ if (!BytesToWrite) {
+ pWdfRequest->CompleteWithInformation(S_OK, 0);
+ return;
+ }
+
+ if( BytesToWrite > MAX_WRITE_LENGTH ) {
+
+ pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0);
+ return;
+ }
+
+ // Get memory object
+ hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2));
+
+ if (FAILED(hr)) {
+ pWdfRequest->Complete(hr);
+ return;
+ }
+
+ // Release previous buffer if set
+
+ if( m_Buffer != NULL ) {
+ delete [] m_Buffer;
+ m_Buffer = NULL;
+ m_Length = 0L;
+ }
+
+ // Allocate Buffer
+
+ m_Buffer = new UCHAR[BytesToWrite];
+ if (m_Buffer == NULL) {
+ pWdfRequest->Complete(E_OUTOFMEMORY);
+ m_Length = 0L;
+ return;
+ }
+
+ hr = pWdfRequest2->RetrieveInputMemory(&pRequestMemory);
+
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+ // Copy from memory object to our buffer
+
+ hr = pRequestMemory->CopyToBuffer(0, m_Buffer, BytesToWrite);
+
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+
+ //
+ // Save the information so that we can use it
+ // to complete the request later.
+ //
+
+ Lock();
+
+ m_Length = (ULONG) BytesToWrite;
+ m_XferredBytes = m_Length;
+ m_CurrentRequest = pWdfRequest2;
+ pWdfRequest2 = NULL;
+
+ Unlock();
+
+Exit:
+
+ if (FAILED(hr)) {
+ pWdfRequest2->CompleteWithInformation(hr, 0);
+ delete [] m_Buffer;
+ m_Buffer = NULL;
+ }
+
+ SAFE_RELEASE(pRequestMemory);
+ SAFE_RELEASE(pWdfRequest2);
+
+ return;
+}
+
+VOID
+STDMETHODCALLTYPE
+CSimdeviceQueue::OnRead(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ SIZE_T SizeInBytes
+ )
+/*++
+
+Routine Description:
+
+
+ Read dispatch routine
+ IQueueCallbackRead
+
+Arguments:
+
+ pWdfQueue - Framework Queue instance
+ pWdfRequest - Framework Request instance
+ SizeInBytes - Length of bytes in the read buffer
+
+ Copy available data into the read buffer
+Return Value:
+
+ VOID
+
+--*/
+{
+ IWDFMemory* pRequestMemory = NULL;
+ IWDFIoRequest2 * pWdfRequest2 = NULL;
+ HRESULT hr;
+
+ UNREFERENCED_PARAMETER(pWdfQueue);
+
+ //
+ // Handle Zero length reads.
+ //
+
+ if (!SizeInBytes) {
+ pWdfRequest->CompleteWithInformation(S_OK, 0);
+ return;
+ }
+
+ if (m_Buffer == NULL) {
+ pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), SizeInBytes);
+ return;
+ }
+
+ if (m_Length < SizeInBytes) {
+ SizeInBytes = m_Length;
+ }
+
+ //
+ // Get memory object
+ //
+
+ hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2));
+
+ if (FAILED(hr)) {
+ pWdfRequest->Complete(hr);
+ return;
+ }
+
+
+ hr = pWdfRequest2->RetrieveOutputMemory(&pRequestMemory );
+
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+ // Copy from buffer to memory object
+
+ hr = pRequestMemory->CopyFromBuffer(0, m_Buffer, SizeInBytes);
+
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+
+ //
+ // Save the information so that we can use it
+ // to complete the request later.
+ //
+
+ Lock();
+
+ m_CurrentRequest = pWdfRequest2;
+ m_XferredBytes = SizeInBytes;
+ pWdfRequest2 = NULL;
+
+ Unlock();
+
+Exit:
+
+ if (FAILED(hr)) {
+ pWdfRequest2->CompleteWithInformation(hr, 0);
+ }
+
+ SAFE_RELEASE(pRequestMemory);
+ SAFE_RELEASE(pWdfRequest2);
+ return;
+}
+
+DWORD
+CSimdeviceQueue::CompletionThread(
+ PVOID ThreadParameter
+ )
+/*++
+
+Routine Description:
+
+
+ This routine is called from the thread started to complete
+ I/O requests. It sleeps for TIMER_PERIOD and then completes
+ the current request. Note that it has to release the lock
+ before it calls the request complete method.
+
+Arguments:
+
+ ThreadParameter - This is a pointer to the Queue object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ CSimdeviceQueue *pQueue = (CSimdeviceQueue *)ThreadParameter;
+ IWDFIoRequest2 *request;
+ SIZE_T bytesXferred = 0;
+
+ for (;;) {
+
+ //
+ // Block for a fixed time and then complete the request.
+ //
+
+ Sleep(TIMER_PERIOD);
+
+ pQueue->Lock();
+
+ //
+ // Process the current request.
+ //
+
+ request = pQueue->m_CurrentRequest;
+
+ if (request) {
+ bytesXferred = pQueue->m_XferredBytes;
+ }
+
+ //
+ // Reset values.
+ //
+
+ pQueue->m_CurrentRequest = NULL;
+ pQueue->m_XferredBytes = 0;
+
+
+ pQueue->Unlock();
+
+ if (request) {
+ request->CompleteWithInformation(S_OK, bytesXferred);
+ SAFE_RELEASE(request);
+ }
+
+ //
+ // If thread needs to be terminated
+ //
+
+ if (pQueue->m_ExitThread) {
+ ExitThread(0);
+ }
+
+ }
+
+}
diff --git a/gpio/samples/simdeviceumdf/queue.h b/gpio/samples/simdeviceumdf/queue.h
new file mode 100644
index 00000000..108299a4
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/queue.h
@@ -0,0 +1,211 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file defines the queue callback interface.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+// Set max write length for testing
+#define MAX_WRITE_LENGTH (40*1024)
+
+// Set timer period in ms
+#define TIMER_PERIOD 100
+
+//
+// Queue Callback Object.
+//
+
+class CSimdeviceQueue :
+ public IQueueCallbackDeviceIoControl,
+ public IQueueCallbackRead,
+ public IQueueCallbackWrite,
+ public CUnknown
+{
+ PVOID m_Buffer; // Current buffer
+ ULONG m_Length; // Length of the buffer
+ SIZE_T m_XferredBytes; // Amount of bytes transferred for the current request
+ IWDFIoRequest2 *m_CurrentRequest; // Current request
+ CRITICAL_SECTION m_Crit; // Lock to protect updates to CSimdeviceQueue fields
+ BOOLEAN m_ExitThread; // If TRUE Terminate thread.
+ BOOLEAN m_InitCritSec; // If TRUE lock initialized
+
+ IWDFIoQueue *m_FxQueue;
+
+ CSimdeviceQueue() :
+ m_Buffer(NULL),
+ m_Length (0),
+ m_CurrentRequest(NULL),
+ m_XferredBytes(0),
+ m_ExitThread(FALSE),
+ m_InitCritSec(FALSE),
+ m_FxQueue(NULL)
+ {
+ }
+
+ virtual ~CSimdeviceQueue();
+
+ __inline
+ void
+ Lock(
+ )
+ {
+ ::EnterCriticalSection(&m_Crit);
+ }
+
+ __inline
+ void
+ Unlock(
+ )
+ {
+ ::LeaveCriticalSection(&m_Crit);
+ }
+
+ HRESULT
+ Initialize(
+ _In_ IWDFDevice *FxDevice
+ );
+
+public:
+
+ //
+ // Completion thread routine.
+ //
+
+ static DWORD CompletionThread( PVOID ThreadParameter);
+
+ //
+ // Sets the flag to make thread exit
+ //
+
+ void
+ SetExitThread()
+ {
+ m_ExitThread = TRUE;
+ }
+
+ static
+ HRESULT
+ CreateInstance(
+ _In_ IWDFDevice *FxDevice,
+ _Out_ PCSimdeviceQueue *Queue
+ );
+
+ HRESULT
+ Configure(
+ VOID
+ )
+ {
+ return S_OK;
+ }
+
+
+ IQueueCallbackDeviceIoControl *
+ QueryIQueueCallbackDeviceIoControl(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IQueueCallbackDeviceIoControl *>(this);
+ }
+
+ IQueueCallbackRead *
+ QueryIQueueCallbackRead(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IQueueCallbackRead *>(this);
+ }
+
+ IQueueCallbackWrite *
+ QueryIQueueCallbackWrite(
+ VOID
+ )
+ {
+ AddRef();
+ return static_cast<IQueueCallbackWrite *>(this);
+ }
+
+ //
+ // IUnknown
+ //
+
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ AddRef(
+ VOID
+ ) {
+ return CUnknown::AddRef();
+ }
+
+ __drv_arg(this, __drv_freesMem(object))
+ virtual
+ ULONG
+ STDMETHODCALLTYPE
+ Release(
+ VOID
+ ) {
+ return CUnknown::Release();
+ }
+
+ virtual
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID InterfaceId,
+ _Out_ PVOID *Object
+ );
+
+ //
+ // Wdf Callbacks
+ //
+
+ // IQueueCallbackDeviceIoControl
+ //
+ virtual
+ VOID
+ STDMETHODCALLTYPE
+ OnDeviceIoControl(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ ULONG ControlCode,
+ _In_ SIZE_T InputBufferSizeInBytes,
+ _In_ SIZE_T OutputBufferSizeInBytes
+ );
+
+ // IQueueCallbackWrite
+ //
+ virtual
+ VOID
+ STDMETHODCALLTYPE
+ OnWrite(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ SIZE_T NumOfBytesToWrite
+ );
+
+ // IQueueCallbackRead
+ //
+ virtual
+ VOID
+ STDMETHODCALLTYPE
+ OnRead(
+ _In_ IWDFIoQueue *pWdfQueue,
+ _In_ IWDFIoRequest *pWdfRequest,
+ _In_ SIZE_T NumOfBytesToRead
+ );
+};
diff --git a/gpio/samples/simdeviceumdf/simdeviceumdf.rc b/gpio/samples/simdeviceumdf/simdeviceumdf.rc
new file mode 100644
index 00000000..8465960f
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/simdeviceumdf.rc
@@ -0,0 +1,21 @@
+//---------------------------------------------------------------------------
+// SimdeviceUMDF.rc
+//
+// Copyright (c) Microsoft Corporation, All Rights Reserved
+//---------------------------------------------------------------------------
+
+
+#include <windows.h>
+#include <ntverp.h>
+
+//
+// TODO: Change the file description and file names to match your binary.
+//
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "WDF:UMDF Simdevice User-Mode Driver Sample"
+#define VER_INTERNALNAME_STR "SimdeviceUMDF"
+#define VER_ORIGINALFILENAME_STR "SimdeviceUMDF.dll"
+
+#include "common.ver"
diff --git a/gpio/samples/simdeviceumdf/simdeviceumdfdriver.ctl b/gpio/samples/simdeviceumdf/simdeviceumdfdriver.ctl
new file mode 100644
index 00000000..a0ce2089
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/simdeviceumdfdriver.ctl
@@ -0,0 +1 @@
+d93fb470-afb1-4af8-860e-75f726c66f6b WudfEchoDriverTraceGuid
diff --git a/gpio/samples/simdeviceumdf/simdeviceumdfdriver.inx b/gpio/samples/simdeviceumdf/simdeviceumdfdriver.inx
new file mode 100644
index 00000000..fa17b2bb
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/simdeviceumdfdriver.inx
@@ -0,0 +1,78 @@
+;
+; SimdeviceUMDFDriver.inf
+;
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Sample
+ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171}
+Provider=%MSFTWUDF%
+CatalogFile=GpioSamples.cat
+DriverVer=03/20/2003,5.00.3788
+
+[Manufacturer]
+%MSFTWUDF%=Microsoft,NT$ARCH$
+
+[Microsoft.NT$ARCH$]
+%SimdeviceUMDFName%=SimdeviceUMDF_Install,ACPI\TEST0004
+
+[ClassInstall32]
+AddReg=SampleClass_RegistryAdd
+
+[SampleClass_RegistryAdd]
+HKR,,,,%ClassName%
+HKR,,Icon,,"-10"
+
+[SourceDisksFiles]
+SimdeviceUMDF.dll=1
+
+[SourceDisksNames]
+1 = %MediaDescription%
+
+; =================== Simdevice Sample UMDF Driver ==================================
+
+[SimdeviceUMDF_Install.NT]
+CopyFiles=UMDriverCopy
+
+[SimdeviceUMDF_Install.NT.hw]
+
+[SimdeviceUMDF_Install.NT.Services]
+AddService=SimdeviceUMDF,0x000001fa,SimdeviceUMDF_ServiceInstall
+
+[SimdeviceUMDF_Install.NT.Wdf]
+UmdfService=SimdeviceUMDF,SimdeviceUMDF_Install
+UmdfServiceOrder=SimdeviceUMDF
+
+; this enables direct hardware access from UMDF driver
+UmdfDirectHardwareAccess=AllowDirectHardwareAccess
+
+; direct i/o devices cannot run in default pool.
+UmdfHostProcessSharing=ProcessSharingDisabled
+
+[SimdeviceUMDF_Install]
+UmdfLibraryVersion=$UMDFVERSION$
+DriverCLSID={7AB7DCF5-D1D4-4085-9547-1DB968CCA720}
+ServiceBinary=%12%\UMDF\SimdeviceUMDF.dll
+
+[SimdeviceUMDF_ServiceInstall]
+DisplayName = %SimdeviceUMDFDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\WUDFRd.sys
+
+[DestinationDirs]
+UMDriverCopy=12,UMDF ; copy to drivers\UMDF
+CoInstallers_CopyFiles=11
+
+[UMDriverCopy]
+SimdeviceUMDF.dll
+
+; =================== Generic ==================================
+
+[Strings]
+MSFTWUDF="Microsoft Internal (WUDF)"
+MediaDescription="Microsoft WUDF Sample Driver Installation Media"
+ClassName="Sample Device"
+SimdeviceUMDFDisplayName="Sample User-mode Driver Framework Reflector driver"
+SimdeviceUMDFName="Sample device UMDF Driver"