summaryrefslogtreecommitdiff
path: root/general/echo/kmdf/driver
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 /general/echo/kmdf/driver
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/echo/kmdf/driver')
-rw-r--r--general/echo/kmdf/driver/AutoSync/device.c210
-rw-r--r--general/echo/kmdf/driver/AutoSync/device.h48
-rw-r--r--general/echo/kmdf/driver/AutoSync/driver.c202
-rw-r--r--general/echo/kmdf/driver/AutoSync/driver.h34
-rw-r--r--general/echo/kmdf/driver/AutoSync/echo.inx104
-rw-r--r--general/echo/kmdf/driver/AutoSync/echo.vcxproj168
-rw-r--r--general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters40
-rw-r--r--general/echo/kmdf/driver/AutoSync/queue.c532
-rw-r--r--general/echo/kmdf/driver/AutoSync/queue.h64
-rw-r--r--general/echo/kmdf/driver/DriverSync/device.c223
-rw-r--r--general/echo/kmdf/driver/DriverSync/device.h48
-rw-r--r--general/echo/kmdf/driver/DriverSync/driver.c201
-rw-r--r--general/echo/kmdf/driver/DriverSync/driver.h48
-rw-r--r--general/echo/kmdf/driver/DriverSync/echo_2.inx105
-rw-r--r--general/echo/kmdf/driver/DriverSync/echo_2.vcxproj180
-rw-r--r--general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters40
-rw-r--r--general/echo/kmdf/driver/DriverSync/queue.c816
-rw-r--r--general/echo/kmdf/driver/DriverSync/queue.h67
18 files changed, 3130 insertions, 0 deletions
diff --git a/general/echo/kmdf/driver/AutoSync/device.c b/general/echo/kmdf/driver/AutoSync/device.c
new file mode 100644
index 00000000..ee20447f
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/device.c
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "driver.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, EchoDeviceCreate)
+#pragma alloc_text (PAGE, EchoEvtDeviceSelfManagedIoSuspend)
+#endif
+
+
+NTSTATUS
+EchoDeviceCreate(
+ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+
+ //
+ // Register pnp/power callbacks so that we can start and stop the timer as the device
+ // gets started and stopped.
+ //
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart;
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend;
+
+ #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks")
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart;
+
+ //
+ // Register the PnP and power callbacks. Power policy related callbacks will be registered
+ // later in SotwareInit.
+ //
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an
+ // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the
+ // device.h header file. This function will do the type checking and return
+ // the device context. If you pass a wrong object handle
+ // it will return NULL and assert if run under framework verifier mode.
+ //
+ deviceContext = WdfObjectGet_DEVICE_CONTEXT(device);
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that application can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_ECHO,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = EchoQueueInitialize(device);
+ }
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+EchoEvtDeviceSelfManagedIoStart(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ This event is called by the Framework when the device is started
+ or restarted after a suspend operation.
+
+ 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 - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - Failures will result in the device stack being torn down.
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));
+ LARGE_INTEGER DueTime;
+
+ KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n"));
+
+ //
+ // Restart the queue and the periodic timer. We stopped them before going
+ // into low power state.
+ //
+ WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device));
+
+ DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100);
+
+ WdfTimerStart(queueContext->Timer, DueTime.QuadPart);
+
+ KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n"));
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+EchoEvtDeviceSelfManagedIoSuspend(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ This event is called by the Framework when the device is stopped
+ for resource rebalance or suspended when the system is entering
+ Sx state.
+
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - The driver is not allowed to fail this function. If it does, the
+ device stack will be torn down.
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));
+
+ PAGED_CODE();
+
+ KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n"));
+
+ //
+ // Before we stop the timer we should make sure there are no outstanding
+ // i/o. We need to do that because framework cannot suspend the device
+ // if there are requests owned by the driver. There are two ways to solve
+ // this issue: 1) We can wait for the outstanding I/O to be complete by the
+ // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge
+ // the request to inform the framework that it's okay to suspend the device
+ // with outstanding I/O. In this sample we will use the 1st approach
+ // because it's pretty easy to do. We will restart the queue when the
+ // device is restarted.
+ //
+ WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device));
+
+ //
+ // Stop the watchdog timer and wait for DPC to run to completion if it's already fired.
+ //
+ WdfTimerStop(queueContext->Timer, TRUE);
+
+ KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+
diff --git a/general/echo/kmdf/driver/AutoSync/device.h b/general/echo/kmdf/driver/AutoSync/device.h
new file mode 100644
index 00000000..f29c7908
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/device.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "public.h"
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT)
+
+//
+// Function to initialize the device and its callbacks
+//
+NTSTATUS
+EchoDeviceCreate(
+ PWDFDEVICE_INIT DeviceInit
+ );
+
+//
+// Device events
+//
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend;
+
diff --git a/general/echo/kmdf/driver/AutoSync/driver.c b/general/echo/kmdf/driver/AutoSync/driver.c
new file mode 100644
index 00000000..60a02692
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/driver.c
@@ -0,0 +1,202 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This driver demonstrates use of a default I/O Queue, its
+ request start events, cancellation event, and a synchronized DPC.
+
+ To demonstrate asynchronous operation, the I/O requests are not completed
+ immediately, but stored in the drivers private data structure, and a timer
+ DPC will complete it next time the DPC runs.
+
+ During the time the request is waiting for the DPC to run, it is
+ made cancellable by the call WdfRequestMarkCancelable. This
+ allows the test program to cancel the request and exit instantly.
+
+ This rather complicated set of events is designed to demonstrate
+ the driver frameworks synchronization of access to a device driver
+ data structure, and a pointer which can be a proxy for device hardware
+ registers or resources.
+
+ This common data structure, or resource is accessed by new request
+ events arriving, the DPC that completes it, and cancel processing.
+
+ Notice the lack of specific lock/unlock operations.
+
+ Even though this example utilizes a serial queue, a parallel queue
+ would not need any additional explicit synchronization, just a
+ strategy for managing multiple requests outstanding.
+
+--*/
+
+#include "driver.h"
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (INIT, EchoPrintDriverVersion)
+#pragma alloc_text (PAGE, EchoEvtDeviceAdd)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ EchoEvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ WDF_NO_HANDLE);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status));
+ return status;
+ }
+
+#if DBG
+ EchoPrintDriverVersion();
+#endif
+
+ return status;
+}
+
+NTSTATUS
+EchoEvtDeviceAdd(
+ IN WDFDRIVER Driver,
+ IN PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ KdPrint(("Enter EchoEvtDeviceAdd\n"));
+
+ status = EchoDeviceCreate(DeviceInit);
+
+ return status;
+}
+
+NTSTATUS
+EchoPrintDriverVersion(
+ )
+/*++
+Routine Description:
+
+ This routine shows how to retrieve framework version string and
+ also how to find out to which version of framework library the
+ client driver is bound to.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+ WDFSTRING string;
+ UNICODE_STRING us;
+ WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver;
+
+ //
+ // 1) Retreive version string and print that in the debugger.
+ //
+ status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error: WdfStringCreate failed 0x%x\n", status));
+ return status;
+ }
+
+ status = WdfDriverRetrieveVersionString(WdfGetDriver(), string);
+ if (!NT_SUCCESS(status)) {
+ //
+ // No need to worry about delete the string object because
+ // by default it's parented to the driver and it will be
+ // deleted when the driverobject is deleted when the DriverEntry
+ // returns a failure status.
+ //
+ KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status));
+ return status;
+ }
+
+ WdfStringGetUnicodeString(string, &us);
+ KdPrint(("Echo Sample %wZ\n", &us));
+
+ WdfObjectDelete(string);
+ string = NULL; // To avoid referencing a deleted object.
+
+ //
+ // 2) Find out to which version of framework this driver is bound to.
+ //
+ WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0);
+ if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) {
+ KdPrint(("Yes, framework version is 1.0\n"));
+ }else {
+ KdPrint(("No, framework verison is not 1.0\n"));
+ }
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/general/echo/kmdf/driver/AutoSync/driver.h b/general/echo/kmdf/driver/AutoSync/driver.h
new file mode 100644
index 00000000..9398ab30
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/driver.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#define INITGUID
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#include "device.h"
+#include "queue.h"
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd;
+
+NTSTATUS
+EchoPrintDriverVersion(
+ );
+
diff --git a/general/echo/kmdf/driver/AutoSync/echo.inx b/general/echo/kmdf/driver/AutoSync/echo.inx
new file mode 100644
index 00000000..fa0e4f6e
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/echo.inx
@@ -0,0 +1,104 @@
+;/*++
+;
+;Copyright (c) 1990-2000 Microsoft Corporation
+;
+;Module Name:
+; ECHO.INF
+;
+;Abstract:
+; INF file for installing the Driver Frameworks ECHO Driver
+;
+;Installation Notes:
+; Using Devcon: Type "devcon install ECHO.inf root\ECHO" to install
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Sample
+ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171}
+Provider=%MSFT%
+DriverVer=03/20/2003,5.00.3788
+CatalogFile=KmdfSamples.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+; ================= Class section =====================
+
+[ClassInstall32]
+Addreg=SampleClassReg
+
+[SampleClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+ECHO.sys = 1,,
+
+;*****************************************
+; ECHO Install Section
+;*****************************************
+
+[Manufacturer]
+%StdMfg%=Standard,NT$ARCH$
+
+[Standard.NT$ARCH$]
+%ECHO.DeviceDesc%=ECHO_Device, root\ECHO
+
+[ECHO_Device.NT]
+CopyFiles=Drivers_Dir
+
+[Drivers_Dir]
+ECHO.sys
+
+
+;-------------- Service installation
+[ECHO_Device.NT.Services]
+AddService = ECHO,%SPSVCINST_ASSOCSERVICE%, ECHO_Service_Inst
+
+; -------------- ECHO driver install sections
+[ECHO_Service_Inst]
+DisplayName = %ECHO.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\ECHO.sys
+
+;
+;--- ECHO_Device Coinstaller installation ------
+;
+
+[DestinationDirs]
+ECHO_Device_CoInstaller_CopyFiles = 11
+
+[ECHO_Device.NT.CoInstallers]
+AddReg=ECHO_Device_CoInstaller_AddReg
+CopyFiles=ECHO_Device_CoInstaller_CopyFiles
+
+[ECHO_Device_CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[ECHO_Device_CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[SourceDisksFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
+
+[ECHO_Device.NT.Wdf]
+KmdfService = ECHO, ECHO_wdfsect
+[ECHO_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+MSFT = "Microsoft"
+StdMfg = "(Standard system devices)"
+DiskId1 = "WDF Sample ECHO Installation Disk #1"
+ECHO.DeviceDesc = "Sample WDF ECHO Driver"
+ECHO.SVCDESC = "Sample WDF ECHO Service"
+ClassName = "Sample Device"
diff --git a/general/echo/kmdf/driver/AutoSync/echo.vcxproj b/general/echo/kmdf/driver/AutoSync/echo.vcxproj
new file mode 100644
index 00000000..fcaaf0ac
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj
@@ -0,0 +1,168 @@
+<?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>{C8F9A776-3675-459B-A0A3-BA17D003C70B}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{8063717F-2826-44B9-BCF2-23ACCAF2C1FA}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <Inf Include=".\echo.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\echo.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>echo</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>echo</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>echo</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>echo</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c" />
+ <ClCompile Include="driver.c" />
+ <ClCompile Include="queue.c" />
+ </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/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters
new file mode 100644
index 00000000..ba649423
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?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>{C301082A-56B5-43D9-AF50-C90CDBB830DA}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{E8E22922-FDB4-496F-9D8B-0E5930795BAC}</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>{78CA938F-ABD5-4BA1-A021-7E751E09B367}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A5E77DC1-258D-4E61-AA8D-1879410AE785}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\echo.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\echo.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="queue.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/echo/kmdf/driver/AutoSync/queue.c b/general/echo/kmdf/driver/AutoSync/queue.c
new file mode 100644
index 00000000..cb02a965
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/queue.c
@@ -0,0 +1,532 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "driver.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, EchoQueueInitialize)
+#pragma alloc_text (PAGE, EchoTimerCreate)
+#endif
+
+NTSTATUS
+EchoQueueInitialize(
+ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for serial request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+ This memory may be used by the driver automatically synchronized
+ by the Queue's presentation lock.
+
+ The lifetime of this memory is tied to the lifetime of the I/O
+ Queue object, and we register an optional destructor callback
+ to release any private allocations, and/or resources.
+
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+ WDF_OBJECT_ATTRIBUTES queueAttributes;
+
+ PAGED_CODE();
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchSequential
+ );
+
+ queueConfig.EvtIoRead = EchoEvtIoRead;
+ queueConfig.EvtIoWrite = EchoEvtIoWrite;
+
+ //
+ // Fill in a callback for destroy, and our QUEUE_CONTEXT size
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT);
+
+ //
+ // Set synchronization scope on queue and have the timer to use queue as
+ // the parent object so that queue and timer callbacks are synchronized
+ // with the same lock.
+ //
+ queueAttributes.SynchronizationScope = WdfSynchronizationScopeQueue;
+
+ queueAttributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ &queueAttributes,
+ &queue
+ );
+
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("WdfIoQueueCreate failed 0x%x\n",status));
+ return status;
+ }
+
+ // Get our Driver Context memory from the returned Queue handle
+ queueContext = QueueGetContext(queue);
+
+ queueContext->Buffer = NULL;
+ queueContext->Timer = NULL;
+
+ queueContext->CurrentRequest = NULL;
+ queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Create the Queue timer
+ //
+ status = EchoTimerCreate(&queueContext->Timer, TIMER_PERIOD, queue);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error creating timer 0x%x\n",status));
+ return status;
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+EchoTimerCreate(
+ IN WDFTIMER* Timer,
+ IN ULONG Period,
+ IN WDFQUEUE Queue
+ )
+/*++
+
+Routine Description:
+
+ Subroutine to create periodic timer. By associating the timerobject with
+ the queue, we are basically telling the framework to serialize the queue
+ callbacks with the dpc callback. By doing so, we don't have to worry
+ about protecting queue-context structure from multiple threads accessing
+ it simultaneously.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS Status;
+ WDF_TIMER_CONFIG timerConfig;
+ WDF_OBJECT_ATTRIBUTES timerAttributes;
+
+ PAGED_CODE();
+
+ //
+ // Create a WDFTIMER object
+ //
+ WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, EchoEvtTimerFunc, Period);
+
+ timerConfig.AutomaticSerialization = FALSE;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+ timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue
+
+ Status = WdfTimerCreate(&timerConfig,
+ &timerAttributes,
+ Timer // Output handle
+ );
+
+ return Status;
+}
+
+
+
+VOID
+EchoEvtIoQueueContextDestroy(
+ WDFOBJECT Object
+)
+/*++
+
+Routine Description:
+
+ This is called when the Queue that our driver context memory
+ is associated with is destroyed.
+
+Arguments:
+
+ Context - Context that's being freed.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Object);
+
+ //
+ // Release any resources pointed to in the queue context.
+ //
+ // The body of the queue context will be released after
+ // this callback handler returns
+ //
+
+ //
+ // If Queue context has an I/O buffer, release it
+ //
+ if( queueContext->Buffer != NULL ) {
+ ExFreePool(queueContext->Buffer);
+ }
+
+ return;
+}
+
+
+VOID
+EchoEvtRequestCancel(
+ IN WDFREQUEST Request
+ )
+/*++
+
+Routine Description:
+
+
+ Called when an I/O request is cancelled after the driver has marked
+ the request cancellable. This callback is automatically synchronized
+ with the I/O callbacks since we have chosen to use frameworks Device
+ level locking.
+
+Arguments:
+
+ Request - Request being cancelled.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(WdfRequestGetIoQueue(Request));
+
+ KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request));
+
+ //
+ // The following is race free by the callside or DPC side
+ // synchronizing completion by calling
+ // WdfRequestMarkCancelable(Queue, Request, FALSE) before
+ // completion and not calling WdfRequestComplete if the
+ // return status == STATUS_CANCELLED.
+ //
+ WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L);
+
+ //
+ // This book keeping is synchronized by the common
+ // Queue presentation lock
+ //
+ ASSERT(queueContext->CurrentRequest == Request);
+ queueContext->CurrentRequest = NULL;
+
+ return;
+}
+
+VOID
+EchoEvtIoRead(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_READ request.
+ It will copy the content from the queue-context buffer to the request buffer.
+ If the driver hasn't received any write request earlier, the read returns zero.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ Length - number of bytes to be read.
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status;
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
+ WDFMEMORY memory;
+
+ _Analysis_assume_(Length > 0);
+
+ KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n",
+ Queue,Request,Length));
+ //
+ // No data to read
+ //
+ if( (queueContext->Buffer == NULL) ) {
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);
+ return;
+ }
+ _Analysis_assume_(queueContext->Length > 0);
+
+ //
+ // Read what we have
+ //
+ if( queueContext->Length < Length ) {
+ Length = queueContext->Length;
+ }
+
+ //
+ // Get the request memory
+ //
+ Status = WdfRequestRetrieveOutputMemory(Request, &memory);
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status));
+ WdfVerifierDbgBreakPoint();
+ WdfRequestCompleteWithInformation(Request, Status, 0L);
+ return;
+ }
+
+ // Copy the memory out
+ Status = WdfMemoryCopyFromBuffer( memory, // destination
+ 0, // offset into the destination memory
+ queueContext->Buffer,
+ Length );
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status));
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ // Set transfer information
+ WdfRequestSetInformation(Request, (ULONG_PTR)Length);
+
+ // Mark the request is cancelable
+ WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);
+
+
+ // Defer the completion to another thread from the timer dpc
+ queueContext->CurrentRequest = Request;
+ queueContext->CurrentStatus = Status;
+
+ return;
+}
+
+VOID
+EchoEvtIoWrite(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_WRITE request.
+ This routine allocates memory buffer, copies the data from the request to it,
+ and stores the buffer pointer in the queue-context with the length variable
+ representing the buffers length. The actual completion of the request
+ is defered to the periodic timer dpc.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ Length - number of bytes to be read.
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status;
+ WDFMEMORY memory;
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
+
+ _Analysis_assume_(Length > 0);
+
+ KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n",
+ Queue,Request,Length));
+
+ if( Length > MAX_WRITE_LENGTH ) {
+ KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n",
+ Length,MAX_WRITE_LENGTH));
+ WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L);
+ return;
+ }
+
+ // Get the memory buffer
+ Status = WdfRequestRetrieveInputMemory(Request, &memory);
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n",
+ Status));
+ WdfVerifierDbgBreakPoint();
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ // Release previous buffer if set
+ if( queueContext->Buffer != NULL ) {
+ ExFreePool(queueContext->Buffer);
+ queueContext->Buffer = NULL;
+ queueContext->Length = 0L;
+ }
+
+ queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1');
+ if( queueContext->Buffer == NULL ) {
+ KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length));
+ WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
+ return;
+ }
+
+
+ // Copy the memory in
+ Status = WdfMemoryCopyToBuffer( memory,
+ 0, // offset into the source memory
+ queueContext->Buffer,
+ Length );
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status));
+ WdfVerifierDbgBreakPoint();
+
+ ExFreePool(queueContext->Buffer);
+ queueContext->Buffer = NULL;
+ queueContext->Length = 0L;
+
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+
+ queueContext->Length = (ULONG) Length;
+
+ // Set transfer information
+ WdfRequestSetInformation(Request, (ULONG_PTR)Length);
+
+ // Specify the request is cancelable
+ WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);
+
+ // Defer the completion to another thread from the timer dpc
+ queueContext->CurrentRequest = Request;
+ queueContext->CurrentStatus = Status;
+
+ return;
+}
+
+
+VOID
+EchoEvtTimerFunc(
+ IN WDFTIMER Timer
+ )
+/*++
+
+Routine Description:
+
+ This is the TimerDPC the driver sets up to complete requests.
+ This function is registered when the WDFTIMER object is created, and
+ will automatically synchronize with the I/O Queue callbacks
+ and cancel routine.
+
+Arguments:
+
+ Timer - Handle to a framework Timer object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status;
+ WDFREQUEST Request;
+ WDFQUEUE queue;
+ PQUEUE_CONTEXT queueContext ;
+
+ queue = WdfTimerGetParentObject(Timer);
+ queueContext = QueueGetContext(queue);
+
+ //
+ // DPC is automatically synchronized to the Queue lock,
+ // so this is race free without explicit driver managed locking.
+ //
+ Request = queueContext->CurrentRequest;
+ if( Request != NULL ) {
+
+ //
+ // Attempt to remove cancel status from the request.
+ //
+ // The request is not completed if it is already cancelled
+ // since the EchoEvtIoCancel function has run, or is about to run
+ // and we are racing with it.
+ //
+ Status = WdfRequestUnmarkCancelable(Request);
+ if( Status != STATUS_CANCELLED ) {
+
+ queueContext->CurrentRequest = NULL;
+ Status = queueContext->CurrentStatus;
+
+ KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status));
+
+ WdfRequestComplete(Request, Status);
+ }
+ else {
+ KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n",
+ Request));
+ }
+ }
+
+ return;
+}
+
+
diff --git a/general/echo/kmdf/driver/AutoSync/queue.h b/general/echo/kmdf/driver/AutoSync/queue.h
new file mode 100644
index 00000000..a20e0375
--- /dev/null
+++ b/general/echo/kmdf/driver/AutoSync/queue.h
@@ -0,0 +1,64 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+// Set max write length for testing
+#define MAX_WRITE_LENGTH 1024*40
+
+// Set timer period in ms
+#define TIMER_PERIOD 1000*2
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ // Here we allocate a buffer from a test write so it can be read back
+ PVOID Buffer;
+ ULONG Length;
+
+ // Timer DPC for this queue
+ WDFTIMER Timer;
+
+ // Virtual I/O
+ WDFREQUEST CurrentRequest;
+ NTSTATUS CurrentStatus;
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+EchoQueueInitialize(
+ WDFDEVICE hDevice
+ );
+
+EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy;
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel;
+EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead;
+EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite;
+
+NTSTATUS
+EchoTimerCreate(
+ IN WDFTIMER* pTimer,
+ IN ULONG Period,
+ IN WDFQUEUE Queue
+ );
+
+EVT_WDF_TIMER EchoEvtTimerFunc;
diff --git a/general/echo/kmdf/driver/DriverSync/device.c b/general/echo/kmdf/driver/DriverSync/device.c
new file mode 100644
index 00000000..eb37eaf2
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/device.c
@@ -0,0 +1,223 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "driver.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, EchoDeviceCreate)
+#pragma alloc_text (PAGE, EchoEvtDeviceSelfManagedIoSuspend)
+#endif
+
+
+NTSTATUS
+EchoDeviceCreate(
+ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_OBJECT_ATTRIBUTES attributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+
+ //
+ // Register pnp/power callbacks so that we can start and stop the timer as the device
+ // gets started and stopped.
+ //
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart;
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend;
+ #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks")
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart;
+
+ //
+ // Register the PnP and power callbacks. Power policy related callbacks will be registered
+ // later in SotwareInit.
+ //
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);
+ WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);
+
+ //
+ // By not setting the synchronization scope and using the default, there is
+ // no locking between any of the callbacks in this driver.
+ //
+ // We will create a sequential queue so all of the EvtIoXxx callbacks are
+ // serialized against each other (at least until the request is completed),
+ // but the cancel routine and the timer DPC are not synchronized against the
+ // queue's EvtIoXxx callbacks.
+ //
+ // attributes.SynchronizationScope = ...
+
+ status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an
+ // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the
+ // device.h header file. This function will do the type checking and return
+ // the device context. If you pass a wrong object handle
+ // it will return NULL and assert if run under framework verifier mode.
+ //
+ deviceContext = WdfObjectGet_DEVICE_CONTEXT(device);
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that application can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_ECHO,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = EchoQueueInitialize(device);
+ }
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+EchoEvtDeviceSelfManagedIoStart(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ This event is called by the Framework when the device is started
+ or restarted after a suspend operation.
+
+ 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 - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - Failures will result in the device stack being torn down.
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));
+ LARGE_INTEGER DueTime;
+
+ KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n"));
+
+ //
+ // Restart the queue and the periodic timer. We stopped them before going
+ // into low power state.
+ //
+ WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device));
+
+ DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100);
+
+ WdfTimerStart(queueContext->Timer, DueTime.QuadPart);
+
+ KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n"));
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+EchoEvtDeviceSelfManagedIoSuspend(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ This event is called by the Framework when the device is stopped
+ for resource rebalance or suspended when the system is entering
+ Sx state.
+
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - The driver is not allowed to fail this function. If it does, the
+ device stack will be torn down.
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));
+
+ PAGED_CODE();
+
+ KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n"));
+
+ //
+ // Before we stop the timer we should make sure there are no outstanding
+ // i/o. We need to do that because framework cannot suspend the device
+ // if there are requests owned by the driver. There are two ways to solve
+ // this issue: 1) We can wait for the outstanding I/O to be complete by the
+ // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge
+ // the request to inform the framework that it's okay to suspend the device
+ // with outstanding I/O. In this sample we will use the 1st approach
+ // because it's pretty easy to do. We will restart the queue when the
+ // device is restarted.
+ //
+ WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device));
+
+ //
+ // Stop the watchdog timer and wait for DPC to run to completion if it's already fired.
+ //
+ WdfTimerStop(queueContext->Timer, TRUE);
+
+ KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+
diff --git a/general/echo/kmdf/driver/DriverSync/device.h b/general/echo/kmdf/driver/DriverSync/device.h
new file mode 100644
index 00000000..f29c7908
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/device.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "public.h"
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT)
+
+//
+// Function to initialize the device and its callbacks
+//
+NTSTATUS
+EchoDeviceCreate(
+ PWDFDEVICE_INIT DeviceInit
+ );
+
+//
+// Device events
+//
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend;
+
diff --git a/general/echo/kmdf/driver/DriverSync/driver.c b/general/echo/kmdf/driver/DriverSync/driver.c
new file mode 100644
index 00000000..f1e216f2
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/driver.c
@@ -0,0 +1,201 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This driver demonstrates use of a default I/O Queue, its
+ request start events, cancellation event, and a synchronized DPC.
+
+ To demonstrate asynchronous operation, the I/O requests are not completed
+ immediately, but stored in the drivers private data structure, and a timer
+ DPC will complete it next time the DPC runs.
+
+ During the time the request is waiting for the DPC to run, it is
+ made cancellable by the call WdfRequestMarkCancelable. This
+ allows the test program to cancel the request and exit instantly.
+
+ This rather complicated set of events is designed to demonstrate
+ the driver frameworks synchronization of access to a device driver
+ data structure, and a pointer which can be a proxy for device hardware
+ registers or resources.
+
+ This common data structure, or resource is accessed by new request
+ events arriving, the DPC that completes it, and cancel processing.
+
+ Notice the lack of specific lock/unlock operations.
+
+ Even though this example utilizes a serial queue, a parallel queue
+ would not need any additional explicit synchronization, just a
+ strategy for managing multiple requests outstanding.
+
+--*/
+
+#include "driver.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (INIT, EchoPrintDriverVersion)
+#pragma alloc_text (PAGE, EchoEvtDeviceAdd)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ EchoEvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ WDF_NO_HANDLE);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status));
+ return status;
+ }
+
+#if DBG
+ EchoPrintDriverVersion();
+#endif
+
+ return status;
+}
+
+NTSTATUS
+EchoEvtDeviceAdd(
+ IN WDFDRIVER Driver,
+ IN PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ KdPrint(("Enter EchoEvtDeviceAdd\n"));
+
+ status = EchoDeviceCreate(DeviceInit);
+
+ return status;
+}
+
+NTSTATUS
+EchoPrintDriverVersion(
+ )
+/*++
+Routine Description:
+
+ This routine shows how to retrieve framework version string and
+ also how to find out to which version of framework library the
+ client driver is bound to.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+ WDFSTRING string;
+ UNICODE_STRING us;
+ WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver;
+
+ //
+ // 1) Retreive version string and print that in the debugger.
+ //
+ status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error: WdfStringCreate failed 0x%x\n", status));
+ return status;
+ }
+
+ status = WdfDriverRetrieveVersionString(WdfGetDriver(), string);
+ if (!NT_SUCCESS(status)) {
+ //
+ // No need to worry about delete the string object because
+ // by default it's parented to the driver and it will be
+ // deleted when the driverobject is deleted when the DriverEntry
+ // returns a failure status.
+ //
+ KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status));
+ return status;
+ }
+
+ WdfStringGetUnicodeString(string, &us);
+ KdPrint(("Echo Sample %wZ\n", &us));
+
+ WdfObjectDelete(string);
+ string = NULL; // To avoid referencing a deleted object.
+
+ //
+ // 2) Find out to which version of framework this driver is bound to.
+ //
+ WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0);
+ if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) {
+ KdPrint(("Yes, framework version is 1.0\n"));
+ }else {
+ KdPrint(("No, framework verison is not 1.0\n"));
+ }
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/general/echo/kmdf/driver/DriverSync/driver.h b/general/echo/kmdf/driver/DriverSync/driver.h
new file mode 100644
index 00000000..5bf8853f
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/driver.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#define INITGUID
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#include "device.h"
+#include "queue.h"
+
+typedef struct _REQUEST_CONTEXT {
+ //
+ // Count to use when trying to claim completion ownership of a cancelable
+ // request when clearing the cancel routine. If the caller can clear the
+ // cancel routine successfully, the caller is *NOT* responsible for decrementing
+ // the count if the request is going to be completed immediately (and a
+ // cancel routine is not going to be set in the future).
+ //
+ LONG CancelCompletionOwnershipCount;
+
+} REQUEST_CONTEXT, *PREQUEST_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, RequestGetContext);
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd;
+
+NTSTATUS
+EchoPrintDriverVersion(
+ );
+
diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.inx b/general/echo/kmdf/driver/DriverSync/echo_2.inx
new file mode 100644
index 00000000..af09757f
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/echo_2.inx
@@ -0,0 +1,105 @@
+;/*++
+;
+;Copyright (c) 1990-2000 Microsoft Corporation
+;
+;Module Name:
+; ECHO_2.INF
+;
+;Abstract:
+; INF file for installing the Driver Frameworks ECHO Driver (DriverSync version)
+;
+;Installation Notes:
+; Using Devcon: Type "devcon install ECHO_2.inf root\ECHO_2" to install
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Sample
+ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171}
+Provider=%MSFT%
+DriverVer=03/20/2003,5.00.3788
+CatalogFile=KmdfSamples.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+; ================= Class section =====================
+
+[ClassInstall32]
+Addreg=SampleClassReg
+
+[SampleClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+ECHO_2.sys = 1,,
+
+;*****************************************
+; ECHO Install Section
+;*****************************************
+
+[Manufacturer]
+%StdMfg%=Standard,NT$ARCH$
+
+[Standard.NT$ARCH$]
+%ECHO.DeviceDesc%=ECHO_Device, root\ECHO_2
+
+[ECHO_Device.NT]
+CopyFiles=Drivers_Dir
+
+[Drivers_Dir]
+ECHO_2.sys
+
+
+;-------------- Service installation
+[ECHO_Device.NT.Services]
+AddService = ECHO_2,%SPSVCINST_ASSOCSERVICE%, ECHO_Service_Inst
+
+; -------------- ECHO driver install sections
+[ECHO_Service_Inst]
+DisplayName = %ECHO.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\ECHO_2.sys
+
+;
+;--- ECHO_Device Coinstaller installation ------
+;
+
+[DestinationDirs]
+ECHO_Device_CoInstaller_CopyFiles = 11
+
+[ECHO_Device.NT.CoInstallers]
+AddReg=ECHO_Device_CoInstaller_AddReg
+CopyFiles=ECHO_Device_CoInstaller_CopyFiles
+
+[ECHO_Device_CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[ECHO_Device_CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[SourceDisksFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
+
+[ECHO_Device.NT.Wdf]
+KmdfService = ECHO_2, ECHO_wdfsect
+
+[ECHO_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+MSFT = "Microsoft"
+StdMfg = "(Standard system devices)"
+DiskId1 = "WDF Sample ECHO Installation Disk #1 (DriverSync)"
+ECHO.DeviceDesc = "Sample WDF ECHO Driver (DriverSync)"
+ECHO.SVCDESC = "Sample WDF ECHO Service (DriverSync)"
+ClassName = "Sample Device"
diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj
new file mode 100644
index 00000000..a96b9b73
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj
@@ -0,0 +1,180 @@
+<?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>{968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{0F2B6094-D739-411B-B15C-D0ABD3ACF20E}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <Inf Include=".\echo_2.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\echo_2.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>echo_2</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>echo_2</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>echo_2</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>echo_2</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c" />
+ <ClCompile Include="driver.c" />
+ <ClCompile Include="queue.c" />
+ </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/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters
new file mode 100644
index 00000000..2fac5833
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?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>{5AF6C435-D6C0-4812-A1B9-A231D60FF6A3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{52F80479-DCAD-49B9-9A2F-BB7363EEEBAF}</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>{1EC49F54-AC4E-447D-B4EA-B9859C16E917}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{9CFF80B0-15ED-408B-B629-91208E5966C3}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\echo_2.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\echo_2.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="queue.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/echo/kmdf/driver/DriverSync/queue.c b/general/echo/kmdf/driver/DriverSync/queue.c
new file mode 100644
index 00000000..89d47fa2
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/queue.c
@@ -0,0 +1,816 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+#include "driver.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, EchoQueueInitialize)
+#pragma alloc_text (PAGE, EchoTimerCreate)
+#endif
+
+LONG
+EchoInterlockedIncrementFloor(
+ LONG volatile *Target,
+ LONG Floor
+ )
+/*++
+
+Routine Description:
+ This routine will interlock increment a value only if the current value
+ is greater then the floor value.
+
+ The volatile keyword on the Target pointer is absolutely required, otherwise
+ the compiler might rearrange pointer dereferences and that cannot happen.
+
+Arguments:
+ Target - the value that will be pontetially incrmented
+
+ Floor - the value in which the Target value must be greater then if it is
+ to be incremented
+
+Return Value:
+ The current value of Target. To detect failure, the return value will be
+ <= Floor + 1. It is +1 because we cannot increment from the Floor value
+ itself, so Floor+1 cannot be a successful return value.
+
+ --*/
+{
+ LONG oldValue, currentValue;
+
+ currentValue = *Target;
+
+ do {
+ if (currentValue <= Floor) {
+ return currentValue;
+ }
+
+ oldValue = currentValue;
+
+ //
+ // currentValue will be the value that used to be Target if the exchange
+ // was made or its current value if the exchange was not made.
+ //
+ currentValue = InterlockedCompareExchange(Target, oldValue + 1, oldValue);
+
+ //
+ // If oldValue == currentValue, then no one updated Target in between
+ // the deref at the top and the InterlockecCompareExchange afterward
+ // and we have successfully incremented the value and can exit the loop.
+ //
+ } while (oldValue != currentValue);
+
+ //
+ // Since InterlockedIncrement returns the new incremented value of Target,
+ // we should do the same here.
+ //
+ return oldValue + 1;
+}
+
+FORCEINLINE
+LONG
+EchoInterlockedIncrementGTZero(
+ IN OUT LONG volatile *Target
+ )
+/*++
+
+Routine Description:
+ Increment the value only if it is currently > 0.
+
+Arguments:
+ Target - the value to be incremented. NOTE: the volatile keyword is requreid
+
+Return Value:
+ Upon success, a value > 0. Upon failure, a value <= 0.
+
+ --*/
+{
+ return EchoInterlockedIncrementFloor(Target, 0);
+}
+
+NTSTATUS
+EchoQueueInitialize(
+ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for serial request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+ This memory may be used by the driver automatically synchronized
+ by the Queue's presentation lock.
+
+ The lifetime of this memory is tied to the lifetime of the I/O
+ Queue object, and we register an optional destructor callback
+ to release any private allocations, and/or resources.
+
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ PAGED_CODE();
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchSequential
+ );
+
+ queueConfig.EvtIoRead = EchoEvtIoRead;
+ queueConfig.EvtIoWrite = EchoEvtIoWrite;
+
+ //
+ // Fill in a callback for destroy, and our QUEUE_CONTEXT size
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, QUEUE_CONTEXT);
+ attributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ &attributes,
+ &queue
+ );
+
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("WdfIoQueueCreate failed 0x%x\n",status));
+ return status;
+ }
+
+ // Get our Driver Context memory from the returned Queue handle
+ queueContext = QueueGetContext(queue);
+
+ queueContext->Buffer = NULL;
+ queueContext->Timer = NULL;
+
+ queueContext->CurrentRequest = NULL;
+ queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Create the SpinLock.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = queue;
+
+ status = WdfSpinLockCreate(&attributes, &queueContext->SpinLock);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfSpinLockCreate failed 0x%x\n",status));
+ return status;
+ }
+
+ //
+ // Create the Queue timer
+ //
+ status = EchoTimerCreate(&queueContext->Timer, TIMER_PERIOD, queue);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error creating timer 0x%x\n",status));
+ return status;
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+EchoTimerCreate(
+ IN WDFTIMER* Timer,
+ IN ULONG Period,
+ IN WDFQUEUE Queue
+ )
+/*++
+
+Routine Description:
+
+ Subroutine to create periodic timer.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS Status;
+ WDF_TIMER_CONFIG timerConfig;
+ WDF_OBJECT_ATTRIBUTES timerAttributes;
+
+ PAGED_CODE();
+
+ //
+ // Create a WDFTIMER object
+ //
+ WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, EchoEvtTimerFunc, Period);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+
+ //
+ // We are explicitly *not* serializing against the queue's lock, we will do
+ // that on our own.
+ //
+ timerAttributes.ParentObject = Queue;
+
+ Status = WdfTimerCreate(
+ &timerConfig,
+ &timerAttributes,
+ Timer // Output handle
+ );
+
+ return Status;
+}
+
+
+
+VOID
+EchoEvtIoQueueContextDestroy(
+ WDFOBJECT Object
+)
+/*++
+
+Routine Description:
+
+ This is called when the Queue that our driver context memory
+ is associated with is destroyed.
+
+Arguments:
+
+ Context - Context that's being freed.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Object);
+
+ //
+ // Release any resources pointed to in the queue context.
+ //
+ // The body of the queue context will be released after
+ // this callback handler returns
+ //
+
+ //
+ // If Queue context has an I/O buffer, release it
+ //
+ if( queueContext->Buffer != NULL ) {
+ ExFreePool(queueContext->Buffer);
+ queueContext->Buffer = NULL;
+ }
+
+ return;
+}
+
+BOOLEAN
+EchoDecrementRequestCancelOwnershipCount(
+ PREQUEST_CONTEXT RequestContext
+ )
+/*++
+
+Routine Description:
+ Decrements the cancel ownership count for the request. When the count
+ reaches zero ownership has been acquired.
+
+Arguments:
+ RequestContext - the context which holds the count
+
+Return Value:
+ TRUE if the caller can complete the request, FALSE otherwise
+
+ --*/
+{
+ LONG result;
+
+ result = InterlockedDecrement(
+ &RequestContext->CancelCompletionOwnershipCount
+ );
+
+ ASSERT(result >= 0);
+
+ if (result == 0) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+BOOLEAN
+EchoIncrementRequestCancelOwnershipCount(
+ PREQUEST_CONTEXT RequestContext
+ )
+/*++
+
+Routine Description:
+ Attempts to increment the request ownership count so that it cannot be
+ completed until the count has been decremented
+
+Arguments:
+ RequestContext - context which holds the count
+
+Return Value:
+ TRUE if the count was incremented, FALSE otherwise
+
+ --*/
+{
+ //
+ // See comments in EchoInterlockedIncrementFloor as to why <= 1 is failure
+ //
+ if (EchoInterlockedIncrementGTZero(
+ &RequestContext->CancelCompletionOwnershipCount
+ ) <= 1) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+VOID
+EchoEvtRequestCancel(
+ IN WDFREQUEST Request
+ )
+/*++
+
+Routine Description:
+
+
+ Called when an I/O request is cancelled after the driver has marked
+ the request cancellable. This callback is not automatically synchronized
+ with the I/O callbacks since we have chosen not to use frameworks Device
+ or Queue level locking.
+
+Arguments:
+
+ Request - Request being cancelled.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PQUEUE_CONTEXT queueContext;
+ PREQUEST_CONTEXT requestContext;
+ WDFQUEUE queue;
+ BOOLEAN completeRequest;
+
+ KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request));
+
+ queue = WdfRequestGetIoQueue(Request);
+
+ requestContext = RequestGetContext(Request);
+ queueContext = QueueGetContext(queue);
+
+ //
+ // This book keeping is synchronized by the common
+ // Queue presentation lock which we are now acquiring
+ //
+ WdfSpinLockAcquire(queueContext->SpinLock);
+
+ completeRequest = EchoDecrementRequestCancelOwnershipCount(requestContext);
+
+ if (completeRequest) {
+ ASSERT(queueContext->CurrentRequest == Request);
+ queueContext->CurrentRequest = NULL;
+ }
+ else {
+ queueContext->CurrentStatus = STATUS_CANCELLED;
+ }
+
+ WdfSpinLockRelease(queueContext->SpinLock);
+
+ //
+ // Complete the request outside of holding any locks
+ //
+ if (completeRequest) {
+ WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L);
+ }
+
+ return;
+}
+
+VOID
+EchoSetCurrentRequest(
+ WDFREQUEST Request,
+ WDFQUEUE Queue
+ )
+{
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext;
+ PREQUEST_CONTEXT requestContext;
+
+ requestContext = RequestGetContext(Request);
+ queueContext = QueueGetContext(Queue);
+
+ //
+ // Set the ownership count to one. When a caller wants to claim ownership,
+ // they will interlock decrement the count. When the count reaches zero,
+ // ownership has been acquired and the caller may complete the request.
+ //
+ requestContext->CancelCompletionOwnershipCount = 1;
+
+ //
+ // Defer the completion to another thread from the timer dpc
+ //
+ WdfSpinLockAcquire(queueContext->SpinLock);
+
+ queueContext->CurrentRequest = Request;
+ queueContext->CurrentStatus = STATUS_SUCCESS;
+
+ //
+ // Set the cancel routine under the lock, otherwise if we set it outside
+ // of the lock, the timer could run and attempt to mark the request
+ // uncancelable before we can mark it cancelable on this thread. Use
+ // WdfRequestMarkCancelableEx here to prevent to deadlock with ourselves
+ // (cancel routine tries to acquire the queue object lock).
+ //
+ status = WdfRequestMarkCancelableEx(Request, EchoEvtRequestCancel);
+ if (!NT_SUCCESS(status)) {
+ queueContext->CurrentRequest = NULL;
+ }
+
+ WdfSpinLockRelease(queueContext->SpinLock);
+
+ //
+ // Complete the request with an error when unable to mark it cancelable.
+ //
+ if (!NT_SUCCESS(status)) {
+ WdfRequestCompleteWithInformation(Request, status, 0L);
+ }
+}
+
+VOID
+EchoEvtIoRead(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_READ request.
+ It will copy the content from the queue-context buffer to the request buffer.
+ If the driver hasn't received any write request earlier, the read returns zero.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+ Request - Handle to a framework request object.
+
+ Length - number of bytes to be read.
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status;
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
+ WDFMEMORY memory;
+
+ _Analysis_assume_(Length > 0);
+
+ KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n",
+ Queue,Request,Length));
+ //
+ // No data to read
+ //
+ if( (queueContext->Buffer == NULL) ) {
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);
+ return;
+ }
+
+ _Analysis_assume_(queueContext->Length > 0);
+
+ //
+ // Read what we have
+ //
+ if( queueContext->Length < Length ) {
+ Length = queueContext->Length;
+ }
+
+ //
+ // Get the request memory
+ //
+ Status = WdfRequestRetrieveOutputMemory(Request, &memory);
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n",Status));
+ WdfVerifierDbgBreakPoint();
+ WdfRequestCompleteWithInformation(Request, Status, 0L);
+ return;
+ }
+
+ // Copy the memory out
+ Status = WdfMemoryCopyFromBuffer( memory, // destination
+ 0, // offset into the destination memory
+ queueContext->Buffer,
+ Length );
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status));
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ // Set transfer information
+ WdfRequestSetInformation(Request, (ULONG_PTR)Length);
+
+ //
+ // Mark the request is cancelable. This must be the last thing we do because
+ // the cancel routine can run immediately after we set it. This means that
+ // CurrentRequest and CurrentStatus must be initialized before we mark the
+ // request cancelable.
+ //
+ EchoSetCurrentRequest(Request, Queue);
+
+ return;
+}
+
+VOID
+EchoEvtIoWrite(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_WRITE request.
+ This routine allocates memory buffer, copies the data from the request to it,
+ and stores the buffer pointer in the queue-context with the length variable
+ representing the buffers length. The actual completion of the request
+ is defered to the periodic timer dpc.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+ Request - Handle to a framework request object.
+
+ Length - number of bytes to be read.
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS Status;
+ WDFMEMORY memory;
+ PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
+
+ _Analysis_assume_(Length > 0);
+
+ KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n",
+ Queue,Request,Length));
+
+ if( Length > MAX_WRITE_LENGTH ) {
+ KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n",
+ Length,MAX_WRITE_LENGTH));
+ WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L);
+ return;
+ }
+
+ // Get the memory buffer
+ Status = WdfRequestRetrieveInputMemory(Request, &memory);
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n",
+ Status));
+ WdfVerifierDbgBreakPoint();
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ // Release previous buffer if set
+ if( queueContext->Buffer != NULL ) {
+ ExFreePool(queueContext->Buffer);
+ queueContext->Buffer = NULL;
+ queueContext->Length = 0L;
+ }
+
+ queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1');
+ if( queueContext->Buffer == NULL ) {
+ KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n",Length));
+ WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
+ return;
+ }
+
+
+ // Copy the memory in
+ Status = WdfMemoryCopyToBuffer( memory,
+ 0, // offset into the source memory
+ queueContext->Buffer,
+ Length );
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status));
+ WdfVerifierDbgBreakPoint();
+ ExFreePool(queueContext->Buffer);
+ queueContext->Buffer = NULL;
+ queueContext->Length = 0L;
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ queueContext->Length = (ULONG) Length;
+
+ // Set transfer information
+ WdfRequestSetInformation(Request, (ULONG_PTR)Length);
+
+
+ //
+ // Mark the request is cancelable. This must be the last thing we do because
+ // the cancel routine can run immediately after we set it. This means that
+ // CurrentRequest and CurrentStatus must be initialized before we mark the
+ // request cancelable.
+ //
+ EchoSetCurrentRequest(Request, Queue);
+
+ return;
+}
+
+
+VOID
+EchoEvtTimerFunc(
+ IN WDFTIMER Timer
+ )
+/*++
+
+Routine Description:
+
+ This is the TimerDPC the driver sets up to complete requests.
+ This function is registered when the WDFTIMER object is created.
+
+ This function does *NOT* automatically synchronize with the I/O Queue
+ callbacks and cancel routine, we must do it ourself in the routine.
+
+Arguments:
+
+ Timer - Handle to a framework Timer object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS status;
+ WDFREQUEST request;
+ WDFQUEUE queue;
+ PQUEUE_CONTEXT queueContext;
+ PREQUEST_CONTEXT requestContext;
+ BOOLEAN cancel, completeRequest;
+
+ //
+ // Default to failure. status is initialized so that the compiler does not
+ // think we are using an uninitialized value when completing the request.
+ //
+ status = STATUS_UNSUCCESSFUL;
+ cancel = FALSE;
+ completeRequest = FALSE;
+
+ queue = (WDFQUEUE) WdfTimerGetParentObject(Timer);
+ queueContext = QueueGetContext(queue);
+ requestContext = NULL;
+
+ //
+ // We must synchronize with the cancel routine which will be taking the
+ // request out of the context under this lock.
+ //
+ WdfSpinLockAcquire(queueContext->SpinLock);
+
+ request = queueContext->CurrentRequest;
+
+ if (request != NULL) {
+ requestContext = RequestGetContext(request);
+
+ if (EchoIncrementRequestCancelOwnershipCount(requestContext)) {
+ cancel = TRUE;
+ }
+ else {
+ //
+ // What has happened is that the cancel routine has executed and
+ // has already claimed cancel ownership of the request, but has not
+ // yet acquired the object lock and cleared the CurrentRequest field
+ // in queueContext. In this case, do nothing and let the cancel
+ // routine run to completion and complete the request.
+ //
+ }
+ }
+
+ WdfSpinLockRelease(queueContext->SpinLock);
+
+ //
+ // If we could not claim cancel ownership, we are done.
+ //
+ if (cancel == FALSE) {
+ return;
+ }
+
+ //
+ // The request handle and requestContext are valid until we release
+ // the cancel ownership count we already acquired.
+ //
+ status = WdfRequestUnmarkCancelable(request);
+ if (status != STATUS_CANCELLED) {
+ KdPrint(("CustomTimerDPC successfully cleared cancel routine on "
+ "request 0x%p, Status 0x%x \n", request,status));
+
+ //
+ // Since we successfully removed the cancel routine (and we are not
+ // currently racing with it), there is no need to use an interlocked
+ // decrement to lower the cancel ownership count.
+ //
+
+ //
+ // 2 is the initial count we set when we initialized CancelCompletionOwnershipCount
+ // plus the call to EchoIncrementRequestCancelOwnershipCount()
+ //
+ ASSERT(requestContext->CancelCompletionOwnershipCount == 2);
+ requestContext->CancelCompletionOwnershipCount -=2;
+
+ completeRequest = TRUE;
+ }
+ else {
+ completeRequest = EchoDecrementRequestCancelOwnershipCount(
+ requestContext
+ );
+
+ if (completeRequest) {
+ KdPrint(
+ ("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, but "
+ "claimed completion ownership\n", request));
+ }
+ else {
+ KdPrint(
+ ("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not "
+ "completing", request));
+ }
+ }
+
+ if (completeRequest) {
+ KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n",
+ request,status));
+
+ //
+ // Clear the current request out of the queue context and complete
+ // the request.
+ //
+ WdfSpinLockAcquire(queueContext->SpinLock);
+ queueContext->CurrentRequest = NULL;
+ status = queueContext->CurrentStatus;
+ WdfSpinLockRelease(queueContext->SpinLock);
+
+ WdfRequestComplete(request, status);
+ }
+}
+
diff --git a/general/echo/kmdf/driver/DriverSync/queue.h b/general/echo/kmdf/driver/DriverSync/queue.h
new file mode 100644
index 00000000..1985a6c7
--- /dev/null
+++ b/general/echo/kmdf/driver/DriverSync/queue.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This is a C version of a very simple sample driver that illustrates
+ how to use the driver framework and demonstrates best practices.
+
+--*/
+
+// Set max write length for testing
+#define MAX_WRITE_LENGTH 1024*40
+
+// Set timer period in ms
+#define TIMER_PERIOD 1000*10
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ // Here we allocate a buffer from a test write so it can be read back
+ PVOID Buffer;
+ ULONG Length;
+
+ // Timer DPC for this queue
+ WDFTIMER Timer;
+
+ // Virtual I/O
+ WDFREQUEST CurrentRequest;
+ NTSTATUS CurrentStatus;
+
+ // SpinLock to synchronize I/O callbacks.
+ WDFSPINLOCK SpinLock;
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+EchoQueueInitialize(
+ WDFDEVICE hDevice
+ );
+
+EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy;
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel;
+EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead;
+EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite;
+
+NTSTATUS
+EchoTimerCreate(
+ IN WDFTIMER* pTimer,
+ IN ULONG Period,
+ IN WDFQUEUE Queue
+ );
+
+EVT_WDF_TIMER EchoEvtTimerFunc;