summaryrefslogtreecommitdiff
path: root/gpio/samples
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
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'gpio/samples')
-rw-r--r--gpio/samples/ReadMe.md28
-rw-r--r--gpio/samples/sim.sln72
-rw-r--r--gpio/samples/simdevice/GpioSample.asl124
-rw-r--r--gpio/samples/simdevice/common.h84
-rw-r--r--gpio/samples/simdevice/simdevice.c819
-rw-r--r--gpio/samples/simdevice/simdevice.inx76
-rw-r--r--gpio/samples/simdevice/simdevice.rc12
-rw-r--r--gpio/samples/simdevice/simdevice.vcxproj189
-rw-r--r--gpio/samples/simdevice/simdevice.vcxproj.Filters39
-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
-rw-r--r--gpio/samples/simgpio/simgpio.c2540
-rw-r--r--gpio/samples/simgpio/simgpio.inxbin0 -> 3616 bytes
-rw-r--r--gpio/samples/simgpio/simgpio.rc12
-rw-r--r--gpio/samples/simgpio/simgpio.vcxproj161
-rw-r--r--gpio/samples/simgpio/simgpio.vcxproj.Filters39
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.c2692
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.h176
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.inxbin0 -> 3688 bytes
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.rc12
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj200
-rw-r--r--gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters42
-rw-r--r--gpio/samples/simgpio_i2c/spb_i2c.c666
-rw-r--r--gpio/samples/simgpio_i2c/trace.h75
39 files changed, 12018 insertions, 0 deletions
diff --git a/gpio/samples/ReadMe.md b/gpio/samples/ReadMe.md
new file mode 100644
index 00000000..97464c5e
--- /dev/null
+++ b/gpio/samples/ReadMe.md
@@ -0,0 +1,28 @@
+GPIO Sample Drivers
+===================
+
+The GPIO samples contain annotated code to illustrate how to write a [GPIO controller driver](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439509) that works in conjunction with the [GPIO framework extension](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439512) (GpioClx) to handle GPIO I/O control requests, and a peripheral driver that runs in kernel mode and uses GPIO resources. For a sample that shows how to write a GPIO peripheral driver that runs in user mode, please refer to the SPB accelerometer sample driver (SPB\\peripherals\\accelerometer).
+
+The GPIO sample set contains the following three samples.
+
+<table>
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="left">Minifilter Sample
+Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left"><p><em>SimGpio</em></p>
+<p>The files in this sample contain the source code for a GPIO controller driver that communicates with GpioClx through the GpioClx device driver interface (DDI). The GPIO controller driver is written for a hypothetical memory-mapped GPIO controller (simgpio). The code is meant to be purely instructional. An ASL file illustrates how to specify a GPIO interrupt and I/O descriptor in the ACPI firmware.</p></td>
+<td align="left"><p><em>SimGpio_I2C</em></p>
+<p>The files in this sample contain the source code for a GPIO controller driver that communicates with GpioClx through the GpioClx DDI. In contrast to the SimGpio sample, the GPIO controller in this sample is not memory-mapped. The GPIO controller driver is written for a hypothetical GPIO controller that resides on an I<sup>2</sup>C bus (simgpio_i2c). The code is meant to be purely instructional. An ASL file illustrates how to specify a GPIO interrupt and I/O descriptor in the ACPI firmware.</p></td>
+</tr>
+</tbody>
+</table>
+
diff --git a/gpio/samples/sim.sln b/gpio/samples/sim.sln
new file mode 100644
index 00000000..edbafcc1
--- /dev/null
+++ b/gpio/samples/sim.sln
@@ -0,0 +1,72 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdevice", "Simdevice", "{B836C8C4-99F3-4B16-8B3D-558EFC65F9D3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simdeviceumdf", "Simdeviceumdf", "{5302F4A4-2BE9-43C9-BF4E-4ED0D4A131A6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio", "Simgpio", "{3544A23D-F159-4D5F-B41D-A045D7BB4220}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simgpio_i2c", "Simgpio_i2c", "{E0A658B7-1A02-4468-AB84-54444838B9BD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simdevice", "simdevice\simdevice.vcxproj", "{57BFED37-06F0-435D-A4CA-610B56B8987F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimdeviceUMDF", "simdeviceumdf\SimdeviceUMDF.vcxproj", "{D768CF1C-AE06-4C12-B11D-21C5D70082F7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio", "simgpio\simgpio.vcxproj", "{BCCD1049-70D2-4C07-BE8C-E9B609BD1714}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simgpio_i2c", "simgpio_i2c\simgpio_i2c.vcxproj", "{FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|Win32.Build.0 = Debug|Win32
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|Win32.ActiveCfg = Release|Win32
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|Win32.Build.0 = Release|Win32
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|x64.ActiveCfg = Debug|x64
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Debug|x64.Build.0 = Debug|x64
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|x64.ActiveCfg = Release|x64
+ {57BFED37-06F0-435D-A4CA-610B56B8987F}.Release|x64.Build.0 = Release|x64
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|Win32.Build.0 = Debug|Win32
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|Win32.ActiveCfg = Release|Win32
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|Win32.Build.0 = Release|Win32
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|x64.ActiveCfg = Debug|x64
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Debug|x64.Build.0 = Debug|x64
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|x64.ActiveCfg = Release|x64
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7}.Release|x64.Build.0 = Release|x64
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|Win32.Build.0 = Debug|Win32
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|Win32.ActiveCfg = Release|Win32
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|Win32.Build.0 = Release|Win32
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|x64.ActiveCfg = Debug|x64
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Debug|x64.Build.0 = Debug|x64
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|x64.ActiveCfg = Release|x64
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714}.Release|x64.Build.0 = Release|x64
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|Win32.Build.0 = Debug|Win32
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|Win32.ActiveCfg = Release|Win32
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|Win32.Build.0 = Release|Win32
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|x64.ActiveCfg = Debug|x64
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Debug|x64.Build.0 = Debug|x64
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|x64.ActiveCfg = Release|x64
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {57BFED37-06F0-435D-A4CA-610B56B8987F} = {B836C8C4-99F3-4B16-8B3D-558EFC65F9D3}
+ {D768CF1C-AE06-4C12-B11D-21C5D70082F7} = {5302F4A4-2BE9-43C9-BF4E-4ED0D4A131A6}
+ {BCCD1049-70D2-4C07-BE8C-E9B609BD1714} = {3544A23D-F159-4D5F-B41D-A045D7BB4220}
+ {FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2} = {E0A658B7-1A02-4468-AB84-54444838B9BD}
+ EndGlobalSection
+EndGlobal
diff --git a/gpio/samples/simdevice/GpioSample.asl b/gpio/samples/simdevice/GpioSample.asl
new file mode 100644
index 00000000..c393d9da
--- /dev/null
+++ b/gpio/samples/simdevice/GpioSample.asl
@@ -0,0 +1,124 @@
+
+/*++
+
+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, "TEST0003")
+ Name (_CID, "TEST0003")
+ Name (_UID, 1)
+
+ Method (_CRS, 0x0, NotSerialized) {
+ Name (RBUF, ResourceTemplate () {
+
+ //
+ // GPIO Interrupt Resources
+ //
+
+ GpioInt(Edge, ActiveHigh, Shared, PullUp, 0, "\\_SB.GPIO", 0, ResourceConsumer,, RawDataBuffer() {1}) {1}
+ // GpioInt(Edge, ActiveHigh, Shared, PullUp, 0, "\\_SB.GPIO", 0, ResourceConsumer,, RawDataBuffer() {1}) {2}
+
+ //
+ // GPIO IO Resources
+ //
+
+ GpioIo(Exclusive, PullUp, 0, 0,, "\\_SB.GPIO",0, ResourceConsumer, , RawDataBuffer() {1}) {10}
+ GpioIo(Exclusive, PullUp, 0, 0,, "\\_SB.GPIO",0, ResourceConsumer, , RawDataBuffer() {1}) {11}
+ })
+
+ Return (RBUF)
+ }
+
+ Method (_STA, 0x0, NotSerialized) {
+ Return(0xf)
+ }
+ }
+ }
+ }
+ }
diff --git a/gpio/samples/simdevice/common.h b/gpio/samples/simdevice/common.h
new file mode 100644
index 00000000..315044c8
--- /dev/null
+++ b/gpio/samples/simdevice/common.h
@@ -0,0 +1,84 @@
+/*++
+
+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:
+
+ common.h
+
+Abstract:
+
+ Header file that provide some utility functionalities to the sample device driver
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+#include <ntddk.h>
+#pragma warning(disable:4201) // disable nameless struct/union warnings
+#include <wdf.h>
+#pragma warning(default:4201)
+
+#define NTSTRSAFE_LIB
+#include <ntstrsafe.h>
+
+#ifndef MAX_USHORT
+#define MAX_USHORT ((USHORT)-1)
+#endif
+
+#ifndef MAX_ULONG
+#define MAX_ULONG ((ULONG)-1)
+#endif
+
+#ifndef MAX_ULONG64
+#define MAX_ULONG64 ((ULONG64)-1)
+#endif
+
+//
+// Useful macros for setting and checking flags.
+//
+
+#define SET_FLAGS(_x, _f) ((_x) |= (_f))
+#define CLEAR_FLAGS(_x, _f) ((_x) &= ~(_f))
+#define CLEAR_OTHER_FLAGS(_x, _f) ((_x) &= (_f))
+#define CHECK_FLAG(_x, _f) ((_x) & (_f))
+
+//
+// Macros for rounding up or down.
+//
+
+#define ROUND_DOWN(_x, _alignment) \
+ ((_alignment == 1) ? (_x) : (((_x) / (_alignment)) * (_alignment)))
+
+#define ROUND_UP(_x, _alignment) \
+ ROUND_DOWN((_x) + (_alignment) - 1, (_alignment))
+
+//
+// Macros for find minimum and maximum of two integers.
+//
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) < (b)) ? (b) : (a))
+
+//
+// Define macros to allow easy pointer arithmetic.
+//
+
+#define Add2Ptr(_Ptr, _Value) ((PVOID)((PUCHAR)(_Ptr) + (_Value)))
+#define PtrOffset(_Base, _Ptr) ((ULONG_PTR)(_Ptr) - (ULONG_PTR)(_Base))
+
+// 4127 -- Conditional Expression is Constant warning
+#define WHILE(constant) \
+__pragma(warning(disable: 4127)) while(constant) __pragma(warning(default: 4127))
+
+#define FIELD_OFFSET_AND_SIZE(t, f) \
+ (FIELD_OFFSET(t, f) + FIELD_SIZE(t, f)) \ No newline at end of file
diff --git a/gpio/samples/simdevice/simdevice.c b/gpio/samples/simdevice/simdevice.c
new file mode 100644
index 00000000..f54f1a84
--- /dev/null
+++ b/gpio/samples/simdevice/simdevice.c
@@ -0,0 +1,819 @@
+/*++
+
+Copyright (c) 1990-2010 Microsoft Corporation
+
+Module Name:
+
+ SimpleDevice.c
+
+Abstract:
+
+ This is a simple device driver that consumes GPIO pins for I/O and interrupt.
+
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include "common.h"
+#include <gpio.h>
+#define RESHUB_USE_HELPER_ROUTINES
+#include <reshub.h>
+
+//
+// -------------------------------------------------------------------- Defines
+//
+
+#define MAX_NUMBER_IO_RESOURCES 2
+
+//
+// -------------------------------------------------------------------- Types
+//
+
+typedef struct _SAMPLE_DRV_DEVICE_EXTENSION {
+ ULONG IoResourceCount;
+ ULONG InterruptCount;
+ LARGE_INTEGER ConnectionIds[MAX_NUMBER_IO_RESOURCES];
+} SAMPLE_DRV_DEVICE_EXTENSION, *PSAMPLE_DRV_DEVICE_EXTENSION;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SAMPLE_DRV_DEVICE_EXTENSION, SampleDrvGetDeviceExtension)
+
+//
+// ----------------------------------------------------------------- Prototypes
+//
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD SampleDrvEvtDeviceAdd;
+EVT_WDF_DEVICE_D0_ENTRY SampleDrvEvtDeviceD0Entry;
+EVT_WDF_DEVICE_PREPARE_HARDWARE SampleDrvEvtDevicePrepareHardware;
+EVT_WDF_INTERRUPT_DPC SampleDrvInterruptDpc;
+EVT_WDF_INTERRUPT_ISR SampleDrvInterruptIsr;
+EVT_WDF_INTERRUPT_ISR SampleDrvInterruptPassiveCallback;
+
+NTSTATUS
+TestReadWrite (
+ _In_ WDFDEVICE Device,
+ _In_ PCUNICODE_STRING RequestString,
+ _In_ BOOLEAN ReadOperation,
+ _Inout_ PUCHAR Data,
+ _In_ _In_range_(>, 0) ULONG Size,
+ _Out_ WDFIOTARGET *IoTargetOut
+ );
+
+//
+// -------------------------------------------------------------------- Pragmas
+//
+
+#pragma alloc_text(PAGE, SampleDrvEvtDeviceAdd)
+#pragma alloc_text(PAGE, SampleDrvEvtDevicePrepareHardware)
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+DriverEntry (
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the driver initialization entry point.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the I/O manager.
+
+ RegistryPath - Pointer to the driver specific registry key.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDFDRIVER Driver;
+ WDF_DRIVER_CONFIG DriverConfig;
+ NTSTATUS Status;
+
+ //
+ // Initialize the driver configuration structure.
+ //
+
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, SampleDrvEvtDeviceAdd);
+
+ //
+ // Create a framework driver object to represent our driver.
+ //
+
+ Status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &DriverConfig,
+ &Driver);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DriverEntryEnd;
+ }
+
+DriverEntryEnd:
+ return Status;
+}
+
+BOOLEAN
+SampleDrvInterruptIsr (
+ _In_ WDFINTERRUPT Interrupt,
+ _In_ ULONG MessageID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the interrupt service routine for the sample device
+
+ N.B. This driver assumes that the interrupt line is not shared with any
+ other device. Hence it always claims the interrupt.
+
+Arguments:
+
+ Interupt - Supplies a handle to interrupt object (WDFINTERRUPT) for this
+ device.
+
+ MessageID - Supplies the MSI message ID for MSI-based interrupts.
+
+Return Value:
+
+ Always TRUE.
+
+--*/
+
+{
+
+
+ UNREFERENCED_PARAMETER(Interrupt);
+ UNREFERENCED_PARAMETER(MessageID);
+
+ //
+ // 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. In case of spurious
+ // interrupts, the ISR returns FALSE. If additional work needs to be done
+ // at a lower IRQL, schedule a DPC.
+ //
+
+ return TRUE;
+}
+
+#if 0
+BOOLEAN
+SampleDrvInterruptPassiveCallback (
+ _In_ WDFINTERRUPT Interrupt,
+ _In_ ULONG MessageID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the passive interrupt callback routine for the sample device.
+ As its name suggests, this routine is always invoked at PASSIVE_LEVEL.
+ This is useful in scenarios where the device is located behind a slow serial
+ peripheral bus(SPB) and requires communication (possible only at PASSIVE_LEVEL)
+ over the bus in quiescing the interrupt source.
+
+ N.B. It is possible for passive interrupt callback and DIRQL ISRs to
+ coexist for the same device and/or IDT entry. Interrupt objects chained to a
+ given IDT entry are always ordered (at interrupt connect time) by the OS such
+ that the DIRQL ISR interrupt objects are located before the passive callback
+ ones. Consequently, during interrupt dispatching, the OS would walk the list
+ in that order until the first ISR/passive callback returns TRUE to claim the
+ interrupt.
+
+Arguments:
+
+ Interupt - Supplies a handle to interrupt object (WDFINTERRUPT) for this
+ device.
+
+ MessageID - Supplies the MSI message ID for MSI-based interrupts.
+
+Return Value:
+
+ Always TRUE.
+
+--*/
+
+{
+
+
+ UNREFERENCED_PARAMETER(Interrupt);
+ UNREFERENCED_PARAMETER(MessageID);
+
+ //
+ // The sample driver always returns TRUE (e.g. claiming the interrupt)
+ // from its passive callback. In reality, the driver needs to do whatever necessary to
+ // quiesce the interrupt before claiming the interrupt.
+ //
+
+ return TRUE;
+}
+#endif
+
+VOID
+SampleDrvInterruptDpc (
+ _In_ WDFINTERRUPT WdfInterrupt,
+ _In_ WDFOBJECT WdfDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the DPC callback for the ISR. This routine is unused.
+
+Arguments:
+
+ Interupt - Supplies a handle to interrupt object (WDFINTERRUPT) for this
+ device.
+
+ Device - Supplies a handle to the framework device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(WdfInterrupt);
+ UNREFERENCED_PARAMETER(WdfDevice);
+ return;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+SampleDrvEvtDeviceAdd (
+ WDFDRIVER Driver,
+ PWDFDEVICE_INIT DeviceInit
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the AddDevice entry point for the sample device driver.
+ It sets the ISR and DPC routine handlers for the interrupt and the passive
+ level callback for the passive interrupt
+
+ N.B. The sample device expects two interrupt resources in connecting its
+ DIRQL ISR and PASSIVE_LEVEL callback.
+
+Arguments:
+
+ Driver - Supplies a handle to the driver object created in DriverEntry.
+
+ DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT
+ structure.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDF_PNPPOWER_EVENT_CALLBACKS Callbacks;
+ WDFDEVICE Device;
+ WDF_OBJECT_ATTRIBUTES FdoAttributes;
+ WDF_INTERRUPT_CONFIG InterruptConfiguration;
+ NTSTATUS Status;
+ WDFINTERRUPT WdfInterrupt;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ //
+ // Set PnP callbacks for prepare/release hardware and D0 entry/exit. All
+ // callbacks not overriden here will be handled by the framework in the
+ // default manner.
+ //
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
+ Callbacks.EvtDevicePrepareHardware = SampleDrvEvtDevicePrepareHardware;
+ Callbacks.EvtDeviceD0Entry = SampleDrvEvtDeviceD0Entry;
+
+ //
+ // Register the PnP callbacks with the framework.
+ //
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &Callbacks);
+
+ //
+ // Initialize FDO attributes with the sample device extension.
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&FdoAttributes);
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&FdoAttributes, SAMPLE_DRV_DEVICE_EXTENSION);
+
+ //
+ // Call the framework to create the device and attach it to the lower stack.
+ //
+
+ Status = WdfDeviceCreate(&DeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status)) {
+ goto EvtDeviceAddEnd;
+ }
+
+ //
+ // Create an interrupt object for the DIRQL ISR
+ //
+
+ WDF_INTERRUPT_CONFIG_INIT(&InterruptConfiguration,
+ SampleDrvInterruptIsr,
+ SampleDrvInterruptDpc);
+
+ Status = WdfInterruptCreate(Device,
+ &InterruptConfiguration,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &WdfInterrupt);
+
+ if (!NT_SUCCESS(Status)) {
+
+ goto EvtDeviceAddEnd;
+ }
+
+#if 0
+ //
+ // Create an interrupt object for the passive interrupt callback. Note that
+ // the interrupt object is chained to the same interrupt line/IDT as the
+ // DIRQL one.
+ //
+
+ WDF_INTERRUPT_CONFIG_INIT(&InterruptConfiguration,
+ SampleDrvInterruptIsr,
+ NULL);
+
+ //
+ // Set passive handling to true
+ //
+
+ InterruptConfiguration.PassiveHandling = TRUE;
+
+ Status = WdfInterruptCreate(Device,
+ &InterruptConfiguration,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &WdfInterrupt);
+#endif
+
+EvtDeviceAddEnd:
+ return Status;
+}
+
+NTSTATUS
+SampleDrvEvtDevicePrepareHardware (
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourcesRaw,
+ _In_ WDFCMRESLIST ResourcesTranslated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the framework when the PnP manager sends an
+ IRP_MN_START_DEVICE request to the driver stack.
+
+Arguments:
+
+ Device - Supplies a handle to a framework device object.
+
+ ResourcesRaw - Supplies a handle to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ ResourcesTranslated - Supplies a handle 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:
+
+ NT status code.
+
+--*/
+
+{
+
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PSAMPLE_DRV_DEVICE_EXTENSION SampleDrvExtension;
+ ULONG Index;
+ ULONG ResourceCount;
+ NTSTATUS Status;
+ ULONG IoResourceIndex;
+
+ UNREFERENCED_PARAMETER(Device);
+ UNREFERENCED_PARAMETER(ResourcesRaw);
+
+ PAGED_CODE();
+
+ SampleDrvExtension = SampleDrvGetDeviceExtension(Device);
+ Status = STATUS_SUCCESS;
+ IoResourceIndex = 0;
+
+ SampleDrvExtension->InterruptCount = 0;
+
+ //
+ // Walk through the resource list and map all the resources. Only one
+ // memory resource and one interrupt is expected.
+ //
+
+ ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
+ for (Index = 0; Index < ResourceCount; Index += 1) {
+ Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
+ switch(Descriptor->Type) {
+
+ //
+ // This memory resource supplies the base of the device registers.
+ //
+
+ case CmResourceTypeConnection:
+
+ //
+ // Check against expected connection type
+ //
+
+ if ((Descriptor->u.Connection.Class ==
+ CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
+ (Descriptor->u.Connection.Type ==
+ CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {
+
+ SampleDrvExtension->ConnectionIds[IoResourceIndex].LowPart =
+ Descriptor->u.Connection.IdLowPart;
+ SampleDrvExtension->ConnectionIds[IoResourceIndex].HighPart =
+ Descriptor->u.Connection.IdHighPart;
+ IoResourceIndex++;
+ } else {
+
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ break;
+
+ //
+ // Interrupt resource
+ //
+
+ case CmResourceTypeInterrupt:
+ SampleDrvExtension->InterruptCount++;
+
+ default:
+ break;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto DevicePrepareHardwareEnd;
+ }
+ }
+
+ //
+ // Ensure that at least two interrupt resources are defined. One for DIRQL
+ // and another for the passive level ISR
+ //
+
+ NT_ASSERT(SampleDrvExtension->InterruptCount > 0);
+
+ if (SampleDrvExtension->InterruptCount < 1) {
+ Status = STATUS_UNSUCCESSFUL;
+ goto DevicePrepareHardwareEnd;
+ }
+
+ //
+ // Store the number of GPIO IO connection strings
+ //
+
+ SampleDrvExtension->IoResourceCount = IoResourceIndex;
+
+DevicePrepareHardwareEnd:
+ return Status;
+}
+
+NTSTATUS
+SampleDrvEvtDeviceD0Entry (
+ _In_ WDFDEVICE Device,
+ _In_ WDF_POWER_DEVICE_STATE PreviousPowerState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked by the framework to program the device to goto
+ D0, which is the working state. The framework invokes callback every
+ time the hardware needs to be (re-)initialized. This includes after
+ IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE,
+ and IRP_MN_SET_POWER-D0.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path. When a function is marked pagable and the
+ code section is paged out, it will generate a page fault which could
+ impact the fast resume behavior because the client driver will have
+ to wait until the system drivers can service this page fault.
+
+Arguments:
+
+ Device - Supplies a handle to the framework device object.
+
+ PreviousPowerState - WDF_POWER_DEVICE_STATE-typed enumerator that identifies
+ the device power state that the device was in before this transition
+ to D0.
+
+Return Value:
+
+ NTSTATUS code. A failure here will indicate a fatal error and cause the
+ framework to tear down the stack.
+
+--*/
+
+{
+
+ BYTE Data;
+ NTSTATUS Status;
+ WDFIOTARGET ReadTarget;
+ WDFIOTARGET WriteTarget;
+ PSAMPLE_DRV_DEVICE_EXTENSION SampleDrvExtension;
+ UNICODE_STRING ReadString;
+ WCHAR ReadStringBuffer[100];
+ UNICODE_STRING WriteString;
+ WCHAR WriteStringBuffer[100];
+
+ UNREFERENCED_PARAMETER(PreviousPowerState);
+
+ ReadTarget = NULL;
+ WriteTarget = NULL;
+
+ SampleDrvExtension = SampleDrvGetDeviceExtension(Device);
+
+ //
+ // For demonstration purporses, the sample device consumes two IO resources,
+ // the first of which will be used for input, and the second for output.
+ //
+
+ RtlInitEmptyUnicodeString(&ReadString,
+ ReadStringBuffer,
+ sizeof(ReadStringBuffer));
+
+ RtlInitEmptyUnicodeString(&WriteString,
+ WriteStringBuffer,
+ sizeof(WriteStringBuffer));
+
+
+ //
+ // Construct full-path string for GPIO read operation
+ //
+
+ Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&ReadString,
+ SampleDrvExtension->ConnectionIds[0].LowPart,
+ SampleDrvExtension->ConnectionIds[0].HighPart);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Cleanup;
+ }
+
+ //
+ // Construct full-path string for GPIO write operation
+ //
+
+ Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&WriteString,
+ SampleDrvExtension->ConnectionIds[1].LowPart,
+ SampleDrvExtension->ConnectionIds[1].HighPart);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Cleanup;
+ }
+
+ //
+ // Perform the read operation
+ //
+
+ Data = 0x0;
+ Status = TestReadWrite(Device, &ReadString, TRUE, &Data, sizeof(Data), &ReadTarget);
+ if (!NT_SUCCESS(Status)) {
+ goto Cleanup;
+ }
+
+ //
+ // Perform the write operation
+ //
+
+ Status = TestReadWrite(Device, &WriteString, FALSE, &Data, sizeof(Data), &WriteTarget);
+ if (!NT_SUCCESS(Status)) {
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if (ReadTarget != NULL) {
+ WdfIoTargetClose(ReadTarget);
+ WdfObjectDelete(ReadTarget);
+ }
+
+ if (WriteTarget != NULL) {
+ WdfIoTargetClose(WriteTarget);
+ WdfObjectDelete(WriteTarget);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+TestReadWrite (
+ _In_ WDFDEVICE Device,
+ _In_ PCUNICODE_STRING RequestString,
+ _In_ BOOLEAN ReadOperation,
+ _Inout_ PUCHAR Data,
+ _In_ _In_range_(>, 0) ULONG Size,
+ _Out_ WDFIOTARGET *IoTargetOut
+ )
+
+/*++
+
+Routine Description:
+
+ This is a utility routine to test read or write on a set of GPIO pins.
+
+Arguments:
+
+ Device - Supplies a handle 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
+ WDF.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ WDF_OBJECT_ATTRIBUTES Attributes;
+ WDFREQUEST IoctlRequest;
+ WDFIOTARGET IoTarget;
+ ULONG DesiredAccess;
+ WDFMEMORY WdfMemory;
+ WDF_OBJECT_ATTRIBUTES RequestAttributes;
+ WDF_REQUEST_SEND_OPTIONS SendOptions;
+ NTSTATUS Status;
+ WDF_OBJECT_ATTRIBUTES ObjectAttributes;
+ WDF_IO_TARGET_OPEN_PARAMS OpenParams;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&ObjectAttributes);
+ ObjectAttributes.ParentObject = Device;
+
+ IoctlRequest = NULL;
+ IoTarget = NULL;
+
+ if ((Data == NULL) || (Size == 0)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto TestReadWriteEnd;
+ }
+
+ Status = WdfIoTargetCreate(Device,
+ &ObjectAttributes,
+ &IoTarget);
+
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ //
+ // Specify desired file access
+ //
+
+ if (ReadOperation != FALSE) {
+ DesiredAccess = FILE_GENERIC_READ;
+
+ } else {
+ DesiredAccess = FILE_GENERIC_WRITE;
+ }
+
+ WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&OpenParams,
+ RequestString,
+ DesiredAccess);
+
+ //
+ // Open the IoTarget for I/O operation
+ //
+
+ Status = WdfIoTargetOpen(IoTarget, &OpenParams);
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&RequestAttributes);
+ Status = WdfRequestCreate(&RequestAttributes, IoTarget, &IoctlRequest);
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ //
+ // Set up a WDF memory object for the IOCTL request
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
+ Attributes.ParentObject = IoctlRequest;
+ Status = WdfMemoryCreatePreallocated(&Attributes, Data, Size, &WdfMemory);
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ //
+ // Format the request as read or write operation
+ //
+
+ if (ReadOperation != FALSE) {
+ Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
+ IoctlRequest,
+ IOCTL_GPIO_READ_PINS,
+ NULL,
+ 0,
+ WdfMemory,
+ 0);
+
+ } else {
+ Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
+ IoctlRequest,
+ IOCTL_GPIO_WRITE_PINS,
+ WdfMemory,
+ 0,
+ WdfMemory,
+ 0);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ //
+ // Send the request synchronously with an arbitrary timeout of 60 seconds
+ //
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
+
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions,
+ WDF_REL_TIMEOUT_IN_SEC(60));
+
+ Status = WdfRequestAllocateTimer(IoctlRequest);
+ if (!NT_SUCCESS(Status)) {
+ goto TestReadWriteEnd;
+ }
+
+ if (!WdfRequestSend(IoctlRequest, IoTarget, &SendOptions)) {
+ Status = WdfRequestGetStatus(IoctlRequest);
+ }
+
+ if (NT_SUCCESS(Status)) {
+ *IoTargetOut = IoTarget;
+ }
+
+TestReadWriteEnd:
+ if (IoctlRequest != NULL) {
+ WdfObjectDelete(IoctlRequest);
+ }
+
+ if (!NT_SUCCESS(Status) && (IoTarget != NULL)) {
+ WdfIoTargetClose(IoTarget);
+ WdfObjectDelete(IoTarget);
+ }
+
+ return Status;
+}
+
+
+
diff --git a/gpio/samples/simdevice/simdevice.inx b/gpio/samples/simdevice/simdevice.inx
new file mode 100644
index 00000000..34e65a68
--- /dev/null
+++ b/gpio/samples/simdevice/simdevice.inx
@@ -0,0 +1,76 @@
+;/*++
+;
+;Copyright (c) Microsoft Corporation. All rights reserved.
+;
+;Module Name:
+;
+; SIMGPIO.INF
+;
+;Abstract:
+; INF file for installing Simulated Peripheral Device Driver.
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=System
+ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
+Provider=%MSFT%
+DriverVer=05/07/2010
+CatalogFile=gpiosamples.cat
+
+[SourceDisksNames]
+3426=windows cd
+
+[SourceDisksFiles]
+Simdevice.sys = 3426
+
+;12 == Windows\System32\Drivers
+[DestinationDirs]
+DefaultDestDir = 12
+
+[ControlFlags]
+ExcludeFromSelect=*
+
+;*****************************************
+; SimDevice Install Section
+;*****************************************
+
+[Manufacturer]
+%MSFT%=Microsoft,NT$ARCH$
+
+[Microsoft.NT$ARCH$]
+%DeviceDesc%=DriverInstall,ACPI\TEST0003
+
+[DriverInstall.NT]
+CopyFiles=DriverInstall_Copy
+
+[DriverInstall.NT.Services]
+AddService = simdevice,2,DriverInstall_Service
+
+[DriverInstall_Copy]
+simdevice.sys,,,0x100
+
+[DriverInstall_Service]
+DisplayName = %SvcDesc%
+ServiceType = %SERVICE_KERNEL_DRIVER%
+StartType = %SERVICE_DEMAND_START%
+ErrorControl = %SERVICE_ERROR_NORMAL%
+ServiceBinary = %12%\Simdevice.sys
+
+[Strings]
+;Localizable Strings
+MSFT = "Microsoft"
+Std = "(Standard system devices) Test device"
+SvcDesc = "Test device service"
+DeviceDesc = "Test device description"
+
+;Non-Localizable Strings
+SERVICE_KERNEL_DRIVER = 1
+SERVICE_DEMAND_START = 3
+SERVICE_ERROR_NORMAL = 1
+
+
+
+
+
diff --git a/gpio/samples/simdevice/simdevice.rc b/gpio/samples/simdevice/simdevice.rc
new file mode 100644
index 00000000..3171260d
--- /dev/null
+++ b/gpio/samples/simdevice/simdevice.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Sample device driver"
+#define VER_INTERNALNAME_STR "simdevice.sys"
+#define VER_ORIGINALFILENAME_STR "simdevice.sys"
+
+#include "common.ver"
+
diff --git a/gpio/samples/simdevice/simdevice.vcxproj b/gpio/samples/simdevice/simdevice.vcxproj
new file mode 100644
index 00000000..6d685fcf
--- /dev/null
+++ b/gpio/samples/simdevice/simdevice.vcxproj
@@ -0,0 +1,189 @@
+<?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>{57BFED37-06F0-435D-A4CA-610B56B8987F}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{7E5C1E9A-1990-437C-B2AB-608C84382F8B}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>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">
+ <Inf Include=".\simdevice.inx">
+ <DateStamp>*</DateStamp>
+ <SpecifyDriverVerDirectiveDate>true</SpecifyDriverVerDirectiveDate>
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\simdevice.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>simdevice</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>simdevice</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>simdevice</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>simdevice</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="simdevice.c" />
+ <ResourceCompile Include="simdevice.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/simdevice/simdevice.vcxproj.Filters b/gpio/samples/simdevice/simdevice.vcxproj.Filters
new file mode 100644
index 00000000..2cc912e8
--- /dev/null
+++ b/gpio/samples/simdevice/simdevice.vcxproj.Filters
@@ -0,0 +1,39 @@
+<?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>{C0D3EEB7-2138-4947-92CF-E7B13BB61AA2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{70E36F5B-DD23-4371-98D3-59AB4042B0F1}</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>{DCCD5E1C-EB33-41FC-81B3-52934D7E2A5A}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{6B2886D3-87CA-46FD-B2A0-C624C0F69F92}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\simdevice.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\simdevice.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="simdevice.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="simdevice.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
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"
diff --git a/gpio/samples/simgpio/simgpio.c b/gpio/samples/simgpio/simgpio.c
new file mode 100644
index 00000000..4696e20d
--- /dev/null
+++ b/gpio/samples/simgpio/simgpio.c
@@ -0,0 +1,2540 @@
+
+/*++
+
+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:
+
+ simgpio.c
+
+Abstract:
+
+ This sample implements a GPIO client driver for simulated GPIO (SimGpio)
+ controller.
+
+ Note: DIRQL in the comments below refers to device IRQL, which is any
+ IRQL > DISPATCH_LEVEL (and less than some IRQL reserved for OS use).
+
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+//
+// The SimGpio controller has 4 GPIO banks, with banks consisting of
+// 32 pins each. Any pin can be configured for interrupt, input or output.
+// Each bank has the the following registers. The register set for different
+// banks are laid out adjacent to one another in the physical memory map.
+//
+// Register | Offset | Size
+// ------------------------------------------------
+// ModeRegister | 0x0 | 4 bytes
+// PolarityRegister | 0x4 | 8 bytes
+// EnableRegister | 0xC | 4 bytes
+// StatusRegister | 0x10 | 4 bytes
+// DirectionRegister | 0x14 | 4 bytes
+// LevelRegister | 0x18 | 4 bytes
+//
+// Mode Register - Interrupt mode (Level = 0x1 or Edge = 0x0) for pins
+// enabled for interrupts.
+//
+// Polarity Register - ActiveLow (0x0) or ActiveHigh (0x1) for Level-triggered
+// interrupts; Falling-edge (0x0), Rising-edge (0x1), or Both-Edges (0x3)
+// for Edge-triggered interrupts. Note there are two bits per pin.
+//
+// Enable Register - A mask of which pins are enabled for interrupt. A bit
+// is set if the pin is enabled for interrupt.
+//
+// Status Register - A register containing which pins are actively interrupting.
+// If any of the bit is set, then the GPIO controller's interrupt fires.
+//
+// Direction Register - A register which indicates whether a given pin is
+// configured for input (0x1) or output (0x0).
+//
+// LevelRegister - A bitmask which indicates holds the value for a given pin
+// (i.e. whether the pin is high (0x1) or low (0x0)).
+//
+
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <ntddk.h>
+#include <wdf.h>
+#include <gpioclx.h>
+
+//
+// -------------------------------------------------------------------- Defines
+//
+
+//
+// Define total number of pins on the simulated GPIO controller.
+//
+
+#define SIM_GPIO_TOTAL_PINS (4 * 32)
+#define SIM_GPIO_PINS_PER_BANK (32)
+#define SIM_GPIO_TOTAL_BANKS (4)
+
+//
+// Pool tag for SimGpio allocations.
+//
+
+#define SIM_GPIO_POOL_TAG 'GmiS'
+
+//
+// Define that controls whether f-state based power management will be supported
+// or not by the client driver.
+//
+
+#define ENABLE_F_STATE_POWER_MGMT
+
+//
+// Define F1 state residency (in sec), latency values (in sec) and nominal
+// power.
+//
+// This sample demonstrates F-state management effected as part of a critical
+// system transition (when the system enters connected-standby). To prevent a
+// GPIO bank from being transitioned into a low power state as part of runtime
+// idle power management (by mini-PEP), specify very high values for residency
+// and transition latency.
+//
+// If GPIO banks need to be runtime power managed, then specify more reasonable
+// values below.
+//
+
+#ifdef ENABLE_F_STATE_POWER_MGMT
+
+#define SIM_GPIO_F1_NOMINAL_POWER (0)
+#define SIM_GPIO_F1_RESIDENCY (8*60*60) // 8hrs
+#define SIM_GPIO_F1_TRANSITION (1*60*60) // 1hr
+
+#endif
+
+//
+// Macro for pointer arithmetic.
+//
+
+#define Add2Ptr(Ptr, Value) ((PVOID)((PUCHAR)(Ptr) + (Value)))
+
+//
+// Determine whether the given pin is reserved or not. Currently no pins are
+// reserved on the simulated GPIO controller.
+//
+
+__pragma(warning(disable: 4127)) // conditional expression is a constant
+
+//
+// ---------------------------------------------------------------------- Types
+//
+
+//
+// Define the registers within the SimGPIO controller. There are 32 pins per
+// controller. Note this is a logical device and thus may correspond to a
+// physical bank or module if the GPIO controller in hardware has more than
+// 32 pins.
+//
+
+
+
+typedef struct _SIM_GPIO_REGISTERS {
+ ULONG ModeRegister;
+ ULONG PolarityRegister[2];
+ ULONG EnableRegister;
+ ULONG StatusRegister;
+ ULONG DirectionRegister;
+ ULONG LevelRegister;
+} SIM_GPIO_REGISTERS, *PSIM_GPIO_REGISTERS;
+
+typedef struct _SIM_GPIO_BANK {
+ LARGE_INTEGER PhysicalBaseAddress;
+ PSIM_GPIO_REGISTERS Registers;
+ ULONG Length;
+ SIM_GPIO_REGISTERS SavedContext;
+} SIM_GPIO_BANK, *PSIM_GPIO_BANK;
+
+//
+// The SimGPIO client driver device extension.
+//
+
+typedef struct _SIM_GPIO_CONTEXT {
+ USHORT TotalPins;
+ LARGE_INTEGER PhysicalBaseAddress;
+ PSIM_GPIO_REGISTERS ControllerBase;
+ ULONG Length;
+ SIM_GPIO_BANK Banks[SIM_GPIO_TOTAL_BANKS];
+} SIM_GPIO_CONTEXT, *PSIM_GPIO_CONTEXT;
+
+SIM_GPIO_REGISTERS GlobalGpioRegisters[SIM_GPIO_TOTAL_BANKS] = {0};
+
+//
+// ----------------------------------------------------------------- Prototypes
+//
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_UNLOAD SimGpioEvtDriverUnload;
+EVT_WDF_DRIVER_DEVICE_ADD SimGpioEvtDeviceAdd;
+
+//
+// General interfaces.
+//
+
+GPIO_CLIENT_PREPARE_CONTROLLER SimGpioPrepareController;
+GPIO_CLIENT_RELEASE_CONTROLLER SimGpioReleaseController;
+GPIO_CLIENT_QUERY_CONTROLLER_BASIC_INFORMATION
+ SimGpioQueryControllerBasicInformation;
+
+GPIO_CLIENT_QUERY_SET_CONTROLLER_INFORMATION
+ SimGpioQuerySetControllerInformation;
+
+GPIO_CLIENT_START_CONTROLLER SimGpioStartController;
+GPIO_CLIENT_STOP_CONTROLLER SimGpioStopController;
+
+//
+// Interrupt enable, disable, mask and unmask handlers.
+//
+
+GPIO_CLIENT_ENABLE_INTERRUPT SimGpioEnableInterrupt;
+GPIO_CLIENT_DISABLE_INTERRUPT SimGpioDisableInterrupt;
+GPIO_CLIENT_MASK_INTERRUPTS SimGpioMaskInterrupts;
+GPIO_CLIENT_UNMASK_INTERRUPT SimGpioUnmaskInterrupt;
+GPIO_CLIENT_RECONFIGURE_INTERRUPT SimGpioReconfigureInterrupt;
+
+//
+// Handlers to query active/enabled interrupts and clear active interrupts.
+//
+
+GPIO_CLIENT_QUERY_ACTIVE_INTERRUPTS SimGpioQueryActiveInterrupts;
+GPIO_CLIENT_CLEAR_ACTIVE_INTERRUPTS SimGpioClearActiveInterrupts;
+GPIO_CLIENT_QUERY_ENABLED_INTERRUPTS SimGpioQueryEnabledInterrupts;
+
+//
+// Handlers for GPIO I/O operations.
+//
+
+GPIO_CLIENT_CONNECT_IO_PINS SimGpioConnectIoPins;
+GPIO_CLIENT_DISCONNECT_IO_PINS SimGpioDisconnectIoPins;
+GPIO_CLIENT_READ_PINS_MASK SimGpioReadGpioPins;
+GPIO_CLIENT_WRITE_PINS_MASK SimGpioWriteGpioPins;
+
+//
+// Handlers for save and restore hardware context callbacks.
+//
+
+GPIO_CLIENT_SAVE_BANK_HARDWARE_CONTEXT SimGpioSaveBankHardwareContext;
+GPIO_CLIENT_RESTORE_BANK_HARDWARE_CONTEXT SimGpioRestoreBankHardwareContext;
+
+//
+// -------------------------------------------------------------------- Pragmas
+//
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, SimGpioEvtDriverUnload)
+#pragma alloc_text(PAGE, SimGpioEvtDeviceAdd)
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+DriverEntry (
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the driver initialization entry point.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the I/O manager.
+
+ RegistryPath - Pointer to the driver specific registry key.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDFDRIVER Driver;
+ WDF_DRIVER_CONFIG DriverConfig;
+ GPIO_CLIENT_REGISTRATION_PACKET RegistrationPacket;
+ NTSTATUS Status;
+
+ //
+ // Initialize the driver configuration structure.
+ //
+
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, SimGpioEvtDeviceAdd);
+ DriverConfig.EvtDriverUnload = SimGpioEvtDriverUnload;
+
+ //
+ // Create a framework driver object to represent our driver.
+ //
+
+ Status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &DriverConfig,
+ &Driver);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DriverEntryEnd;
+ }
+
+ //
+ // Initialize the client driver registration packet.
+ //
+
+ RtlZeroMemory(&RegistrationPacket, sizeof(GPIO_CLIENT_REGISTRATION_PACKET));
+ RegistrationPacket.Version = GPIO_CLIENT_VERSION;
+ RegistrationPacket.Size = sizeof(GPIO_CLIENT_REGISTRATION_PACKET);
+
+ //
+ // Initialize the device context size.
+ //
+
+ RegistrationPacket.ControllerContextSize = sizeof(SIM_GPIO_CONTEXT);
+
+ //
+ // General interfaces.
+ //
+
+ RegistrationPacket.CLIENT_PrepareController = SimGpioPrepareController;
+ RegistrationPacket.CLIENT_QueryControllerBasicInformation =
+ SimGpioQueryControllerBasicInformation;
+
+ //
+ // The query/set handler is required in this sample only if F-state
+ // power management is enabled to indicate which banks support f-state
+ // based power maanagement.
+ //
+
+#ifdef ENABLE_F_STATE_POWER_MGMT
+
+ RegistrationPacket.CLIENT_QuerySetControllerInformation =
+ SimGpioQuerySetControllerInformation;
+
+#endif
+
+ RegistrationPacket.CLIENT_StartController = SimGpioStartController;
+ RegistrationPacket.CLIENT_StopController = SimGpioStopController;
+ RegistrationPacket.CLIENT_ReleaseController = SimGpioReleaseController;
+
+ //
+ // Interrupt enable and disable handlers.
+ //
+
+ RegistrationPacket.CLIENT_DisableInterrupt = SimGpioDisableInterrupt;
+ RegistrationPacket.CLIENT_EnableInterrupt = SimGpioEnableInterrupt;
+
+ //
+ // Interrupt mask, unmask and reconfigure interrupt handlers.
+ //
+
+ RegistrationPacket.CLIENT_MaskInterrupts = SimGpioMaskInterrupts;
+ RegistrationPacket.CLIENT_UnmaskInterrupt = SimGpioUnmaskInterrupt;
+ RegistrationPacket.CLIENT_ReconfigureInterrupt = SimGpioReconfigureInterrupt;
+
+ //
+ // Handlers to query active/enabled interrupts and clear active interrupts.
+ //
+
+ RegistrationPacket.CLIENT_ClearActiveInterrupts = SimGpioClearActiveInterrupts;
+ RegistrationPacket.CLIENT_QueryActiveInterrupts = SimGpioQueryActiveInterrupts;
+ RegistrationPacket.CLIENT_QueryEnabledInterrupts = SimGpioQueryEnabledInterrupts;
+
+ //
+ // Handlers for GPIO I/O operations.
+ //
+
+ RegistrationPacket.CLIENT_ConnectIoPins = SimGpioConnectIoPins;
+ RegistrationPacket.CLIENT_DisconnectIoPins = SimGpioDisconnectIoPins;
+ RegistrationPacket.CLIENT_ReadGpioPinsUsingMask = SimGpioReadGpioPins;
+ RegistrationPacket.CLIENT_WriteGpioPinsUsingMask = SimGpioWriteGpioPins;
+
+ //
+ // Handlers for GPIO save and restore context (if F-state power mgmt is
+ // supported).
+ //
+
+#ifdef ENABLE_F_STATE_POWER_MGMT
+
+ RegistrationPacket.CLIENT_SaveBankHardwareContext = SimGpioSaveBankHardwareContext;
+ RegistrationPacket.CLIENT_RestoreBankHardwareContext = SimGpioRestoreBankHardwareContext;
+
+#endif
+
+ //
+ // Register the SimGPIO client driver with the GPIO class extension.
+ //
+
+ Status = GPIO_CLX_RegisterClient(Driver, &RegistrationPacket, RegistryPath);
+
+DriverEntryEnd:
+ return Status;
+}
+
+VOID
+SimGpioEvtDriverUnload (
+ _In_ WDFDRIVER Driver
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by WDF to allow final cleanup prior to unloading the
+ SimGPIO client driver. This routine unregisters the client driver from the
+ class extension.
+
+Arguments:
+
+ Driver - Supplies a handle to a framework driver object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ Status = GPIO_CLX_UnregisterClient(Driver);
+ NT_ASSERT(NT_SUCCESS(Status));
+}
+
+NTSTATUS
+SimGpioEvtDeviceAdd (
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the AddDevice entry point for the client driver. This
+ routine is called by the framework in response to AddDevice call from the
+ PnP manager. It will create and initialize the device object to represent
+ a new instance of the simulated GPIO controller.
+
+Arguments:
+
+ Driver - Supplies a handle to the driver object created in DriverEntry.
+
+ DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT
+ structure.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDFDEVICE Device;
+ WDF_OBJECT_ATTRIBUTES FdoAttributes;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ //
+ // Call the GPIO class extension's pre-device create interface.
+ //
+
+ Status = GPIO_CLX_ProcessAddDevicePreDeviceCreate(Driver,
+ DeviceInit,
+ &FdoAttributes);
+ if (!NT_SUCCESS(Status)) {
+ goto EvtDeviceAddEnd;
+ }
+
+ //
+ // Call the framework to create the device and attach it to the lower stack.
+ //
+
+ Status = WdfDeviceCreate(&DeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status)) {
+ goto EvtDeviceAddEnd;
+ }
+
+ //
+ // Call the GPIO class extension's post-device create interface.
+ //
+
+ Status = GPIO_CLX_ProcessAddDevicePostDeviceCreate(Driver, Device);
+ if (!NT_SUCCESS(Status)) {
+ goto EvtDeviceAddEnd;
+ }
+
+EvtDeviceAddEnd:
+ return Status;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+VOID
+SimGpiopUnmapControllerBase (
+ _In_ PSIM_GPIO_CONTEXT GpioContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases the memory mapping for the GPIO controller's
+ registers, if one has been established.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power down path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ if ((GpioContext->ControllerBase != NULL) &&
+ (GpioContext->ControllerBase != GlobalGpioRegisters)) {
+ MmUnmapIoSpace(GpioContext->ControllerBase, GpioContext->Length);
+ GpioContext->ControllerBase = NULL;
+ }
+}
+
+//
+// ---------------------------------------------------------- General intefaces
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioPrepareController (
+ _In_ WDFDEVICE Device,
+ _In_ PVOID Context,
+ _In_ WDFCMRESLIST ResourcesRaw,
+ _In_ WDFCMRESLIST ResourcesTranslated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the GPIO class extension to prepare the
+ simulated GPIO controller for use.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ResourcesRaw - Supplies a handle to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ ResourcesTranslated - Supplies a handle 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:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ ULONG InterruptResourceCount;
+ ULONG MemoryResourceCount;
+ ULONG RequiredSize;
+ ULONG Offset;
+ ULONG ResourceCount;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Device);
+ UNREFERENCED_PARAMETER(ResourcesRaw);
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ RtlZeroMemory(GpioContext, sizeof(SIM_GPIO_CONTEXT));
+ GpioContext->TotalPins = SIM_GPIO_TOTAL_PINS;
+
+ //
+ // Walk through the resource list and map all the resources. Atleast one
+ // memory resource and one interrupt resource is expected. The resources
+ // are described in the ACPI namespace.
+ //
+
+ InterruptResourceCount = 0;
+ MemoryResourceCount = 0;
+ ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
+ Status = STATUS_SUCCESS;
+ for (Index = 0; Index < ResourceCount; Index += 1) {
+ Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
+ switch(Descriptor->Type) {
+
+ //
+ // The memory resource supplies the physical register base for the GPIO
+ // controller. Map it virtually as non-cached.
+ //
+
+ case CmResourceTypeMemory:
+ if (MemoryResourceCount == 0) {
+ RequiredSize = SIM_GPIO_TOTAL_BANKS * sizeof(SIM_GPIO_REGISTERS);
+
+ NT_ASSERT(Descriptor->u.Memory.Length >= RequiredSize);
+
+ if (Descriptor->u.Memory.Length < RequiredSize) {
+ Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ GpioContext->PhysicalBaseAddress = Descriptor->u.Memory.Start;
+ GpioContext->ControllerBase =
+ (PSIM_GPIO_REGISTERS)MmMapIoSpaceEx(
+ Descriptor->u.Memory.Start,
+ RequiredSize,
+ PAGE_NOCACHE | PAGE_READWRITE);
+
+ //
+ // Fail initialization if mapping of the memory region failed.
+ //
+
+ if (GpioContext->ControllerBase == NULL) {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ GpioContext->Length = RequiredSize;
+ }
+
+ MemoryResourceCount += 1;
+ break;
+
+ //
+ // IO port resources are unexpected, fail initialization.
+ //
+
+ case CmResourceTypePort:
+ Status = STATUS_UNSUCCESSFUL;
+ break;
+
+ //
+ // Interrupt resource which supplies the GPIO controller interrupt
+ // (that connects to the GIC).
+ //
+ // N.B. Connecting of the interrupt is handled by the GPIO class
+ // extension. Only ensure that appropriate number of interrupts
+ // were described.
+ //
+
+ case CmResourceTypeInterrupt:
+ InterruptResourceCount += 1;
+ break;
+
+ //
+ // This could be device-private type added by the underlying bus
+ // driver. Do not filter or alter this resource information.
+ //
+
+ default:
+ break;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto PrepareControllerEnd;
+ }
+ }
+
+ //
+ // NOTE: As SimGPIO is not a real hardware device, it doesn't really have
+ // any physical registers. For test purposes, fake the GPIO registers
+ // using a software defined global structure. This should NOT be done
+ // for a real GPIO controller
+ //
+ // BEGIN: SIMGPIO HACK.
+ //
+
+ if (MemoryResourceCount == 0) {
+ GpioContext->ControllerBase = GlobalGpioRegisters;
+ MemoryResourceCount = 1;
+ }
+
+ //
+ // END: SIMGPIO HACK.
+ //
+
+ //
+ // Fail initialization if minimum number of interrupt
+ // and memory resources were not described correctly.
+ //
+
+ if ((InterruptResourceCount < SIM_GPIO_TOTAL_BANKS) ||
+ (MemoryResourceCount < 1)) {
+ Status = STATUS_UNSUCCESSFUL;
+ goto PrepareControllerEnd;
+ }
+
+ //
+ // Initialize the base address of registers per bank.
+ //
+
+ for (BankId = 0; BankId < SIM_GPIO_TOTAL_BANKS; BankId += 1) {
+ GpioBank = &GpioContext->Banks[BankId];
+ Offset = BankId * sizeof(SIM_GPIO_REGISTERS);
+ GpioBank->Registers = Add2Ptr(GpioContext->ControllerBase, Offset);
+ GpioBank->Length = sizeof(SIM_GPIO_REGISTERS);
+ }
+
+PrepareControllerEnd:
+ if (!NT_SUCCESS(Status)) {
+ SimGpiopUnmapControllerBase(GpioContext);
+ }
+
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioReleaseController (
+ _In_ WDFDEVICE Device,
+ _In_ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the GPIO class extension to uninitialize the GPIO
+ controller.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power down path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Device);
+ UNREFERENCED_PARAMETER(Context);
+
+ //
+ // Release the mappings established in the initialize callback.
+ //
+ // N.B. Disconnecting of the interrupt is handled by the GPIO class
+ // extension.
+ //
+
+ SimGpiopUnmapControllerBase((PSIM_GPIO_CONTEXT)Context);
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioQueryControllerBasicInformation (
+ _In_ PVOID Context,
+ _Out_ PCLIENT_CONTROLLER_BASIC_INFORMATION ControllerInformation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the GPIO controller's attributes to the class extension.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ControllerInformation - Supplies a pointer to a buffer that receives
+ controller's information.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PSIM_GPIO_CONTEXT GpioContext;
+
+ ControllerInformation->Version = GPIO_CONTROLLER_BASIC_INFORMATION_VERSION;
+ ControllerInformation->Size = sizeof(CLIENT_CONTROLLER_BASIC_INFORMATION);
+
+ //
+ // Specify the number of pins on the SimGPIO controller.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ ControllerInformation->TotalPins = GpioContext->TotalPins;
+ ControllerInformation->NumberOfPinsPerBank = SIM_GPIO_PINS_PER_BANK;
+
+ //
+ // Indicate that the GPIO controller is memory-mapped and thus can be
+ // manipulated at DIRQL.
+ //
+ // N.B. If the GPIO controller is off-SOC behind some serial bus like
+ // I2C or SPI, then this field must be set to FALSE.
+ //
+
+ ControllerInformation->Flags.MemoryMappedController = TRUE;
+
+ //
+ // Indicate that status register must be cleared explicitly.
+ //
+
+ ControllerInformation->Flags.ActiveInterruptsAutoClearOnRead = 0;
+
+ //
+ // Indicate that the client driver would like to receive IO requests as a
+ // set of bitmasks as that maps directly to the register operations.
+ //
+
+ ControllerInformation->Flags.FormatIoRequestsAsMasks = 1;
+
+ //
+ // Indicate that the GPIO controller does not support controller-level
+ // D-state power management.
+ //
+
+ ControllerInformation->Flags.DeviceIdlePowerMgmtSupported = FALSE;
+
+ //
+ // Note if bank-level F-state power management is supported, then specify
+ // as such. Note the QuerySetControllerInformation() handler also needs to
+ // be implemented in this case.
+ //
+
+#ifdef ENABLE_F_STATE_POWER_MGMT
+
+ ControllerInformation->Flags.BankIdlePowerMgmtSupported = TRUE;
+
+#else
+
+ ControllerInformation->Flags.BankIdlePowerMgmtSupported = FALSE;
+
+#endif
+
+ //
+ // Note the IdleTimeout parameter does not need to be initialized if
+ // D-state power management is not supported.
+ //
+ // ControllerInformation->IdleTimeout = IdleTimeoutDefaultValue;
+ //
+
+ //
+ // Note if the GPIO controller does not support hardware debouncing and
+ // software-debouncing should be used instead, set the EmulateDebouncing
+ // flag.
+ //
+ // ControllerInformation->Flags.EmulateDebouncing = TRUE;
+ //
+
+ //
+ // Indicate that the client driver prefers GPIO class extension ActiveBoth
+ // emulation.
+ //
+
+ ControllerInformation->Flags.EmulateActiveBoth = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioQuerySetControllerInformation (
+ _In_ PVOID Context,
+ _In_ PCLIENT_CONTROLLER_QUERY_SET_INFORMATION_INPUT InputBuffer,
+ _Out_opt_ PCLIENT_CONTROLLER_QUERY_SET_INFORMATION_OUTPUT OutputBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the generic GPIO query/set handler. Currently it only
+ supports returning bank power information.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ InputBuffer - Supplies a pointer to a buffer that receives the parameters
+ for the query or set operation.
+
+ OutputBuffer - Supplies a pointer to the GPIO class extension allocated
+ buffer to return the output values. Note on entry, the
+ OutputBuffer->Size indicates how big the output buffer is. On exit, the
+ OutputBuffer->Size indicates the filled-in size or required size.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PPO_FX_COMPONENT_IDLE_STATE F1Parameters;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Context);
+
+ if((InputBuffer == NULL) || (OutputBuffer == NULL)) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto QuerySetControllerInformationEnd;
+ }
+
+ if (InputBuffer->RequestType != QueryBankPowerInformation) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto QuerySetControllerInformationEnd;
+ }
+
+ //
+ // Set the version and size of the output buffer.
+ //
+
+ OutputBuffer->Version = GPIO_BANK_POWER_INFORMATION_OUTPUT_VERSION;
+ OutputBuffer->Size = sizeof(CLIENT_CONTROLLER_QUERY_SET_INFORMATION_OUTPUT);
+
+ //
+ // Mark the given bank (InputBuffer->BankPowerInformation.BankId) as
+ // supporting F1 state. Since all banks support it, the BankId is not
+ // checked.
+ //
+
+ OutputBuffer->BankPowerInformation.F1StateSupported = TRUE;
+
+ //
+ // Supply the attributes for the F1 power state.
+ //
+
+ F1Parameters = &OutputBuffer->BankPowerInformation.F1IdleStateParameters;
+ F1Parameters->NominalPower = SIM_GPIO_F1_NOMINAL_POWER;
+ F1Parameters->ResidencyRequirement =
+ WDF_ABS_TIMEOUT_IN_SEC(SIM_GPIO_F1_RESIDENCY);
+
+ F1Parameters->TransitionLatency =
+ WDF_ABS_TIMEOUT_IN_SEC(SIM_GPIO_F1_TRANSITION);
+
+ Status = STATUS_SUCCESS;
+
+QuerySetControllerInformationEnd:
+ return Status;
+}
+
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioStartController (
+ _In_ PVOID Context,
+ _In_ BOOLEAN RestoreContext,
+ _In_ WDF_POWER_DEVICE_STATE PreviousPowerState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the simulated GPIO controller. This routine is
+ responsible for configuring all the pins to their default modes.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path. It is called at PASSIVE_IRQL though.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ RestoreContext - Supplies a flag that indicates whether the client driver
+ should restore the GPIO controller state to a previously saved state
+ or not.
+
+ PreviousPowerState - Supplies the device power state that the device was in
+ before this transition to D0.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ GPIO_SAVE_RESTORE_BANK_HARDWARE_CONTEXT_PARAMETERS RestoreParameters;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ UNREFERENCED_PARAMETER(PreviousPowerState);
+
+ //
+ // Perform all the steps necessary to start the device.
+ //
+
+ //
+ // If restore context is FALSE, then this is initial transition into D0
+ // power state for this controller. In such case, disable any interrupts
+ // that may have been left enabled (e.g. perhaps by FW, previous D0 -> Dx
+ // transition etc.) Otherwise, such interrupts could trigger an interrupt
+ // storm if they were to assert without any driver being registered to
+ // handle such interrupts.
+ //
+ // If restore context is TRUE, then this is a transition into D0 power
+ // state from a lower power Dx state. In such case, restore the context
+ // that was present before the controller transitioned into the lower
+ // power state.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ if (RestoreContext == FALSE) {
+ for (BankId = 0; BankId < SIM_GPIO_TOTAL_BANKS; BankId += 1) {
+ GpioBank = &GpioContext->Banks[BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Disable all interrupts on this bank by clearing the enable
+ // register.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ if (PinValue > 0) {
+ PinValue = 0;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister,
+ PinValue);
+ }
+ }
+
+ } else {
+
+ //
+ // Restoring the controller state involves restoring the state of
+ // each SimGPIO bank.
+ //
+
+ for (BankId = 0; BankId < SIM_GPIO_TOTAL_BANKS; BankId += 1) {
+ RestoreParameters.BankId = BankId;
+ RestoreParameters.State = PreviousPowerState;
+ SimGpioRestoreBankHardwareContext(Context, &RestoreParameters);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioStopController (
+ _In_ PVOID Context,
+ _In_ BOOLEAN SaveContext,
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the GPIO controller. This routine is responsible for
+ resetting all the pins to their default modes.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power down path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ SaveContext - Supplies a flag that indicates whether the client driver
+ should save the GPIO controller state or not. The state may need
+ to be restored when the controller is restarted.
+
+ TargetState - Supplies the device power state which the device will be put
+ in once the callback is complete.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+
+ BANK_ID BankId;
+ PSIM_GPIO_CONTEXT GpioContext;
+ GPIO_SAVE_RESTORE_BANK_HARDWARE_CONTEXT_PARAMETERS SaveParameters;
+
+ UNREFERENCED_PARAMETER(TargetState);
+
+ //
+ // Perform all the steps necessary to stop the device.
+ //
+
+ //
+ // If save context is FALSE, then this is a final transition into D3/off
+ // power state. Hence saving of context is not necessary.
+ //
+ // If save context is TRUE, then this is a transition into a lower power
+ // Dx state. In such case, save the context as it will need to be
+ // restored when the device is brought back to D0 (i.e. ON) power state.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ if (SaveContext == TRUE) {
+ for (BankId = 0; BankId < SIM_GPIO_TOTAL_BANKS; BankId += 1) {
+ SaveParameters.BankId = BankId;
+ SaveParameters.State = TargetState;
+ SimGpioSaveBankHardwareContext(Context, &SaveParameters);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//
+// --------------------------------------------------------- Interrupt Handlers
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioEnableInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_ENABLE_INTERRUPT_PARAMETERS EnableParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine configures the supplied pin for interrupt.
+
+ N.B. This routine is called from within a regular thread context (i.e.,
+ non-interrupt context) by the class extension. Thus the interrupt lock
+ needs to be explicitly acquired for memory-mapped GPIO controllers
+ prior to manipulating any device state that is also affected from a
+ routine called within the interrupt context.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ EnableParameters - Supplies a pointer to a structure containing enable
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be enabled. The pin
+ number is relative to the bank.
+
+ Flags - Supplies flags controlling the enable operation. Currently
+ no flags are defined.
+
+ InterruptMode - Supplies the trigger mode (edge or level) configured for
+ this interrupt when it was enabled.
+
+ Polarity - Supplies the polarity (active low or active high) configured
+ for this interrupt when it was enabled.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ VendorData - Supplies an optional pointer to a buffer containing the
+ vendor data supplied in the GPIO descriptor. This field will be
+ NULL if no vendor data was supplied. This buffer is read-only.
+
+ VendorDataLength - Supplies the length of the vendor data buffer.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ ULONG PinValue;
+ PIN_NUMBER ShiftBits;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+ NTSTATUS Status;
+
+ //
+ // If the polarity is not supported, then bail out. Note the interrupt
+ // polarity cannot be InterruptActiveBoth as this sample uses ActiveBoth
+ // emulation.
+ //
+
+ if ((EnableParameters->Polarity != InterruptActiveHigh) &&
+ (EnableParameters->Polarity != InterruptActiveLow)) {
+
+ Status = STATUS_NOT_SUPPORTED;
+ goto EnableInterruptEnd;
+ }
+
+ BankId = EnableParameters->BankId;
+ PinNumber = EnableParameters->PinNumber;
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+ SimGpioRegisters = GpioBank->Registers;
+ Status = STATUS_SUCCESS;
+
+ //
+ // The interrupt enable register/bitmap may be manipulated from within the
+ // interrupt context. Hence updates to it must be synchronized using the
+ // interrupt lock.
+ //
+
+ GPIO_CLX_AcquireInterruptLock(Context, BankId);
+
+ //
+ // Set the mode register. If the interrupt is Level then set the bit;
+ // otherwise, clear it (edge-triggered).
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->ModeRegister);
+ if (EnableParameters->InterruptMode == LevelSensitive) {
+ PinValue |= (1 << PinNumber);
+ } else {
+ PinValue &= ~(1 << PinNumber);
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->ModeRegister, PinValue);
+
+ //
+ // Set the polarity register. There are two bits for each pin. If the
+ // interrupt is ActiveHigh (or Rising-edge) then set it to 0x1.
+ //
+
+ Index = PinNumber / 16;
+ ShiftBits = (PinNumber % 16) * 2;
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[Index]);
+ switch (EnableParameters->Polarity) {
+
+ case InterruptActiveHigh:
+ PinValue &= ~(0x3 << ShiftBits);
+ PinValue |= (1 << ShiftBits);
+ break;
+
+ case InterruptActiveLow:
+ PinValue &= ~(0x3 << ShiftBits);
+ break;
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[Index], PinValue);
+
+ //
+ // NOTE: If the GPIO controller supports a separate set of mask registers,
+ // then any stale value must be cleared here. SimGPIO controller
+ // doesn't and hence this step is skipped here.
+ //
+
+ //
+ // Clear the corresponding status bit first to ignore any stale value.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->StatusRegister);
+ PinValue &= ~(1 << PinNumber);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->StatusRegister, PinValue);
+
+ //
+ // Enable the interrupt by setting the bit in the interrupt enable register.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ PinValue |= (1 << PinNumber);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister, PinValue);
+
+ //
+ // Release the interrupt lock.
+ //
+
+ GPIO_CLX_ReleaseInterruptLock(Context, BankId);
+
+ Status = STATUS_SUCCESS;
+
+EnableInterruptEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioDisableInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_DISABLE_INTERRUPT_PARAMETERS DisableParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine disables the supplied pin from interrupting.
+
+ This routine is not marked PAGED as it may be called before/after
+ the boot device is in D0/D3 if boot device has GPIO dependencies.
+
+ N.B. This routine is called from within a regular thread context (i.e.,
+ non-interrupt context) by the class extension. Thus the interrupt lock
+ needs to be explicitly acquired prior to manipulating the device state.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ DisableParameters - Supplies a pointer to a structure supplying the
+ parameters for disabling the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be disabled. The pin
+ number is relative to the bank.
+
+ Flags - Supplies flags controlling the disable operation. Currently
+ no flags are defined.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ BankId = DisableParameters->BankId;
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // The interrupt enable register may be manipulated from within the
+ // interrupt context. Hence updates to it must be synchronized using the
+ // interrupt lock.
+ //
+
+ GPIO_CLX_AcquireInterruptLock(Context, BankId);
+
+ //
+ // Disable the interrupt by clearing the bit in the interrupt enable
+ // register.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ PinValue &= ~(1 << DisableParameters->PinNumber);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister, PinValue);
+
+ GPIO_CLX_ReleaseInterruptLock(Context, BankId);
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioMaskInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_MASK_INTERRUPT_PARAMETERS MaskParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes masks the supplied pin from interrupting.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ MaskParameters - Supplies a pointer to a structure containing mask
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinMask - Supplies a bitmask of pins which should be masked. If a pin
+ should be masked, then the corresponding bit is set in the bitmask.
+
+ FailedMask - Supplies a bitmask of pins that failed to be masked. If
+ a pin could not be masked, the bit should be set in this field.
+
+ N.B. This should only be done if for non memory-mapped controllers.
+ Memory-mapped controllers are never expected to fail this
+ operation.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[MaskParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Mask is essentially same as disable for SimGPIO controller. The
+ // difference between the routines is that mask callback is called at DIRQL
+ // and automatically synchronized with other DIRQL interrupts callbacks.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ PinValue &= ~(ULONG)(MaskParameters->PinMask);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister, PinValue);
+
+ //
+ // Set the bitmask of pins that could not be successfully masked.
+ // Since this is a memory-mapped controller, the mask operation always
+ // succeeds.
+ //
+
+ MaskParameters->FailedMask = 0x0;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SimGpioUnmaskInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_ENABLE_INTERRUPT_PARAMETERS UnmaskParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes unmasks the supplied interrupt pin.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ UnmaskParameters - Supplies a pointer to a structure containing parameters
+ for unmasking the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be unmasked. The pin
+ number is relative to the bank.
+
+ InterruptMode - Supplies the trigger mode (edge or level) configured for
+ this interrupt when it was enabled.
+
+ Polarity - Supplies the polarity (active low or active high) configured
+ for this interrupt when it was enabled.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ VendorData - NULL.
+
+ VendorDataLength - 0.
+
+ N.B. The VendorData and VendorDataLength are not supplied for unmask
+ operation (i.e., both fields are zero).
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[UnmaskParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Unmask is same as enable on this GPIO controller. The difference between
+ // this routine and the enable routine is that unmask callback is called at
+ // DIRQL and automatically synchronized with other DIRQL-level callbacks.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ PinValue |= (1 << UnmaskParameters->PinNumber);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister, PinValue);
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioQueryActiveInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_QUERY_ACTIVE_INTERRUPTS_PARAMETERS QueryActiveParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current set of active interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ QueryActiveParameters - Supplies a pointer to a structure containing query
+ parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ EnabledMask - Supplies a bitmask of pins enabled for interrupts
+ on the specified GPIO bank.
+
+ ActiveMask - Supplies a bitmask that receives the active interrupt
+ mask. If a pin is interrupting and set in EnabledMask, then the
+ corresponding bit is set in the bitmask.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[QueryActiveParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // NOTE: As SimGPIO is not a real hardware device, no interrupt will ever
+ // fire. Thus the status register value will never change. To pretend
+ // as if a real interrupt happened, it marks all currently enabled
+ // interrupts as asserting. Copy the enable interrupt value into
+ // the status register.
+ //
+ // This should NOT be done for a real GPIO controller.
+ //
+
+ //
+ // BEGIN: SIMGPIO HACK.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->StatusRegister, PinValue);
+
+ //
+ // END: SIMGPIO HACK.
+ //
+
+ //
+ // Return the current value of the interrupt status register into the
+ // ActiveMask parameter.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->StatusRegister);
+ QueryActiveParameters->ActiveMask = (ULONG64)PinValue;
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioQueryEnabledInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_QUERY_ENABLED_INTERRUPTS_PARAMETERS QueryEnabledParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current set of enabled interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ QueryEnabledParameters - Supplies a pointer to a structure containing query
+ parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ EnabledMask - Supplies a bitmask that receives the enabled interrupt
+ mask. If a pin is enabled, then the corresponding bit is set in the
+ mask.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called with the
+ interrupt lock acquired by the class extension, but not always
+ from within the interrupt context.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[QueryEnabledParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Return the current value of the interrupt enable register into the
+ // EnabledMask parameter. It is strongly preferred that the true state of
+ // the hardware is returned, rather than a software-cached variable, since
+ // CLIENT_QueryEnabledInterrupts is used by the class extension to detect
+ // interrupt storms.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->EnableRegister);
+ QueryEnabledParameters->EnabledMask = (ULONG64)PinValue;
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioClearActiveInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_CLEAR_ACTIVE_INTERRUPTS_PARAMETERS ClearParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine clears the GPIO controller's active set of interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ClearParameters - Supplies a pointer to a structure containing clear
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ ClearActiveMask - Supplies a mask of pins which should be marked as
+ inactive. If a pin should be cleared, then the corresponding bit is
+ set in the mask.
+
+ FailedMask - Supplies a bitmask of pins that failed to be cleared. If
+ a pin could not be cleared, the bit should be set in this field.
+
+ N.B. This should only be done if for non memory-mapped controllers.
+ Memory-mapped controllers are never expected to fail this
+ operation.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ClearParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Clear the bits that are set in the ClearActiveMask parameter.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->StatusRegister);
+ PinValue &= ~((ULONG)ClearParameters->ClearActiveMask);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->StatusRegister, PinValue);
+
+ //
+ // Set the bitmask of pins that could not be successfully cleared.
+ // Since this is a memory-mapped controller, the clear operation always
+ // succeeds.
+ //
+
+ ClearParameters->FailedClearMask = 0x0;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SimGpioReconfigureInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_RECONFIGURE_INTERRUPTS_PARAMETERS ReconfigureParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reconfigures the interrupt in the specified mode.
+
+ N.B. This routine is called with the interrupt lock acquired by the
+ class extension. Hence the lock is not re-acquired here.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ReconfigureParameters - Supplies a pointer to a structure containing
+ parameters for reconfiguring the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be reconfigured.
+ The pin number is relative to the bank.
+
+ InterruptMode - Supplies the trigger mode (edge or level) for the new
+ configuration.
+
+ Polarity - Supplies the polarity (active low or active high) for the
+ new configuration.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ ULONG PinValue;
+ PIN_NUMBER ShiftBits;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+ NTSTATUS Status;
+
+ BankId = ReconfigureParameters->BankId;
+ PinNumber = ReconfigureParameters->PinNumber;
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+ SimGpioRegisters = GpioBank->Registers;
+ Status = STATUS_SUCCESS;
+
+ //
+ // Clear any stale status bits from the previous configuration.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->StatusRegister);
+ PinValue &= ~(1 << PinNumber);
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->StatusRegister, PinValue);
+
+ //
+ // Set the mode register. If the interrupt is Level then set the bit;
+ // otherwise, clear it (edge-triggered).
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->ModeRegister);
+ if (ReconfigureParameters->InterruptMode == LevelSensitive) {
+ PinValue |= (1 << PinNumber);
+ } else {
+ PinValue &= ~(1 << PinNumber);
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->ModeRegister, PinValue);
+
+ //
+ // Set the polarity register. There are two bits for each pin. If the
+ // interrupt is ActiveHigh (or Rising-edge) then set it to 0x1.
+ //
+
+ Index = PinNumber / 16;
+ ShiftBits = (PinNumber % 16) * 2;
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[Index]);
+ switch (ReconfigureParameters->Polarity) {
+
+ case InterruptActiveHigh:
+ PinValue &= ~(0x3 << ShiftBits);
+ PinValue |= (1 << ShiftBits);
+ break;
+
+ case InterruptActiveLow:
+ PinValue &= ~(0x3 << ShiftBits);
+ break;
+
+ default:
+
+ NT_ASSERT(FALSE);
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[Index], PinValue);
+ return STATUS_SUCCESS;
+}
+
+//
+// --------------------------------------------------------------- I/O Handlers
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioConnectIoPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_CONNECT_IO_PINS_PARAMETERS ConnectParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes connects the specified pins for IO. The pins can
+ be read from if connected for input, or written to if connected for
+ output.
+
+ N.B. This routine is called at PASSIVE_LEVEL but is not marked as
+ PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ConnectParameters - Supplies a pointer to a structure supplying the
+ parameters for connecting the IO pins. Fields description:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumberTable - Supplies an array of pins to be connected for IO. The
+ pin numbers are 0-based and relative to the GPIO bank.
+
+ PinCount - Supplies the number of pins in the pin number table.
+
+ ConnectMode - Supplies the mode in which the pins should be configured
+ (viz. input or output).
+
+ ConnectFlags - Supplies the flags controlling the IO setup. Currently
+ no flags are defined.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ DriveStrength - Supplies the drive strength to be applied. The value
+ is in 100th of mA (i.e., 1.21mA will be supplied as 121mA).
+
+ VendorData - Supplies an optional pointer to a buffer containing the
+ vendor data supplied in the GPIO descriptor. This field will be
+ NULL if no vendor data was supplied. This buffer is read-only.
+
+ VendorDataLength - Supplies the length of the vendor data buffer.
+
+ ConnectFlags - Supplies the flag to be used for connect operation.
+ Currently no flags are defined.
+
+Return Value:
+
+ NT status code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ PPIN_NUMBER PinNumberTable;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ConnectParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+ Status = STATUS_SUCCESS;
+
+ //
+ // Read the current direction register value.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->DirectionRegister);
+
+ //
+ // Walk through all the supplied pins and connect them in the specified
+ // mode (input or output).
+ //
+
+ PinNumberTable = ConnectParameters->PinNumberTable;
+ for (Index = 0; Index < ConnectParameters->PinCount; Index += 1) {
+ PinNumber = PinNumberTable[Index];
+
+ //
+ // If the pins are being connected for input, then set the bit.
+ // Otherwise clear the bit.
+ //
+
+ if (ConnectParameters->ConnectMode == ConnectModeInput) {
+ PinValue |= (1 << PinNumber);
+
+ } else if (ConnectParameters->ConnectMode == ConnectModeOutput) {
+ PinValue &= ~(1 << PinNumber);
+ }
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->DirectionRegister, PinValue);
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioDisconnectIoPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_DISCONNECT_IO_PINS_PARAMETERS DisconnectParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes disconnects the specified IO pins. The pins are
+ put back in their original mode.
+
+ N.B. This routine is called at PASSIVE_LEVEL but is not marked as
+ PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ DisconnectParameters - Supplies a pointer to a structure containing
+ disconnect operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumberTable - Supplies an array of pins to be disconnected. The pin
+ numbers are relative to the GPIO bank.
+
+ PinCount - Supplies the number of pins in the pin number table.
+
+ DisconnectMode - Supplies the mode in which the pins are currently
+ configured (viz. input or output).
+
+ DisconnectFlags - Supplies the flags controlling the IO setup. Currently
+ no flags are defined.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ PPIN_NUMBER PinNumberTable;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ //
+ // If the pin configuration should be preserved post disconnect, then
+ // there is nothing left to do.
+ //
+
+ if (DisconnectParameters->DisconnectFlags.PreserveConfiguration == 1) {
+ return STATUS_SUCCESS;
+ }
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[DisconnectParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Read the current direction register value.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->DirectionRegister);
+
+ //
+ // Walk through all the supplied pins and disconnect them. On SimGPIO
+ // controller, all pins are reset to the default mode (output).
+ //
+
+ PinNumberTable = DisconnectParameters->PinNumberTable;
+ for (Index = 0; Index < DisconnectParameters->PinCount; Index += 1) {
+ PinNumber = PinNumberTable[Index];
+ PinValue &= ~(1 << PinNumber);
+ }
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->DirectionRegister, PinValue);
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+NTSTATUS
+SimGpioReadGpioPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_READ_PINS_MASK_PARAMETERS ReadParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the current values for all the pins.
+
+ As the FormatIoRequestsAsMasks bit was set inside
+ SimGpioQueryControllerInformation(), all this routine needs to do is read
+ the level register value and return to the GPIO class extension. It will
+ return the right set of bits to the caller.
+
+ N.B. This routine is called at DIRQL for memory-mapped GPIOs and thus not
+ marked as PAGED.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ReadParameters - Supplies a pointer to a structure containing read
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinValues - Supplies a pointer to a variable that receives the current
+ pin values.
+
+ Flags - Supplies the flag to be used for read operation. Currently
+ defined flags are:
+
+ WriteConfiguredPins: If set, the read is being done on a set of
+ pin that were configured for write. In such cases, the
+ GPIO client driver is expected to read and return the
+ output register value.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped;
+ PASSIVE_LEVEL if the controller is behind some serial-bus.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable)
+ and IO callbacks (connect/disconnect).
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ReadParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Read the current level register value. Note the GPIO class may invoke
+ // the read routine on write-configured pins. In such case the output
+ // register values should be read.
+ //
+ // N.B. In case of SimGPIO, the LevelRegister holds the value for input
+ // as well as output pins. Thus the same register is read in either
+ // case.
+ //
+
+ if (ReadParameters->Flags.WriteConfiguredPins == FALSE) {
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->LevelRegister);
+
+ } else {
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->LevelRegister);
+ }
+
+ *ReadParameters->PinValues = PinValue;
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+NTSTATUS
+SimGpioWriteGpioPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_WRITE_PINS_MASK_PARAMETERS WriteParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the current values for the specified pins. This call is
+ synchronized with the write and connect/disconnect IO calls.
+
+ N.B. This routine is called at DIRQL for memory-mapped GPIOs and thus not
+ marked as PAGED.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ WriteParameters - Supplies a pointer to a structure containing write
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ SetMask - Supplies a mask of pins which should be set (0x1). If a pin
+ should be set, then the corresponding bit is set in the mask.
+ All bits that are clear in the mask should be left intact.
+
+ ClearMask - Supplies a mask of pins which should be cleared (0x0). If
+ a pin should be cleared, then the bit is set in the bitmask. All
+ bits that are clear in the mask should be left intact.
+
+ Flags - Supplies the flag controlling the write operation. Currently
+ no flags are defined.
+
+Return Value:
+
+ NTSTATUS code (STATUS_SUCCESS always for memory-mapped GPIO controllers).
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped;
+ PASSIVE_LEVEL if the controller is behind some serial-bus.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable)
+ and IO callbacks (connect/disconnect).
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[WriteParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Read the current level register value.
+ //
+
+ PinValue = READ_REGISTER_ULONG(&SimGpioRegisters->LevelRegister);
+
+ //
+ // Set the bits specified in the set mask and clear the ones specified
+ // in the clear mask.
+ //
+
+ PinValue |= WriteParameters->SetMask;
+ PinValue &= ~WriteParameters->ClearMask;
+
+ //
+ // Write the updated value to the register.
+ //
+
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->LevelRegister, PinValue);
+
+ return STATUS_SUCCESS;
+}
+
+//
+// ------------------------------------------------------- Power mgmt handlers
+//
+
+VOID
+SimGpioSaveBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ PGPIO_SAVE_RESTORE_BANK_HARDWARE_CONTEXT_PARAMETERS SaveParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the hardware context for the GPIO controller.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ SaveRestoreParameters - Supplies a pointer to a structure containing
+ parameters for the save operation:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ State - Target F-state the bank will be transitioned into.
+
+ Flags - Supplies flags for the save operation:
+ CriticalTransition - TRUE if this is due to a critical transition.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PULONG DestinationAddress;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ ULONG RegisterCount;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+ PULONG SourceAddress;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[SaveParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Copy the contents of the registers into memory.
+ //
+
+ SourceAddress = &SimGpioRegisters->ModeRegister;
+ DestinationAddress = &GpioBank->SavedContext.ModeRegister;
+ RegisterCount = sizeof(SIM_GPIO_REGISTERS) / sizeof(ULONG);
+ for (Index = 0; Index < RegisterCount; Index += 1) {
+ *DestinationAddress = READ_REGISTER_ULONG(SourceAddress);
+ SourceAddress += 1;
+ DestinationAddress += 1;
+ }
+
+ return;
+}
+
+VOID
+SimGpioRestoreBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ PGPIO_SAVE_RESTORE_BANK_HARDWARE_CONTEXT_PARAMETERS RestoreParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the hardware context for the GPIO controller.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ SaveRestoreParameters - Supplies a pointer to a structure containing
+ parameters for the restore operation:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ State - Target F-state the bank will be transitioned into.
+
+ Flags - Supplies flags for the save operation:
+ CriticalTransition - TRUE if this is due to a critical transition.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG PinValue;
+ PSIM_GPIO_REGISTERS SimGpioRegisters;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[RestoreParameters->BankId];
+ SimGpioRegisters = GpioBank->Registers;
+
+ //
+ // Restore the level register.
+ //
+
+ PinValue = GpioBank->SavedContext.LevelRegister;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->LevelRegister, PinValue);
+
+ //
+ // Restore the mode, polarity and enable registers.
+ //
+
+ PinValue = GpioBank->SavedContext.ModeRegister;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->ModeRegister, PinValue);
+
+ PinValue = GpioBank->SavedContext.PolarityRegister[0];
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[0], PinValue);
+
+ PinValue = GpioBank->SavedContext.PolarityRegister[1];
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->PolarityRegister[1], PinValue);
+
+ PinValue = GpioBank->SavedContext.StatusRegister;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->StatusRegister, PinValue);
+
+ //
+ // Restore the direction register.
+ //
+
+ PinValue = GpioBank->SavedContext.DirectionRegister;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->DirectionRegister, PinValue);
+
+ //
+ // Take care to restore the enable register only after restoring the
+ // mode and polarity registers. Otherwise, the interrupt line will get
+ // sampled when the enable register gets written to with the mode and
+ // polarity at that point in time (and could cause a spurious interrupt).
+ //
+
+ PinValue = GpioBank->SavedContext.EnableRegister;
+ WRITE_REGISTER_ULONG(&SimGpioRegisters->EnableRegister, PinValue);
+
+ return;
+}
+
+__pragma(warning(default: 4127)) // conditional expression is a constant
+
+
diff --git a/gpio/samples/simgpio/simgpio.inx b/gpio/samples/simgpio/simgpio.inx
new file mode 100644
index 00000000..0a00ec79
--- /dev/null
+++ b/gpio/samples/simgpio/simgpio.inx
Binary files differ
diff --git a/gpio/samples/simgpio/simgpio.rc b/gpio/samples/simgpio/simgpio.rc
new file mode 100644
index 00000000..1573b89c
--- /dev/null
+++ b/gpio/samples/simgpio/simgpio.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Simulated GPIO Client"
+#define VER_INTERNALNAME_STR "simgpio.sys"
+#define VER_ORIGINALFILENAME_STR "simgpio.sys"
+
+#include "common.ver"
+
diff --git a/gpio/samples/simgpio/simgpio.vcxproj b/gpio/samples/simgpio/simgpio.vcxproj
new file mode 100644
index 00000000..f9e47196
--- /dev/null
+++ b/gpio/samples/simgpio/simgpio.vcxproj
@@ -0,0 +1,161 @@
+<?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>{BCCD1049-70D2-4C07-BE8C-E9B609BD1714}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{1C686E11-FC59-4029-AFA6-6083113CBA26}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>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">
+ <Inf Include=".\simgpio.inx">
+ <DateStamp>*</DateStamp>
+ <SpecifyDriverVerDirectiveDate>true</SpecifyDriverVerDirectiveDate>
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\simgpio.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>simgpio</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>simgpio</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>simgpio</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>simgpio</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="simgpio.c" />
+ <ResourceCompile Include="simgpio.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/simgpio/simgpio.vcxproj.Filters b/gpio/samples/simgpio/simgpio.vcxproj.Filters
new file mode 100644
index 00000000..21ab66e9
--- /dev/null
+++ b/gpio/samples/simgpio/simgpio.vcxproj.Filters
@@ -0,0 +1,39 @@
+<?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>{BFF3D918-3BBB-4AF1-B1A2-C2A4FD8E82E8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{3BC12FA6-2491-4DA4-86C0-8F10AA4DB124}</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>{004102F6-6CB6-4E30-A1D8-B663D4B8CE08}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{38B34A48-263B-481A-81DE-81BF490980CD}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\simgpio.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\simgpio.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="simgpio.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="simgpio.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.c b/gpio/samples/simgpio_i2c/simgpio_i2c.c
new file mode 100644
index 00000000..9cdaee69
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.c
@@ -0,0 +1,2692 @@
+
+/*++
+
+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:
+
+ simgpio_i2c.c
+
+Abstract:
+
+ This sample implements a GPIO client driver for simulated GPIO (SimGpio)
+ controller.
+
+ Note: DIRQL in the comments below refers to device IRQL, which is any
+ IRQL > DISPATCH_LEVEL (and less than some IRQL reserved for OS use).
+
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+//
+// The SimGpio_I2C controller has 2 GPIO banks, with banks consisting of
+// 8 pins each. Any pin can be configured for interrupt, input or output.
+// Each bank has the the following registers. There are two sets of registers:
+// the first set for pins 0...7 and second for pins 8...15.
+//
+// Register | Address | Offset | Size
+// ----------------------------------------------------------------
+//
+// (Register set for pins 0...7)
+//
+// ModeRegister1 | 0x0 | 0x0 | 1 byte
+// PolarityRegister1 | 0x1 | 0x1 | 1 byte
+// EnableRegister1 | 0x2 | 0x2 | 1 byte
+// StatusRegister1 | 0x3 | 0x3 | 1 byte
+// DirectionRegister1 | 0x4 | 0x4 | 1 byte
+// LevelRegister1 | 0x5 | 0x5 | 1 byte
+//
+// (Register set for pins 8...15)
+//
+// ModeRegister2 | 0x6 | 0x6 | 1 byte
+// PolarityRegister2 | 0x7 | 0x7 | 1 byte
+// EnableRegister2 | 0x8 | 0x8 | 1 byte
+// StatusRegister2 | 0x9 | 0x9 | 1 byte
+// DirectionRegister2 | 0xA | 0xA | 1 byte
+// LevelRegister2 | 0xB | 0xB | 1 byte
+//
+// Mode Register - Interrupt mode (Level = 0x1 or Edge = 0x0) for pins
+// enabled for interrupts.
+//
+// Polarity Register - ActiveLow (0x0) or ActiveHigh (0x1) for Level-triggered
+// interrupts; Falling-edge (0x0), Rising-edge (0x1). Note this controller
+// does not support ActiveBoth.
+//
+// Enable Register - A mask of which pins are enabled for interrupt. A bit
+// is set if the pin is enabled for interrupt.
+//
+// Status Register - A register containing which pins are actively interrupting.
+// If any of the bit is set, then the GPIO controller's interrupt fires.
+//
+// Direction Register - A register which indicates whether a given pin is
+// configured for input (0x1) or output (0x0).
+//
+// LevelRegister - A bitmask which indicates holds the value for a given pin
+// (i.e. whether the pin is high (0x1) or low (0x0)).
+//
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <ntddk.h>
+#include <wdf.h>
+#include <gpioclx.h>
+#include "simgpio_i2c.h"
+#include "trace.h"
+#include "simgpio_i2c.tmh"
+
+//
+// -------------------------------------------------------------------- Defines
+//
+
+//
+// Determine whether the given pin is reserved or not. Currently no pins are
+// reserved on the simulated GPIO controller.
+//
+
+__pragma(warning(disable: 4127)) // conditional expression is a constant
+
+//
+// ----------------------------------------------------------------- Prototypes
+//
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD SimGpioEvtDeviceAdd;
+EVT_WDF_DRIVER_UNLOAD SimGpioEvtDriverUnload;
+
+//
+// General interfaces.
+//
+
+GPIO_CLIENT_PREPARE_CONTROLLER SimGpioPrepareController;
+GPIO_CLIENT_RELEASE_CONTROLLER SimGpioReleaseController;
+GPIO_CLIENT_QUERY_CONTROLLER_BASIC_INFORMATION
+ SimGpioQueryControllerBasicInformation;
+
+GPIO_CLIENT_START_CONTROLLER SimGpioStartController;
+GPIO_CLIENT_STOP_CONTROLLER SimGpioStopController;
+
+//
+// Interrupt enable, disable, mask and unmask handlers.
+//
+
+GPIO_CLIENT_ENABLE_INTERRUPT SimGpioEnableInterrupt;
+GPIO_CLIENT_DISABLE_INTERRUPT SimGpioDisableInterrupt;
+GPIO_CLIENT_MASK_INTERRUPTS SimGpioMaskInterrupts;
+GPIO_CLIENT_UNMASK_INTERRUPT SimGpioUnmaskInterrupt;
+GPIO_CLIENT_RECONFIGURE_INTERRUPT SimGpioReconfigureInterrupt;
+
+//
+// Handlers to query active/enabled interrupts and clear active interrupts.
+//
+
+GPIO_CLIENT_QUERY_ACTIVE_INTERRUPTS SimGpioQueryActiveInterrupts;
+GPIO_CLIENT_CLEAR_ACTIVE_INTERRUPTS SimGpioClearActiveInterrupts;
+GPIO_CLIENT_QUERY_ENABLED_INTERRUPTS SimGpioQueryEnabledInterrupts;
+
+//
+// Handlers for GPIO I/O operations.
+//
+
+GPIO_CLIENT_CONNECT_IO_PINS SimGpioConnectIoPins;
+GPIO_CLIENT_DISCONNECT_IO_PINS SimGpioDisconnectIoPins;
+GPIO_CLIENT_READ_PINS_MASK SimGpioReadGpioPins;
+GPIO_CLIENT_WRITE_PINS_MASK SimGpioWriteGpioPins;
+
+//
+// -------------------------------------------------------------------- Pragmas
+//
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, SimGpioEvtDeviceAdd)
+#pragma alloc_text(PAGE, SimGpioEvtDriverUnload)
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+DriverEntry (
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the driver initialization entry point.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the I/O manager.
+
+ RegistryPath - Pointer to the driver specific registry key.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDFDRIVER Driver;
+ WDF_DRIVER_CONFIG DriverConfig;
+ GPIO_CLIENT_REGISTRATION_PACKET RegistrationPacket;
+ NTSTATUS Status;
+
+ WPP_INIT_TRACING(DriverObject, RegistryPath);
+
+ //
+ // Initialize the driver configuration structure.
+ //
+
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, SimGpioEvtDeviceAdd);
+ DriverConfig.EvtDriverUnload = SimGpioEvtDriverUnload;
+
+ //
+ // Create a framework driver object to represent our driver.
+ //
+
+ Status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &DriverConfig,
+ &Driver);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: WdfDriverCreate failed status:%#x\n",
+ __FUNCTION__,
+ Status);
+
+ WPP_CLEANUP(DriverObject);
+ goto DriverEntryEnd;
+ }
+
+ //
+ // Initialize the client driver registration packet.
+ //
+
+ RtlZeroMemory(&RegistrationPacket, sizeof(GPIO_CLIENT_REGISTRATION_PACKET));
+ RegistrationPacket.Version = GPIO_CLIENT_VERSION;
+ RegistrationPacket.Size = sizeof(GPIO_CLIENT_REGISTRATION_PACKET);
+
+ //
+ // Initialize the device context size.
+ //
+
+ RegistrationPacket.ControllerContextSize = sizeof(SIM_GPIO_CONTEXT);
+
+ //
+ // General interfaces.
+ //
+
+ RegistrationPacket.CLIENT_PrepareController = SimGpioPrepareController;
+ RegistrationPacket.CLIENT_QueryControllerBasicInformation =
+ SimGpioQueryControllerBasicInformation;
+
+ RegistrationPacket.CLIENT_StartController = SimGpioStartController;
+ RegistrationPacket.CLIENT_StopController = SimGpioStopController;
+ RegistrationPacket.CLIENT_ReleaseController = SimGpioReleaseController;
+
+ //
+ // Interrupt enable and disable handlers.
+ //
+
+ RegistrationPacket.CLIENT_DisableInterrupt = SimGpioDisableInterrupt;
+ RegistrationPacket.CLIENT_EnableInterrupt = SimGpioEnableInterrupt;
+
+ //
+ // Interrupt mask, unmask and reconfigure interrupt handlers.
+ //
+
+ RegistrationPacket.CLIENT_MaskInterrupts = SimGpioMaskInterrupts;
+ RegistrationPacket.CLIENT_UnmaskInterrupt = SimGpioUnmaskInterrupt;
+ RegistrationPacket.CLIENT_ReconfigureInterrupt = SimGpioReconfigureInterrupt;
+
+ //
+ // Handlers to query active/enabled interrupts and clear active interrupts.
+ //
+
+ RegistrationPacket.CLIENT_ClearActiveInterrupts = SimGpioClearActiveInterrupts;
+ RegistrationPacket.CLIENT_QueryActiveInterrupts = SimGpioQueryActiveInterrupts;
+ RegistrationPacket.CLIENT_QueryEnabledInterrupts = SimGpioQueryEnabledInterrupts;
+
+ //
+ // Handlers for GPIO I/O operations.
+ //
+
+ RegistrationPacket.CLIENT_ConnectIoPins = SimGpioConnectIoPins;
+ RegistrationPacket.CLIENT_DisconnectIoPins = SimGpioDisconnectIoPins;
+ RegistrationPacket.CLIENT_ReadGpioPinsUsingMask = SimGpioReadGpioPins;
+ RegistrationPacket.CLIENT_WriteGpioPinsUsingMask = SimGpioWriteGpioPins;
+
+ //
+ // Register the SimGPIO client driver with the GPIO class extension.
+ //
+
+ Status = GPIO_CLX_RegisterClient(Driver, &RegistrationPacket, RegistryPath);
+
+DriverEntryEnd:
+ return Status;
+}
+
+NTSTATUS
+SimGpioEvtDeviceAdd (
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the AddDevice entry point for the client driver. This
+ routine is called by the framework in response to AddDevice call from the
+ PnP manager. It will create and initialize the device object to represent
+ a new instance of the simulated GPIO controller.
+
+Arguments:
+
+ Driver - Supplies a handle to the driver object created in DriverEntry.
+
+ DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT
+ structure.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDFDEVICE Device;
+ WDF_OBJECT_ATTRIBUTES FdoAttributes;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ //
+ // Call the GPIO class extension's pre-device create interface.
+ //
+
+ Status = GPIO_CLX_ProcessAddDevicePreDeviceCreate(Driver,
+ DeviceInit,
+ &FdoAttributes);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: GPIO_CLX_ProcessAddDevicePreDeviceCreate() failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EvtDeviceAddEnd;
+ }
+
+ //
+ // Call the framework to create the device and attach it to the lower stack.
+ //
+
+ Status = WdfDeviceCreate(&DeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: WdfDeviceCreate() failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EvtDeviceAddEnd;
+ }
+
+ //
+ // Call the GPIO class extension's post-device create interface.
+ //
+
+ Status = GPIO_CLX_ProcessAddDevicePostDeviceCreate(Driver, Device);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: GPIO_CLX_ProcessAddDevicePostDeviceCreate() failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EvtDeviceAddEnd;
+ }
+
+EvtDeviceAddEnd:
+ return Status;
+}
+
+//
+// ---------------------------------------------------------- General intefaces
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioPrepareController (
+ _In_ WDFDEVICE Device,
+ _In_ PVOID Context,
+ _In_ WDFCMRESLIST ResourcesRaw,
+ _In_ WDFCMRESLIST ResourcesTranslated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the GPIO class extension to prepare the
+ simulated GPIO controller for use.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ResourcesRaw - Supplies a handle to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ ResourcesTranslated - Supplies a handle 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:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ UCHAR ConnectionClass;
+ UCHAR ConnectionType;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ BOOLEAN I2ResourceFound;
+ ULONG InterruptResourceCount;
+ ULONG ResourceCount;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Device);
+ UNREFERENCED_PARAMETER(ResourcesRaw);
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ RtlZeroMemory(GpioContext, sizeof(SIM_GPIO_CONTEXT));
+ GpioContext->TotalPins = SIM_GPIO_TOTAL_PINS;
+
+ //
+ // Walk through the resource list and map all the resources. Atleast one
+ // memory resource and one interrupt resource is expected. The resources
+ // are described in the ACPI namespace.
+ //
+
+ I2ResourceFound = FALSE;
+ InterruptResourceCount = 0;
+ ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
+ Status = STATUS_SUCCESS;
+ for (Index = 0; Index < ResourceCount; Index += 1) {
+ Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
+ switch(Descriptor->Type) {
+
+ //
+ // Look for a connection resource that supplies the connection ID
+ // required to open a handle to the I2C controller.
+ //
+
+ case CmResourceTypeConnection:
+ ConnectionClass = Descriptor->u.Connection.Class;
+ ConnectionType = Descriptor->u.Connection.Type;
+ if ((ConnectionClass == CM_RESOURCE_CONNECTION_CLASS_SERIAL) &&
+ (ConnectionType == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) &&
+ (I2ResourceFound == FALSE)) {
+
+ GpioContext->SpbConnectionId.LowPart =
+ Descriptor->u.Connection.IdLowPart;
+
+ GpioContext->SpbConnectionId.HighPart =
+ Descriptor->u.Connection.IdHighPart;
+
+ I2ResourceFound = TRUE;
+ }
+
+ break;
+
+ //
+ // Interrupt resource which supplies the GPIO controller interrupt
+ // (that connects to the GIC).
+ //
+ // N.B. Connecting of the interrupt is handled by the GPIO class
+ // extension. Only ensure that appropriate number of interrupts
+ // were described.
+ //
+
+ case CmResourceTypeInterrupt:
+ InterruptResourceCount += 1;
+ break;
+
+ //
+ // This could be device-private type added by the underlying bus
+ // driver. Do not filter or alter this resource information.
+ //
+
+ default:
+ break;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto PrepareControllerEnd;
+ }
+ }
+
+ //
+ // Fail initialization if minimum number of interrupt and connection
+ // resources were not described correctly.
+ //
+
+ if ((InterruptResourceCount != 1) || (I2ResourceFound == FALSE)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: Resource do not match expected values! "
+ "Interrupt = %d, I2C = %d\n",
+ __FUNCTION__,
+ InterruptResourceCount,
+ I2ResourceFound);
+
+ Status = STATUS_UNSUCCESSFUL;
+ goto PrepareControllerEnd;
+ }
+
+ GpioContext->TotalPins = SIM_GPIO_TOTAL_PINS;
+ GpioContext->TotalBanks = SIM_GPIO_TOTAL_BANKS;
+ GpioContext->Device = Device;
+ for (Index = 0; Index < GpioContext->TotalBanks; Index += 1) {
+ GpioContext->Banks[Index].GpioContext = GpioContext;
+ GpioContext->Banks[Index].AddressBase =
+ (USHORT)(Index * MaximumSimGpioAddress);
+ }
+
+ //
+ // For SimGpio_i2c, the connection to the I2C controller needs to be
+ // established.
+ //
+
+ Status = SimGpioSetupSpbConnection(GpioContext);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSetupSpbConnection() failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto PrepareControllerEnd;
+ }
+
+PrepareControllerEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioReleaseController (
+ _In_ WDFDEVICE Device,
+ _In_ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the GPIO class extension to uninitialize the GPIO
+ controller.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power down path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Device);
+
+ //
+ // Release the mappings established in the initialize callback.
+ //
+ // N.B. Disconnecting of the interrupt is handled by the GPIO class
+ // extension.
+ //
+
+ SimGpioDestroySpbConnection(Context);
+
+ //
+ // Stop WPP Tracing.
+ //
+ // TODO: DO THIS in the cleanup callback!
+ //
+
+ WPP_CLEANUP(NULL);
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioQueryControllerBasicInformation (
+ _In_ PVOID Context,
+ _Out_ PCLIENT_CONTROLLER_BASIC_INFORMATION ControllerInformation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the GPIO controller's attributes to the class extension.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ControllerInformation - Supplies a pointer to a buffer that receives
+ controller's information.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PSIM_GPIO_CONTEXT GpioContext;
+
+ ControllerInformation->Version = GPIO_CONTROLLER_BASIC_INFORMATION_VERSION;
+ ControllerInformation->Size = sizeof(CLIENT_CONTROLLER_BASIC_INFORMATION);
+
+ //
+ // Specify the number of pins on the SimGPIO controller.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ ControllerInformation->TotalPins = GpioContext->TotalPins;
+ ControllerInformation->NumberOfPinsPerBank = SIM_GPIO_PINS_PER_BANK;
+
+ //
+ // Indicate that the GPIO controller is off-SoC (i.e. behind some I2C bus)
+ // and thus can only be serviced at PASSIVE_LEVEL IRQL.
+ //
+
+ ControllerInformation->Flags.MemoryMappedController = FALSE;
+
+ //
+ // Indicate that status register must be cleared explicitly.
+ //
+
+ ControllerInformation->Flags.ActiveInterruptsAutoClearOnRead = FALSE;
+
+ //
+ // Indicate that the client driver would like to receive IO requests as a
+ // set of bitmasks as that maps directly to the register operations.
+ //
+
+ ControllerInformation->Flags.FormatIoRequestsAsMasks = TRUE;
+
+ //
+ // Indicate that the GPIO controller does not support controller-level
+ // D-state power management or F-state power management.
+ //
+ // N.B. F-state management is only supported for on-SoC GPIO controllers.
+ //
+
+ ControllerInformation->Flags.DeviceIdlePowerMgmtSupported = FALSE;
+ ControllerInformation->Flags.BankIdlePowerMgmtSupported = FALSE;
+
+ //
+ // Note the IdleTimeout parameter does not need to be initialized if
+ // D-state power management is not supported.
+ //
+ // ControllerInformation->IdleTimeout = IdleTimeoutDefaultValue;
+ //
+
+ //
+ // Indicate that the client driver prefers GPIO class extension ActiveBoth
+ // emulation.
+ //
+
+ ControllerInformation->Flags.EmulateActiveBoth = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioStartController (
+ _In_ PVOID Context,
+ _In_ BOOLEAN RestoreContext,
+ _In_ WDF_POWER_DEVICE_STATE PreviousPowerState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the simulated GPIO controller. This routine is
+ responsible for configuring all the pins to their default modes.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path. It is called at PASSIVE_IRQL though.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ RestoreContext - Supplies a flag that indicates whether the client driver
+ should restore the GPIO controller state to a previously saved state
+ or not.
+
+ PreviousPowerState - Supplies the device power state that the device was in
+ before this transition to D0.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(PreviousPowerState);
+
+ //
+ // Perform all the steps necessary to start the device.
+ //
+
+ //
+ // If restore context is FALSE, then this is initial transition into D0
+ // power state for this controller. In such case, disable any interrupts
+ // that may have been left enabled (e.g. perhaps by FW, previous D0 -> Dx
+ // transition etc.) Otherwise, such interrupts could trigger an interrupt
+ // storm if they were to assert without any driver being registered to
+ // handle such interrupts.
+ //
+ // If restore context is TRUE, then this is a transition into D0 power
+ // state from a lower power Dx state. In such case, restore the context
+ // that was present before the controller transitioned into the lower
+ // power state.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ Status = STATUS_SUCCESS;
+ if (RestoreContext == FALSE) {
+ for (BankId = 0; BankId < GpioContext->TotalBanks; BankId += 1) {
+ GpioBank = &GpioContext->Banks[BankId];
+
+ //
+ // Read the current values of the interrupt enable register.
+ //
+
+ EnableValue = 0;
+ Status = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto StartControllerEnd;
+ }
+
+ //
+ // If no interrupts are enabled, then skip to the next bank.
+ //
+
+ if (EnableValue == 0) {
+ continue;
+ }
+
+ //
+ // Disable all interrupts on this bank by clearing the enable
+ // register.
+ //
+
+ EnableValue = 0;
+ Status = SimGpioSpbWriteByte(GpioBank, EnableRegister, EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto StartControllerEnd;
+ }
+ }
+
+ } else {
+
+ //
+ // Restoring the controller state involves restoring the state of
+ // each SimGPIO bank.
+ //
+
+ for (BankId = 0; BankId < GpioContext->TotalBanks; BankId += 1) {
+ Status = SimGpioRestoreBankHardwareContext(Context, BankId);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioRestoreBankHardwareContext() failed! "
+ "Context = %p, Bank = %d, Status = %#x\n",
+ __FUNCTION__,
+ Context,
+ BankId,
+ Status);
+
+ goto StartControllerEnd;
+ }
+ }
+ }
+
+StartControllerEnd:
+ return Status;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioStopController (
+ _In_ PVOID Context,
+ _In_ BOOLEAN SaveContext,
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the GPIO controller. This routine is responsible for
+ resetting all the pins to their default modes.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ SaveContext - Supplies a flag that indicates whether the client driver
+ should save the GPIO controller state or not. The state may need
+ to be restored when the controller is restarted.
+
+ TargetState - Supplies the device power state which the device will be put
+ in once the callback is complete.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(TargetState);
+
+ //
+ // Perform all the steps necessary to stop the device.
+ //
+
+ //
+ // If save context is FALSE, then this is a final transition into D3/off
+ // power state. Hence saving of context is not necessary.
+ //
+ // If save context is TRUE, then this is a transition into a lower power
+ // Dx state. In such case, save the context as it will need to be
+ // restored when the device is brought back to D0 (i.e. ON) power state.
+ //
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ Status = STATUS_SUCCESS;
+ if (SaveContext == TRUE) {
+ for (BankId = 0; BankId < GpioContext->TotalBanks; BankId += 1) {
+ Status = SimGpioSaveBankHardwareContext(Context, BankId);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSaveBankHardwareContext() failed! "
+ "Context = %p, Bank = %d, Status = %#x\n",
+ __FUNCTION__,
+ Context,
+ BankId,
+ Status);
+
+ goto StopControllerEnd;
+ }
+ }
+ }
+
+StopControllerEnd:
+ return Status;
+}
+
+//
+// --------------------------------------------------------- Interrupt Handlers
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioEnableInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_ENABLE_INTERRUPT_PARAMETERS EnableParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine configures the supplied pin for interrupt.
+
+ N.B. For off-SOC GPIOs, the GPIO class extension synchronizes this callback
+ with other interrupt-related callbacks. Thus the locking is
+ automatically taken care of by the class extension.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ EnableParameters - Supplies a pointer to a structure containing enable
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be enabled. The pin
+ number is relative to the bank.
+
+ Flags - Supplies flags controlling the enable operation. Currently
+ no flags are defined.
+
+ InterruptMode - Supplies the trigger mode (edge or level) configured for
+ this interrupt when it was enabled.
+
+ Polarity - Supplies the polarity (active low or active high) configured
+ for this interrupt when it was enabled.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ VendorData - Supplies an optional pointer to a buffer containing the
+ vendor data supplied in the GPIO descriptor. This field will be
+ NULL if no vendor data was supplied. This buffer is read-only.
+
+ VendorDataLength - Supplies the length of the vendor data buffer.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ UCHAR ModeValue;
+ PIN_NUMBER PinNumber;
+ UCHAR PolarityValue;
+ NTSTATUS Status;
+ UCHAR StatusRegisterValue;
+
+ //
+ // If the polarity is not supported, then bail out. Note the interrupt
+ // polarity cannot be InterruptActiveBoth as this sample uses ActiveBoth
+ // emulation.
+ //
+
+ if ((EnableParameters->Polarity != InterruptActiveHigh) &&
+ (EnableParameters->Polarity != InterruptActiveLow)) {
+
+ Status = STATUS_NOT_SUPPORTED;
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: Polarity not supported! Polarity = %d, Status = %#x\n",
+ __FUNCTION__,
+ EnableParameters->Polarity,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ BankId = EnableParameters->BankId;
+ PinNumber = EnableParameters->PinNumber;
+ Status = STATUS_SUCCESS;
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+
+ //
+ // Read the current values of the interrupt mode register, polarity
+ // register, enable register.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, ModeRegister, &ModeValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(ModeRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ Status = SimGpioSpbReadByte(GpioBank, PolarityRegister, &PolarityValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(PolarityRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ Status = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ //
+ // Determine the mode register value. If the interrupt is Level then set
+ // the bit; otherwise, clear it (edge-triggered).
+ //
+
+ if (EnableParameters->InterruptMode == LevelSensitive) {
+ ModeValue |= (1 << PinNumber);
+ } else {
+ ModeValue &= ~(1 << PinNumber);
+ }
+
+ //
+ // Determine the new polarity register value. If the interrupt is ActiveHigh
+ // (or Rising-edge) then set it to 0x1. Otherwise, clear it.
+ //
+
+ switch (EnableParameters->Polarity) {
+
+ case InterruptActiveHigh:
+ PolarityValue |= (1 << PinNumber);
+ break;
+
+ case InterruptActiveLow:
+ PolarityValue &= ~(1 << PinNumber);
+ break;
+ }
+
+ //
+ // Clear the corresponding status bit first to ignore any stale value.
+ // The status register is atomically modified on the controller. It takes
+ // a bitmask on the bits to be cleared.
+ //
+
+ StatusRegisterValue = (1 << PinNumber);
+
+ //
+ // Enable the interrupt by setting the bit in the interrupt enable register.
+ //
+
+ EnableValue |= (1 << PinNumber);
+
+ //
+ // Write the new values for the interrupt mode register, polarity
+ // register, status register and enable register.
+ //
+
+ Status = SimGpioSpbWriteByte(GpioBank, ModeRegister, ModeValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(ModeRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ Status = SimGpioSpbWriteByte(GpioBank, PolarityRegister, PolarityValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(PolarityRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ Status = SimGpioSpbWriteByte(GpioBank, StatusRegister, StatusRegisterValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(StatusRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto EnableInterruptEnd;
+ }
+
+ //
+ // Enable the interrupt by setting the bit in the interrupt enable register.
+ //
+
+ Status = SimGpioSpbWriteByte(GpioBank, EnableRegister, EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+
+ goto EnableInterruptEnd;
+ }
+
+EnableInterruptEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioDisableInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_DISABLE_INTERRUPT_PARAMETERS DisableParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine disables the supplied pin from interrupting.
+
+ This routine is not marked PAGED as it may be called before/after
+ the boot device is in D0/D3 if boot device has GPIO dependencies.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ DisableParameters - Supplies a pointer to a structure supplying the
+ parameters for disabling the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be disabled. The pin
+ number is relative to the bank.
+
+ Flags - Supplies flags controlling the disable operation. Currently
+ no flags are defined.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[DisableParameters->BankId];
+
+ //
+ // Read the current value of the interrupt enable register.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto DisableInterruptEnd;
+ }
+
+ //
+ // Disable the interrupt by clearing the bit in the interrupt enable
+ // register.
+ //
+
+ EnableValue &= ~(1 << DisableParameters->PinNumber);
+ Status = SimGpioSpbWriteByte(GpioBank, EnableRegister, EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto DisableInterruptEnd;
+ }
+
+DisableInterruptEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioMaskInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_MASK_INTERRUPT_PARAMETERS MaskParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes masks the supplied pin from interrupting.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ MaskParameters - Supplies a pointer to a structure containing mask
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinMask - Supplies a bitmask of pins which should be masked. If a pin
+ should be masked, then the corresponding bit is set in the bitmask.
+
+ FailedMask - Supplies a bitmask of pins that failed to be masked. If
+ a pin could not be masked, the bit should be set in this field.
+
+ N.B. This should only be done if for non memory-mapped controllers.
+ Memory-mapped controllers are never expected to fail this
+ operation.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ GPIO_DISABLE_INTERRUPT_PARAMETERS DisableParameters;
+ PIN_NUMBER PinIndex;
+ ULONG64 PinMask;
+ NTSTATUS Status;
+
+ //
+ // Mask is essentially same as disable for SimGPIO controller. The primary
+ // difference is that mask callback supplies a bit-mask.
+ //
+
+ Status = STATUS_SUCCESS;
+ PinMask = MaskParameters->PinMask;
+ RtlZeroMemory(&DisableParameters, sizeof(DisableParameters));
+ DisableParameters.BankId = MaskParameters->BankId;
+ while (PinMask > 0) {
+ PinIndex = RtlFindLeastSignificantBit(PinMask);
+ if (PinIndex == 0xFF) {
+
+ NT_ASSERT(FALSE);
+
+ goto MaskInterruptsEnd;
+ }
+
+ DisableParameters.PinNumber = PinIndex;
+ Status = SimGpioDisableInterrupt(Context, &DisableParameters);
+ if (!NT_SUCCESS(Status)) {
+ goto MaskInterruptsEnd;
+ }
+
+ PinMask &= ~(1 << PinIndex);
+ }
+
+ //
+ // Set the bitmask of pins that could not be successfully masked.
+ //
+
+MaskInterruptsEnd:
+ MaskParameters->FailedMask = PinMask;
+ return Status;
+}
+
+NTSTATUS
+SimGpioUnmaskInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_ENABLE_INTERRUPT_PARAMETERS UnmaskParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes unmasks the supplied interrupt pin.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ UnmaskParameters - Supplies a pointer to a structure containing parameters
+ for unmasking the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be unmasked. The pin
+ number is relative to the bank.
+
+ InterruptMode - Supplies the trigger mode (edge or level) configured for
+ this interrupt when it was enabled.
+
+ Polarity - Supplies the polarity (active low or active high) configured
+ for this interrupt when it was enabled.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ VendorData - NULL.
+
+ VendorDataLength - 0.
+
+ N.B. The VendorData and VendorDataLength are not supplied for unmask
+ operation (i.e., both fields are zero).
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[UnmaskParameters->BankId];
+
+ //
+ // Read the current value of the interrupt enable register.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto UnmaskInterruptEnd;
+ }
+
+ //
+ // Unmask the interrupt by setting the bit in the interrupt enable
+ // register.
+ //
+
+ EnableValue |= (1 << UnmaskParameters->PinNumber);
+ Status = SimGpioSpbWriteByte(GpioBank, EnableRegister, EnableValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto UnmaskInterruptEnd;
+ }
+
+UnmaskInterruptEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioQueryActiveInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_QUERY_ACTIVE_INTERRUPTS_PARAMETERS QueryActiveParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current set of active interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ QueryActiveParameters - Supplies a pointer to a structure containing query
+ parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ EnabledMask - Supplies a bitmask of pins enabled for interrupts
+ on the specified GPIO bank.
+
+ ActiveMask - Supplies a bitmask that receives the active interrupt
+ mask. If a pin is interrupting and set in EnabledMask, then the
+ corresponding bit is set in the bitmask.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS ReturnStatus;
+ UCHAR StatusValue;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[QueryActiveParameters->BankId];
+
+ //
+ // NOTE: As SimGPIO is not a real hardware device, no interrupt will ever
+ // fire. Thus the status register value will never change. To pretend
+ // as if a real interrupt happened, it marks all currently enabled
+ // interrupts as asserting. Copy the enable interrupt value into
+ // the status register.
+ //
+ // This should NOT be done for a real GPIO controller!!
+ //
+
+ //
+ // BEGIN: SIMGPIO HACK.
+ //
+
+ ReturnStatus = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(ReturnStatus)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ ReturnStatus);
+
+ goto QueryActiveInterruptsEnd;
+ }
+
+ ReturnStatus = SimGpioSpbWriteByte(GpioBank, StatusRegister, EnableValue);
+ if (!NT_SUCCESS(ReturnStatus)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(StatusRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ ReturnStatus);
+
+ goto QueryActiveInterruptsEnd;
+ }
+
+ //
+ // END: SIMGPIO HACK.
+ //
+
+ //
+ // Return the current value of the interrupt status register in the
+ // ActiveMask parameter.
+ //
+
+ ReturnStatus = SimGpioSpbReadByte(GpioBank, StatusRegister, &StatusValue);
+ if (!NT_SUCCESS(ReturnStatus)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ ReturnStatus);
+
+ goto QueryActiveInterruptsEnd;
+ }
+
+ QueryActiveParameters->ActiveMask = (ULONG64)StatusValue;
+
+QueryActiveInterruptsEnd:
+ return ReturnStatus;
+}
+
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioQueryEnabledInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_QUERY_ENABLED_INTERRUPTS_PARAMETERS QueryEnabledParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current set of enabled interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ QueryEnabledParameters - Supplies a pointer to a structure containing query
+ parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ EnabledMask - Supplies a bitmask that receives the enabled interrupt
+ mask. If a pin is enabled, then the corresponding bit is set in the
+ mask.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called with the
+ interrupt lock acquired by the class extension, but not always
+ from within the interrupt context.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ UCHAR EnableValue;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS ReturnStatus;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[QueryEnabledParameters->BankId];
+
+ //
+ // Return the current value of the interrupt enable register into the
+ // EnabledMask parameter. It is strongly preferred that the true state of
+ // the hardware is returned, rather than a software-cached variable, since
+ // CLIENT_QueryEnabledInterrupts is used by the class extension to detect
+ // interrupt storms.
+ //
+
+ ReturnStatus = SimGpioSpbReadByte(GpioBank, EnableRegister, &EnableValue);
+ if (!NT_SUCCESS(ReturnStatus)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ ReturnStatus);
+
+ goto QueryEnabledInterruptsEnd;
+ }
+
+ QueryEnabledParameters->EnabledMask = (ULONG64)EnableValue;
+
+QueryEnabledInterruptsEnd:
+ return ReturnStatus;
+}
+_Must_inspect_result_
+_IRQL_requires_same_
+NTSTATUS
+SimGpioClearActiveInterrupts (
+ _In_ PVOID Context,
+ _In_ PGPIO_CLEAR_ACTIVE_INTERRUPTS_PARAMETERS ClearParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine clears the GPIO controller's active set of interrupts.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ClearParameters - Supplies a pointer to a structure containing clear
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ ClearActiveMask - Supplies a mask of pins which should be marked as
+ inactive. If a pin should be cleared, then the corresponding bit is
+ set in the mask.
+
+ FailedClearMask - Supplies a bitmask of pins that failed to be cleared. If
+ a pin could not be cleared, the bit should be set in this field.
+
+ N.B. This should only be done if for non memory-mapped controllers.
+ Memory-mapped controllers are never expected to fail this
+ operation.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS ReturnStatus;
+ UCHAR StatusValue;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ClearParameters->BankId];
+
+ //
+ // Clear the bits that are set in the ClearActiveMask parameter.
+ //
+
+ StatusValue = (UCHAR)ClearParameters->ClearActiveMask;
+ ReturnStatus = SimGpioSpbWriteByte(GpioBank, StatusRegister, StatusValue);
+ if (!NT_SUCCESS(ReturnStatus)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(StatusRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ ReturnStatus);
+
+ goto ClearActiveInterruptsEnd;
+ }
+
+ //
+ // If the operation succeeded, then all the bits were cleared.
+ //
+
+ StatusValue = 0x0;
+
+ //
+ // Set the bitmask of pins that could not be successfully cleared.
+ // Either all bits get written successfully or none does.
+ //
+
+ClearActiveInterruptsEnd:
+ ClearParameters->FailedClearMask = StatusValue;
+ return ReturnStatus;
+}
+
+NTSTATUS
+SimGpioReconfigureInterrupt (
+ _In_ PVOID Context,
+ _In_ PGPIO_RECONFIGURE_INTERRUPTS_PARAMETERS ReconfigureParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reconfigures the interrupt in the specified mode.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ReconfigureParameters - Supplies a pointer to a structure containing
+ parameters for reconfiguring the interrupt. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumber - Supplies the interrupt line that should be reconfigured.
+ The pin number is relative to the bank.
+
+ InterruptMode - Supplies the trigger mode (edge or level) for the new
+ configuration.
+
+ Polarity - Supplies the polarity (active low or active high) for the
+ new configuration.
+ Note: For edge-triggered interrupts, ActiveLow corresponds to the
+ falling edge; ActiveHigh corresponds to the rising edge.
+
+Return Value:
+
+ NTSTATUS code.
+
+Environment:
+
+ Entry IRQL: DIRQL if the GPIO controller is memory-mapped; PASSIVE_LEVEL
+ if the controller is behind some serial-bus.
+
+ N.B. For memory-mapped controllers, this routine is called from within
+ the interrupt context with the interrupt lock acquired by the class
+ extension. Hence the lock is not re-acquired here.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other query/clear active and enabled interrupts.
+ Memory-mapped GPIO controllers:
+ Callbacks invoked at PASSIVE_LEVEL IRQL (e.g. interrupt
+ enable/disable/unmask or IO operations) may be active. Those
+ routines should acquire the interrupt lock prior to manipulating
+ any state accessed from within this routine.
+
+ Serial-accessible GPIO controllers:
+ This call is synchronized with all other interrupt and IO callbacks.
+
+--*/
+
+{
+
+ BANK_ID BankId;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ UCHAR ModeValue;
+ PIN_NUMBER PinNumber;
+ UCHAR PolarityValue;
+ NTSTATUS Status;
+ UCHAR StatusRegisterValue;
+
+
+ BankId = ReconfigureParameters->BankId;
+ PinNumber = ReconfigureParameters->PinNumber;
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+
+ //
+ // Read the current values of the interrupt mode register, polarity
+ // register, enable register.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, ModeRegister, &ModeValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(ModeRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReconfigureInterruptEnd;
+ }
+
+ Status = SimGpioSpbReadByte(GpioBank, PolarityRegister, &PolarityValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(PolarityRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReconfigureInterruptEnd;
+ }
+
+ //
+ // Determine the mode register value. If the interrupt is Level then set
+ // the bit; otherwise, clear it (edge-triggered).
+ //
+
+ if (ReconfigureParameters->InterruptMode == LevelSensitive) {
+ ModeValue |= (1 << PinNumber);
+ } else {
+ ModeValue &= ~(1 << PinNumber);
+ }
+
+ //
+ // Determine the new polarity register value. If the interrupt is ActiveHigh
+ // (or Rising-edge) then set it to 0x1. Otherwise, clear it.
+ //
+
+ switch (ReconfigureParameters->Polarity) {
+
+ case InterruptActiveHigh:
+ PolarityValue |= (1 << PinNumber);
+ break;
+
+ case InterruptActiveLow:
+ PolarityValue &= ~(1 << PinNumber);
+ break;
+ }
+
+ //
+ // Clear any stale status bits from the previous configuration.
+ //
+ // The status register is atomically modified on the controller. It takes
+ // a bitmask on the bits to be cleared.
+ //
+
+ StatusRegisterValue = (1 << PinNumber);
+ Status = SimGpioSpbWriteByte(GpioBank, StatusRegister, StatusRegisterValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(StatusRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReconfigureInterruptEnd;
+ }
+
+ //
+ // Write the new values for the interrupt mode register, polarity
+ // register, status register and enable register.
+ //
+
+ Status = SimGpioSpbWriteByte(GpioBank, ModeRegister, ModeValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(ModeRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReconfigureInterruptEnd;
+ }
+
+ Status = SimGpioSpbWriteByte(GpioBank, PolarityRegister, PolarityValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(PolarityRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReconfigureInterruptEnd;
+ }
+
+ReconfigureInterruptEnd:
+ return Status;
+}
+
+//
+// --------------------------------------------------------------- I/O Handlers
+//
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioConnectIoPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_CONNECT_IO_PINS_PARAMETERS ConnectParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes connects the specified pins for IO. The pins can
+ be read from if connected for input, or written to if connected for
+ output.
+
+ N.B. This routine is called at PASSIVE_LEVEL but is not marked as
+ PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ConnectParameters - Supplies a pointer to a structure supplying the
+ parameters for connecting the IO pins. Fields description:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumberTable - Supplies an array of pins to be connected for IO. The
+ pin numbers are 0-based and relative to the GPIO bank.
+
+ PinCount - Supplies the number of pins in the pin number table.
+
+ ConnectMode - Supplies the mode in which the pins should be configured
+ (viz. input or output).
+
+ ConnectFlags - Supplies the flags controlling the IO setup. Currently
+ no flags are defined.
+
+ PullConfiguration - Supplies the pin pull-up/pull-down configuration.
+
+ DebouceTimeout - Supplies the debounce timeout to be applied. The
+ field is in 100th of milli-seconds (i.e., 5.84ms will be supplied
+ as 584). Default value is zero, which implies, no debounce.
+
+ DriveStrength - Supplies the drive strength to be applied. The value
+ is in 100th of mA (i.e., 1.21mA will be supplied as 121mA).
+
+ VendorData - Supplies an optional pointer to a buffer containing the
+ vendor data supplied in the GPIO descriptor. This field will be
+ NULL if no vendor data was supplied. This buffer is read-only.
+
+ VendorDataLength - Supplies the length of the vendor data buffer.
+
+ ConnectFlags - Supplies the flag to be used for connect operation.
+ Currently no flags are defined.
+
+Return Value:
+
+ NT status code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ PPIN_NUMBER PinNumberTable;
+ UCHAR PinValue;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ConnectParameters->BankId];
+
+ //
+ // Read the current direction register value.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, DirectionRegister, &PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(DirectionRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ConnectIoPinsEnd;
+ }
+
+ //
+ // Walk through all the supplied pins and connect them in the specified
+ // mode (input or output).
+ //
+
+ PinNumberTable = ConnectParameters->PinNumberTable;
+ for (Index = 0; Index < ConnectParameters->PinCount; Index += 1) {
+ PinNumber = PinNumberTable[Index];
+
+ //
+ // If the pins are being connected for input, then set the bit.
+ // Otherwise clear the bit.
+ //
+
+ if (ConnectParameters->ConnectMode == ConnectModeInput) {
+ PinValue |= (1 << PinNumber);
+
+ } else if (ConnectParameters->ConnectMode == ConnectModeOutput) {
+ PinValue &= ~(1 << PinNumber);
+ }
+ }
+
+ Status = SimGpioSpbWriteByte(GpioBank, DirectionRegister, PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(DirectionRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ConnectIoPinsEnd;
+ }
+
+ConnectIoPinsEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+_IRQL_requires_(PASSIVE_LEVEL)
+NTSTATUS
+SimGpioDisconnectIoPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_DISCONNECT_IO_PINS_PARAMETERS DisconnectParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine invokes disconnects the specified IO pins. The pins are
+ put back in their original mode.
+
+ N.B. This routine is called at PASSIVE_LEVEL but is not marked as
+ PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ DisconnectParameters - Supplies a pointer to a structure containing
+ disconnect operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinNumberTable - Supplies an array of pins to be disconnected. The pin
+ numbers are relative to the GPIO bank.
+
+ PinCount - Supplies the number of pins in the pin number table.
+
+ DisconnectMode - Supplies the mode in which the pins are currently
+ configured (viz. input or output).
+
+ DisconnectFlags - Supplies the flags controlling the IO setup. Currently
+ no flags are defined.
+
+Return Value:
+
+ NT status code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ PIN_NUMBER PinNumber;
+ PPIN_NUMBER PinNumberTable;
+ UCHAR PinValue;
+ NTSTATUS Status;
+
+ //
+ // If the pin configuration should be preserved post disconnect, then
+ // there is nothing left to do.
+ //
+
+ if (DisconnectParameters->DisconnectFlags.PreserveConfiguration == 1) {
+ Status = STATUS_SUCCESS;
+ goto DisconnectIoPinsEnd;
+ }
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[DisconnectParameters->BankId];
+
+ //
+ // Read the current direction register value.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, DirectionRegister, &PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(DirectionRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto DisconnectIoPinsEnd;
+ }
+
+ //
+ // Walk through all the supplied pins and disconnect them. On SimGPIO
+ // controller, all pins are reset to the default mode (output).
+ //
+
+ PinNumberTable = DisconnectParameters->PinNumberTable;
+ for (Index = 0; Index < DisconnectParameters->PinCount; Index += 1) {
+ PinNumber = PinNumberTable[Index];
+ PinValue &= ~(1 << PinNumber);
+ }
+
+ Status = SimGpioSpbWriteByte(GpioBank, DirectionRegister, PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(DirectionRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto DisconnectIoPinsEnd;
+ }
+
+DisconnectIoPinsEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+NTSTATUS
+SimGpioReadGpioPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_READ_PINS_MASK_PARAMETERS ReadParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the current values for all the pins.
+
+ As the FormatIoRequestsAsMasks bit was set inside
+ SimGpioQueryControllerInformation(), all this routine needs to do is read
+ the level register value and return to the GPIO class extension. It will
+ return the right set of bits to the caller.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ ReadParameters - Supplies a pointer to a structure containing read
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ PinValues - Supplies a pointer to a variable that receives the current
+ pin values.
+
+ Flags - Supplies the flag to be used for read operation. Currently
+ defined flags are:
+
+ WriteConfiguredPins: If set, the read is being done on a set of
+ pin that were configured for write. In such cases, the
+ GPIO client driver is expected to read and return the
+ output register value.
+
+Return Value:
+
+ NT status code.
+
+Environment:
+
+ Entry IRQL: PASSIVE_LEVEL.
+
+ Synchronization: The GPIO class extension will synchronize this call
+ against other passive-level interrupt callbacks (e.g. enable/disable/
+ unmask) and IO callbacks.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ UCHAR PinValue;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[ReadParameters->BankId];
+
+ //
+ // Read the current level register value. Note the GPIO class may invoke
+ // the read routine on write-configured pins. In such case the output
+ // register values should be read.
+ //
+ // N.B. In case of SimGPIO, the LevelRegister holds the value for input
+ // as well as output pins. Thus the same register is read in either
+ // case.
+ //
+
+ if (ReadParameters->Flags.WriteConfiguredPins == FALSE) {
+ Status = SimGpioSpbReadByte(GpioBank, LevelRegister, &PinValue);
+
+ } else {
+ Status = SimGpioSpbReadByte(GpioBank, LevelRegister, &PinValue);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(DirectionRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto ReadGpioPinsEnd;
+ }
+
+ *ReadParameters->PinValues = PinValue;
+
+ReadGpioPinsEnd:
+ return Status;
+}
+
+_Must_inspect_result_
+NTSTATUS
+SimGpioWriteGpioPins (
+ _In_ PVOID Context,
+ _In_ PGPIO_WRITE_PINS_MASK_PARAMETERS WriteParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the current values for the specified pins. This call is
+ synchronized with the write and connect/disconnect IO calls.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ WriteParameters - Supplies a pointer to a structure containing write
+ operation parameters. Fields are:
+
+ BankId - Supplies the ID for the GPIO bank.
+
+ SetMask - Supplies a mask of pins which should be set (0x1). If a pin
+ should be set, then the corresponding bit is set in the mask.
+ All bits that are clear in the mask should be left intact.
+
+ ClearMask - Supplies a mask of pins which should be cleared (0x0). If
+ a pin should be cleared, then the bit is set in the bitmask. All
+ bits that are clear in the mask should be left intact.
+
+ Flags - Supplies the flag controlling the write operation. Currently
+ no flags are defined.
+
+Return Value:
+
+ NT status code.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ UCHAR PinValue;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[WriteParameters->BankId];
+
+ //
+ // Read the current level register value.
+ //
+
+ Status = SimGpioSpbReadByte(GpioBank, LevelRegister, &PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(DirectionRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto WriteGpioPinsEnd;
+ }
+
+ //
+ // Set the bits specified in the set mask and clear the ones specified
+ // in the clear mask.
+ //
+
+ PinValue |= WriteParameters->SetMask;
+ PinValue &= ~WriteParameters->ClearMask;
+
+ //
+ // Write the updated value to the register.
+ //
+
+ Status = SimGpioSpbWriteByte(GpioBank, LevelRegister, PinValue);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(DirectionRegister) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto WriteGpioPinsEnd;
+ }
+
+WriteGpioPinsEnd:
+ return Status;
+}
+
+VOID
+SimGpioEvtDriverUnload (
+ _In_ WDFDRIVER Driver
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by WDF to allow final cleanup prior to unloading
+ the GPIO class extension. This routine destroys the class library and stops
+ tracing.
+
+Arguments:
+
+ Driver - Supplies a handle to a framework driver object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDRIVER_OBJECT DriverObject;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ Status = GPIO_CLX_UnregisterClient(Driver);
+ NT_ASSERT(NT_SUCCESS(Status));
+
+ DriverObject = WdfDriverWdmGetDriverObject(Driver);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_INIT,
+ "%s: Driver unloaded!\n",
+ __FUNCTION__);
+
+ WPP_CLEANUP(DriverObject);
+ return;
+}
+
+//
+// ------------------------------------------------------- Power mgmt handlers
+//
+
+NTSTATUS
+SimGpioSaveBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ BANK_ID BankId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the hardware context for the GPIO controller.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path. It is called at PASSIVE_IRQL though.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ BankId - Supplies the ID of the bank.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PUCHAR DestinationAddress;
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ NTSTATUS Status;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+ Status = STATUS_SUCCESS;
+
+ //
+ // Loop through all the registers and save them. The status register can
+ // only be written to be cleared and thus isn't saved.
+ //
+
+ for (Index = 0; Index < MaximumSimGpioAddress; Index += 1) {
+ if (Index == StatusRegister) {
+ continue;
+ }
+
+ DestinationAddress = &GpioBank->SavedRegisterContext[Index];
+ Status = SimGpioSpbReadByte(GpioBank, Index, DestinationAddress);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbReadByte(Register = %d) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Index,
+ Status);
+
+ goto SaveBankHardwareContextEnd;
+ }
+ }
+
+SaveBankHardwareContextEnd:
+ return Status;
+}
+
+NTSTATUS
+SimGpioRestoreBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ BANK_ID BankId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the hardware context for the GPIO controller.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ Context - Supplies a pointer to the GPIO client driver's device extension.
+
+ BankId - Supplies the ID of the bank.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PSIM_GPIO_BANK GpioBank;
+ PSIM_GPIO_CONTEXT GpioContext;
+ ULONG Index;
+ NTSTATUS Status;
+ UCHAR Value;
+
+ GpioContext = (PSIM_GPIO_CONTEXT)Context;
+ GpioBank = &GpioContext->Banks[BankId];
+ Status = STATUS_SUCCESS;
+
+ //
+ // Loop through all the registers and write them. The order of restore is
+ // important. The enable and direction registers need to be programmed
+ // after the (mode, polarity) and level registers have been written to.
+ // Hence they are restored at the very end.
+ //
+
+ for (Index = 0; Index < MaximumSimGpioAddress; Index += 1) {
+ if ((Index == EnableRegister) ||
+ (Index == DirectionRegister) ||
+ (Index == StatusRegister)) {
+
+ continue;
+ }
+
+ Value = GpioBank->SavedRegisterContext[Index];
+ Status = SimGpioSpbWriteByte(GpioBank, Index, Value);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(Register = %d) failed! "
+ "Status = %#x\n",
+ __FUNCTION__,
+ Index,
+ Status);
+
+ goto RestoreBankHardwareContextEnd;
+ }
+ }
+
+ //
+ // Restore the direction register.
+ //
+
+ Value = GpioBank->SavedRegisterContext[DirectionRegister];
+ Status = SimGpioSpbWriteByte(GpioBank, DirectionRegister, Value);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(DirectionRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto RestoreBankHardwareContextEnd;
+ }
+
+ //
+ // Restore the interrupt enable register at the very end.
+ //
+
+ Value = GpioBank->SavedRegisterContext[EnableRegister];
+ Status = SimGpioSpbWriteByte(GpioBank, EnableRegister, Value);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: SimGpioSpbWriteByte(EnableRegister) failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto RestoreBankHardwareContextEnd;
+ }
+
+RestoreBankHardwareContextEnd:
+ return Status;
+}
+
+__pragma(warning(default: 4127)) // conditional expression is a constant
+
+
diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.h b/gpio/samples/simgpio_i2c/simgpio_i2c.h
new file mode 100644
index 00000000..a9c02af3
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.h
@@ -0,0 +1,176 @@
+/*++
+
+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:
+
+ simgpio_i2c.h
+
+Abstract:
+
+ This sample implements a GPIO client driver for simulated GPIO (SimGpio)
+ controller.
+
+ Note: DIRQL in the comments below refers to device IRQL, which is any
+ IRQL > DISPATCH_LEVEL (and less than some IRQL reserved for OS use).
+
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+//
+// -------------------------------------------------------------------- Defines
+//
+
+//
+// Define total number of pins on the simulated GPIO controller.
+//
+
+#define SIM_GPIO_TOTAL_PINS (16)
+#define SIM_GPIO_PINS_PER_BANK (8)
+#define SIM_GPIO_TOTAL_BANKS (SIM_GPIO_TOTAL_PINS / SIM_GPIO_PINS_PER_BANK)
+
+#define SIM_GPIO_REGISTER_ADDRESS_SIZE (sizeof(USHORT))
+
+//
+// Pool tag for SimGpio allocations.
+//
+
+#define SIM_GPIO_POOL_TAG 'GmiS'
+
+//
+// Macro for pointer arithmetic.
+//
+
+#define Add2Ptr(Ptr, Value) ((PVOID)((PUCHAR)(Ptr) + (Value)))
+
+//
+// ---------------------------------------------------------------------- Types
+//
+
+//
+// Define the registers within the SimGPIO controller. There are 16 pins per
+// controller. Note this is a logical device and thus may correspond to a
+// physical bank or module if the GPIO controller in hardware has more than
+// 16 pins. Below is the register set from a logical perspective.
+//
+// typedef struct _SIM_GPIO_REGISTERS {
+// UCHAR ModeRegister1;
+// UCHAR PolarityRegister1;
+// UCHAR EnableRegister1;
+// UCHAR StatusRegister1;
+// UCHAR DirectionRegister1;
+// UCHAR LevelRegister1;
+// UCHAR ModeRegister2;
+// UCHAR PolarityRegister2;
+// UCHAR EnableRegister2;
+// UCHAR StatusRegister2;
+// UCHAR DirectionRegister2;
+// UCHAR LevelRegister2;
+// } SIM_GPIO_REGISTERS, *PSIM_GPIO_REGISTERS;
+//
+//
+
+typedef enum _SIM_GPIO_REGISTER_ADDRESS {
+ ModeRegister = 0x0,
+ PolarityRegister,
+ EnableRegister,
+ StatusRegister,
+ DirectionRegister,
+ LevelRegister,
+ MaximumSimGpioAddress
+} SIM_GPIO_REGISTER_ADDRESS, *PSIM_GPIO_REGISTER_ADDRESS;
+
+struct _SIM_GPIO_CONTEXT;
+
+typedef struct _SIM_GPIO_BANK {
+ USHORT AddressBase;
+ struct _SIM_GPIO_CONTEXT *GpioContext;
+ UCHAR SavedRegisterContext[MaximumSimGpioAddress];
+} SIM_GPIO_BANK, *PSIM_GPIO_BANK;
+
+//
+// The SimGPIO client driver device extension.
+//
+
+struct _SIM_GPIO_CONTEXT {
+ USHORT TotalBanks;
+ USHORT TotalPins;
+ WDFDEVICE Device;
+ WDFIOTARGET SpbIoTarget;
+ LARGE_INTEGER SpbConnectionId;
+ WDFREQUEST SpbRequest;
+ // PSIM_GPIO_REGISTERS ControllerBase;
+ // ULONG Length;
+ SIM_GPIO_BANK Banks[SIM_GPIO_TOTAL_BANKS];
+};
+
+typedef struct _SIM_GPIO_CONTEXT SIM_GPIO_CONTEXT;
+typedef SIM_GPIO_CONTEXT *PSIM_GPIO_CONTEXT;
+
+//
+// Request context
+//
+typedef struct _SIM_GPIO_REQUEST_CONTEXT {
+ WDFDEVICE Device;
+
+ //
+ // Whether the request is a sequence or not.
+ //
+
+ BOOLEAN SequenceRequest;
+} SIM_GPIO_REQUEST_CONTEXT, *PSIM_GPIO_REQUEST_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SIM_GPIO_REQUEST_CONTEXT, GetRequestContext);
+
+//
+// ----------------------------------------------------------------- Prototypes
+//
+
+VOID
+SimGpioDestroySpbConnection (
+ _In_ PSIM_GPIO_CONTEXT SimGpioContext
+ );
+
+NTSTATUS
+SimGpioSpbReadByte (
+ _In_ PSIM_GPIO_BANK GpioBank,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _Out_writes_(sizeof(UCHAR)) PUCHAR Data
+ );
+
+NTSTATUS
+SimGpioSetupSpbConnection (
+ _In_ PSIM_GPIO_CONTEXT GpioContext
+ );
+
+NTSTATUS
+SimGpioSpbWriteByte (
+ _In_ PSIM_GPIO_BANK GpioBank,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _In_ UCHAR Data
+ );
+
+NTSTATUS
+SimGpioRestoreBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ BANK_ID BankId
+ );
+
+NTSTATUS
+SimGpioSaveBankHardwareContext (
+ _In_ PVOID Context,
+ _In_ BANK_ID BankId
+ );
+
+
diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.inx b/gpio/samples/simgpio_i2c/simgpio_i2c.inx
new file mode 100644
index 00000000..ab8a130d
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.inx
Binary files differ
diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.rc b/gpio/samples/simgpio_i2c/simgpio_i2c.rc
new file mode 100644
index 00000000..a2b60d9a
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Simulated GPIO I2C Client"
+#define VER_INTERNALNAME_STR "simgpio_i2c.sys"
+#define VER_ORIGINALFILENAME_STR "simgpio_i2c.sys"
+
+#include "common.ver"
+
diff --git a/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj
new file mode 100644
index 00000000..1e2e182e
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj
@@ -0,0 +1,200 @@
+<?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>{FBC7D66C-8D89-4ED5-B378-A4EBB8DED3B2}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{ABDC1F8D-20A4-4A63-9D67-7B8374C9057D}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>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="simgpio_i2c.c; spb_i2c.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ </ClCompile>
+ <Inf Include=".\simgpio_i2c.inx">
+ <DateStamp>*</DateStamp>
+ <SpecifyDriverVerDirectiveDate>true</SpecifyDriverVerDirectiveDate>
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\simgpio_i2c.inf</CopyOutput>
+ </Inf>
+ <OtherWpp Include="simgpio_i2c.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>simgpio_i2c</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>simgpio_i2c</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>simgpio_i2c</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>simgpio_i2c</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ksguid.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\msgpioclxstub.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="simgpio_i2c.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/simgpio_i2c/simgpio_i2c.vcxproj.Filters b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters
new file mode 100644
index 00000000..e5d09d4d
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/simgpio_i2c.vcxproj.Filters
@@ -0,0 +1,42 @@
+<?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>{522EE08F-03EE-45E0-875A-A47E2E9F025C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{22B4A1F1-B05A-4383-A9D2-BDBF45C56975}</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>{E394D95C-DF2A-4F28-9A22-A3C121FC5394}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{5D13D9B5-61BC-45B1-AF0D-4EDE9C7D2F80}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="simgpio_i2c.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="spb_i2c.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\simgpio_i2c.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\simgpio_i2c.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="simgpio_i2c.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/gpio/samples/simgpio_i2c/spb_i2c.c b/gpio/samples/simgpio_i2c/spb_i2c.c
new file mode 100644
index 00000000..a5ac3fc3
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/spb_i2c.c
@@ -0,0 +1,666 @@
+
+/*++
+
+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:
+
+ spb_i2c.c
+
+Abstract:
+
+ This sample implements a GPIO client driver for simulated GPIO (SimGpio)
+ controller.
+
+ Note: DIRQL in the comments below refers to device IRQL, which is any
+ IRQL > DISPATCH_LEVEL (and less than some IRQL reserved for OS use).
+
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <ntddk.h>
+#include <wdf.h>
+#include <gpioclx.h>
+#define RESHUB_USE_HELPER_ROUTINES
+#include "reshub.h" // Resource and descriptor definitions
+#include "spb.h" // SPB definitions
+#include "simgpio_i2c.h"
+#include "trace.h"
+#include "spb_i2c.tmh"
+
+//
+// -------------------------------------------------------------------- Defines
+//
+
+NTSTATUS
+SimGpioSpbRead (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _Out_writes_(DataLength) PUCHAR Data,
+ _In_ USHORT DataLength
+ );
+
+NTSTATUS
+SimGpioSpbSequence (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_reads_(SequenceLength) PVOID Sequence,
+ _In_ SIZE_T SequenceLength
+ );
+
+NTSTATUS
+SimGpioSpbWrite (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_ USHORT RegisterAddress,
+ _In_reads_(DataLength) PUCHAR Data,
+ _In_ ULONG DataLength
+ );
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+SimGpioSetupSpbConnection (
+ _In_ PSIM_GPIO_CONTEXT GpioContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens an I/O target to the controller driver using the
+ connection ID received during PrepareController callback.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power up path.
+
+Arguments:
+
+ GpioContext - Supplies a pionter to the client driver's device context.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDF_OBJECT_ATTRIBUTES Attributes;
+ WDF_IO_TARGET_OPEN_PARAMS Parameters;
+ WDF_OBJECT_ATTRIBUTES RequestAttributes;
+ PSIM_GPIO_REQUEST_CONTEXT RequestContext;
+ NTSTATUS Status;
+ DECLARE_UNICODE_STRING_SIZE(SpbDevicePath, RESOURCE_HUB_PATH_SIZE);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
+ Status = WdfIoTargetCreate(GpioContext->Device,
+ &Attributes,
+ &GpioContext->SpbIoTarget);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_INIT,
+ "%s: WdfIoTargetCreate failed to create SPB IoTarget! "
+ "Device = %p, Status:%#x\n",
+ __FUNCTION__,
+ GpioContext->Device,
+ Status);
+
+ if (GpioContext->SpbIoTarget != NULL) {
+ WdfObjectDelete(GpioContext->SpbIoTarget);
+ }
+
+ goto SetupSpbConnectionEnd;
+ }
+
+ //
+ // Use the connection ID supplied to create the full device path. This
+ // device path (indirectly) represents the path for the I2C controller.
+ //
+
+ Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
+ &SpbDevicePath,
+ GpioContext->SpbConnectionId.LowPart,
+ GpioContext->SpbConnectionId.HighPart);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "ResourceHub create device path (%wZ) failed Status:%#x",
+ &SpbDevicePath,
+ Status);
+
+ goto SetupSpbConnectionEnd;
+ }
+
+ //
+ // Initialize the parameters for the SPB IO target.
+ //
+
+ WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&Parameters,
+ &SpbDevicePath,
+ (GENERIC_READ | GENERIC_WRITE));
+
+ Parameters.ShareAccess = 0;
+ Parameters.CreateDisposition = FILE_OPEN;
+ Parameters.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ //
+ // Open the SPB IO target. This creates a handle to the I2C controller
+ // behind which SimGPO resides.
+ //
+
+ Status = WdfIoTargetOpen(GpioContext->SpbIoTarget, &Parameters);
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "WdfIoTargetOpen failed to open SPB target Status:%#x",
+ Status);
+
+ goto SetupSpbConnectionEnd;
+ }
+
+ //
+ // Create a SPB request for writes and reads to the IO target.
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&RequestAttributes, \
+ SIM_GPIO_REQUEST_CONTEXT);
+
+ Status = WdfRequestCreate(&RequestAttributes,
+ NULL,
+ &GpioContext->SpbRequest);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: WdfRequestCreate failed creating SpbRequest Status:%#x",
+ __FUNCTION__,
+ Status);
+
+ goto SetupSpbConnectionEnd;
+ }
+
+ //
+ // Initialize the request context with default values
+ //
+
+ RequestContext = GetRequestContext(GpioContext->SpbRequest);
+ RequestContext->Device = GpioContext->Device;
+ RequestContext->SequenceRequest = FALSE;
+
+SetupSpbConnectionEnd:
+ return Status;
+}
+
+VOID
+SimGpioDestroySpbConnection (
+ _In_ PSIM_GPIO_CONTEXT GpioContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the SPB I/O target and releases SPB-related resources.
+
+ N.B. This function is not marked pageable because this function is in
+ the device power down path.
+
+Arguments:
+
+ GpioContext - Supplies a pionter to the client driver's device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Delete the SPB request.
+ //
+
+ if (GpioContext->SpbRequest != NULL) {
+ WdfObjectDelete(GpioContext->SpbRequest);
+ }
+
+ //
+ // Delete the IO target. Note this will also close if it is opened.
+ //
+
+ if (GpioContext->SpbIoTarget != NULL) {
+ WdfObjectDelete(GpioContext->SpbIoTarget);
+ }
+
+ return;
+}
+
+NTSTATUS
+SimGpioSpbReadByte (
+ _In_ PSIM_GPIO_BANK GpioBank,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _Out_writes_(sizeof(UCHAR)) PUCHAR Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs a single-byte read from the SPB I/O target.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ GpioBank - Supplies a pionter to the GPIO bank to be read from.
+
+ RegisterAddress - Supplies the bank-relative register address to be read.
+
+ Data - Supplies the byte buffer to read the data into.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ USHORT ActualAddress;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ if (RegisterAddress >= MaximumSimGpioAddress) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto SpbReadByteEnd;
+ }
+
+ ActualAddress = GpioBank->AddressBase + (USHORT)RegisterAddress;
+ GpioContext = GpioBank->GpioContext;
+ Status = SimGpioSpbRead(GpioContext, RegisterAddress, Data, sizeof(UCHAR));
+
+SpbReadByteEnd:
+ return Status;
+}
+
+NTSTATUS
+SimGpioSpbRead (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _Out_writes_(DataLength) PUCHAR Data,
+ _In_ USHORT DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs a read from the SPB I/O target.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ GpioContext - Supplies a pionter to the client driver's device context.
+
+ RegisterAddress - Supplies the absolute register address to read from.
+
+ Data - Supplies the output byte buffer containing the data read.
+
+ DataLength - Supplies the length of the byte buffer data.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ USHORT Address;
+ UCHAR Index;
+ SPB_TRANSFER_LIST_AND_ENTRIES(2) Sequence;
+ NTSTATUS Status;
+
+ //
+ // Build the SPB sequence (send address, read data).
+ //
+
+ Address = RegisterAddress;
+ SPB_TRANSFER_LIST_INIT(&(Sequence.List), 2);
+ Index = 0; // silence prefast
+ Sequence.List.Transfers[Index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionToDevice,
+ 0,
+ &Address,
+ SIM_GPIO_REGISTER_ADDRESS_SIZE);
+
+ Index += 1; // silence prefast
+ Sequence.List.Transfers[Index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionFromDevice,
+ 0x0,
+ Data,
+ DataLength);
+
+ //
+ // Send the read as a sequence request to the SPB target.
+ //
+
+ Status = SimGpioSpbSequence(GpioContext, &Sequence, sizeof(Sequence));
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: SpbSequence failed sending a read sequence! "
+ "Status:%#x\n",
+ __FUNCTION__,
+ Status);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+SimGpioSpbWriteByte (
+ _In_ PSIM_GPIO_BANK GpioBank,
+ _In_ SIM_GPIO_REGISTER_ADDRESS RegisterAddress,
+ _In_ UCHAR Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs a single-byte write to the SPB I/O target.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ GpioBank - Supplies a pionter to the GPIO bank to be written to.
+
+ RegisterAddress - Supplies the bank-relative register address to write to.
+
+ Data - Supplies the data to be written.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ USHORT ActualAddress;
+ PSIM_GPIO_CONTEXT GpioContext;
+ NTSTATUS Status;
+
+ if (RegisterAddress >= MaximumSimGpioAddress) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto SpbWriteByteEnd;
+ }
+
+ ActualAddress = GpioBank->AddressBase + (USHORT)RegisterAddress;
+ GpioContext = GpioBank->GpioContext;
+ Status = SimGpioSpbWrite(GpioContext, RegisterAddress, &Data, sizeof(UCHAR));
+
+SpbWriteByteEnd:
+ return Status;
+}
+
+NTSTATUS
+SimGpioSpbWrite (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_ USHORT RegisterAddress,
+ _In_reads_(DataLength) PUCHAR Data,
+ _In_ ULONG DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs a write to the SPB I/O target.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ GpioContext - Supplies a pionter to the client driver's device context.
+
+ RegisterAddress - Supplies the absolute register address to write to.
+
+ Data - Supplies the byte buffer containing the data to be written.
+
+ DataLength - Supplies the length of the write buffer.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ PUCHAR Buffer;
+ ULONG BufferLength;
+ ULONG_PTR BytesWritten;
+ WDF_MEMORY_DESCRIPTOR MemoryDescriptor;
+ WDFMEMORY MemoryWrite;
+ NTSTATUS Status;
+
+ MemoryWrite = NULL;
+ if ((Data == NULL) || (DataLength <= 0)) {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: Invalid write request! Data:%p Length:%lu Status:%#x\n",
+ __FUNCTION__,
+ Data,
+ DataLength,
+ Status);
+
+ goto SpbWriteEnd;
+ }
+
+ //
+ // A SPB write-write is a single write request with the register
+ // and data combined in one buffer. So we need to allocate memory
+ // for the size of a register + data length
+
+ BufferLength = DataLength + SIM_GPIO_REGISTER_ADDRESS_SIZE;
+ Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES,
+ NonPagedPoolNx,
+ SIM_GPIO_POOL_TAG,
+ BufferLength,
+ &MemoryWrite,
+ (PVOID*)&Buffer);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: WdfMemoryCreate failed allocating memory buffer for write!"
+ "Status:%#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto SpbWriteEnd;
+ }
+
+ //
+ // Setup the write buffer. The buffer should contain address followed by
+ // data.
+ //
+
+ RtlCopyMemory(Buffer, &RegisterAddress, SIM_GPIO_REGISTER_ADDRESS_SIZE);
+ RtlCopyMemory((Buffer + SIM_GPIO_REGISTER_ADDRESS_SIZE), Data, DataLength);
+
+ //
+ // Send the request synchronously.
+ //
+
+ WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&MemoryDescriptor, MemoryWrite, NULL);
+ Status = WdfIoTargetSendWriteSynchronously(
+ GpioContext->SpbIoTarget,
+ NULL,
+ &MemoryDescriptor,
+ NULL,
+ NULL,
+ &BytesWritten);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: WdfIoTargetSendWriteSynchronously failed! Status = %#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto SpbWriteEnd;
+ }
+
+SpbWriteEnd:
+ if (MemoryWrite != NULL) {
+ WdfObjectDelete(MemoryWrite);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+SimGpioSpbSequence (
+ _In_ PSIM_GPIO_CONTEXT GpioContext,
+ _In_reads_(SequenceLength) PVOID Sequence,
+ _In_ SIZE_T SequenceLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine issues a sequence read-write request to the SPB I/O target.
+
+ N.B. This routine is called at PASSIVE_LEVEL for off-SoC GPIOs but is not
+ marked as PAGED_CODE as it could be executed late in the hibernate or
+ early in resume sequence (or the deep-idle sequence).
+
+Arguments:
+
+ GpioContext - Supplies a pionter to the client driver's device context.
+
+ Sequence - Supplies a pointer to a list of sequence transfers.
+
+ SequenceLength - Supplies the length of sequence transfers.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ WDF_OBJECT_ATTRIBUTES Attributes;
+ ULONG_PTR BytesReturned;
+ WDF_MEMORY_DESCRIPTOR MemoryDescriptor;
+ WDFMEMORY MemorySequence;
+ NTSTATUS Status;
+
+ if ((Sequence == NULL) || (SequenceLength == 0)) {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: Invalid sequence request! Sequence:%p Length:%lu Status:%#x\n",
+ __FUNCTION__,
+ Sequence,
+ (ULONG)SequenceLength,
+ Status);
+
+ goto SpbSequenceEnd;
+ }
+
+ //
+ // Create preallocated WDFMEMORY.
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
+ Status = WdfMemoryCreatePreallocated(
+ &Attributes,
+ Sequence,
+ SequenceLength,
+ &MemorySequence);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: WdfMemoryCreatePreallocated failed! Status:%#x\n",
+ __FUNCTION__,
+ Status);
+
+ goto SpbSequenceEnd;
+ }
+
+ WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&MemoryDescriptor, MemorySequence, NULL);
+
+ //
+ // Send the SPB sequence IOCTL.
+ //
+
+ Status = WdfIoTargetSendIoctlSynchronously(
+ GpioContext->SpbIoTarget,
+ NULL,
+ IOCTL_SPB_EXECUTE_SEQUENCE,
+ &MemoryDescriptor,
+ NULL,
+ NULL,
+ &BytesReturned);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceEvents(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPB,
+ "%s: Failed sending SPB sequence request! Bytes:%lu Status:%#x",
+ __FUNCTION__,
+ (ULONG)BytesReturned,
+ Status);
+
+ goto SpbSequenceEnd;
+ }
+
+SpbSequenceEnd:
+ return Status;
+}
+
+
diff --git a/gpio/samples/simgpio_i2c/trace.h b/gpio/samples/simgpio_i2c/trace.h
new file mode 100644
index 00000000..22969f69
--- /dev/null
+++ b/gpio/samples/simgpio_i2c/trace.h
@@ -0,0 +1,75 @@
+/*++
+
+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:
+
+ trace.h
+
+Abstract:
+
+ This sample implements a GPIO client driver for simulated GPIO (SimGpio)
+ controller.
+
+ Note: DIRQL in the comments below refers to device IRQL, which is any
+ IRQL > DISPATCH_LEVEL (and less than some IRQL reserved for OS use).
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _TRACE_H
+#define _TRACE_H
+
+#include <evntrace.h> // For TRACE_LEVEL definitions
+
+//
+// Define the tracing flags.
+//
+// Tracing GUID - e71e3b6e-aaf9-402c-97fe-7610cb3985db
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ SimGpioI2CTraceGuid, \
+ (e71e3b6e,aaf9,402c,97fe,7610cb3985db), \
+ WPP_DEFINE_BIT(TRACE_FLAG_INIT) \
+ WPP_DEFINE_BIT(TRACE_FLAG_SPB) \
+ WPP_DEFINE_BIT(TRACE_FLAG_REQUEST) \
+ WPP_DEFINE_BIT(TRACE_FLAG_INTERRUPT) \
+ WPP_DEFINE_BIT(TRACE_FLAG_IO) \
+ )
+
+#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)
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS);
+// FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS);
+// USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> entry");
+// USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <--");
+// end_wpp
+//
+
+#endif _TRACE_H \ No newline at end of file