summaryrefslogtreecommitdiff
path: root/general/echo/umdf2/driver/AutoSync
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/umdf2/driver/AutoSync
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/echo/umdf2/driver/AutoSync')
-rw-r--r--general/echo/umdf2/driver/AutoSync/device.c202
-rw-r--r--general/echo/umdf2/driver/AutoSync/device.h48
-rw-r--r--general/echo/umdf2/driver/AutoSync/driver.c192
-rw-r--r--general/echo/umdf2/driver/AutoSync/driver.h46
-rw-r--r--general/echo/umdf2/driver/AutoSync/echo.vcxproj180
-rw-r--r--general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters40
-rw-r--r--general/echo/umdf2/driver/AutoSync/echoum.inx89
-rw-r--r--general/echo/umdf2/driver/AutoSync/queue.c541
-rw-r--r--general/echo/umdf2/driver/AutoSync/queue.h62
9 files changed, 1400 insertions, 0 deletions
diff --git a/general/echo/umdf2/driver/AutoSync/device.c b/general/echo/umdf2/driver/AutoSync/device.c
new file mode 100644
index 00000000..48afdb66
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/device.c
@@ -0,0 +1,202 @@
+/*++
+
+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"
+
+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;
+
+ 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/umdf2/driver/AutoSync/device.h b/general/echo/umdf2/driver/AutoSync/device.h
new file mode 100644
index 00000000..f29c7908
--- /dev/null
+++ b/general/echo/umdf2/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/umdf2/driver/AutoSync/driver.c b/general/echo/umdf2/driver/AutoSync/driver.c
new file mode 100644
index 00000000..34fdd776
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/driver.c
@@ -0,0 +1,192 @@
+/*++
+
+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
+ will complete it next time the Timer callback runs.
+
+ During the time the request is waiting for the timer callback 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 Timer callback 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"
+
+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);
+
+ 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/umdf2/driver/AutoSync/driver.h b/general/echo/umdf2/driver/AutoSync/driver.h
new file mode 100644
index 00000000..b1a5b40a
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/driver.h
@@ -0,0 +1,46 @@
+/*++
+
+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 <windows.h>
+#include <wdf.h>
+#include "device.h"
+#include "queue.h"
+
+#ifndef ASSERT
+#if DBG
+#define ASSERT( exp ) \
+ ((!(exp)) ? \
+ (KdPrint(( "\n*** Assertion failed: " #exp "\n\n")), \
+ DebugBreak(), \
+ FALSE) : \
+ TRUE)
+#else
+#define ASSERT( exp )
+#endif // DBG
+#endif // ASSERT
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd;
+
+NTSTATUS
+EchoPrintDriverVersion(
+ );
+
diff --git a/general/echo/umdf2/driver/AutoSync/echo.vcxproj b/general/echo/umdf2/driver/AutoSync/echo.vcxproj
new file mode 100644
index 00000000..defa7b4d
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/echo.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>{95360722-8B66-4DD4-957A-DF8B7CA700FB}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{F03689D2-F1BC-4D18-B99E-286CA22656D5}</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>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>Universal</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>Universal</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>Universal</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=".\EchoUm.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\EchoUm.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>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </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>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </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>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </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>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </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/umdf2/driver/AutoSync/echo.vcxproj.Filters b/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters
new file mode 100644
index 00000000..75ab6a0f
--- /dev/null
+++ b/general/echo/umdf2/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>{EF21C647-A675-40F9-981A-364CC77BFA4D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{DC1E303A-60D0-45E3-AD8E-FA903A23C932}</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>{04F193A8-1C9D-45EC-ADDB-918233FB151D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{C0846D78-C3A3-42B0-AFDD-5D33B6AAE456}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\EchoUm.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\EchoUm.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/umdf2/driver/AutoSync/echoum.inx b/general/echo/umdf2/driver/AutoSync/echoum.inx
new file mode 100644
index 00000000..287c05df
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/echoum.inx
@@ -0,0 +1,89 @@
+;/*++
+;
+;Copyright (c) 1990-2000 Microsoft Corporation
+;
+;Module Name:
+; EchoUm.INF
+;
+;Abstract:
+; INF file for installing the Usermode Driver Frameworks Echo Driver
+;
+;Installation Notes:
+; Using Devcon: Type "devcon install EchoUm.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=wudf.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+; ================= Class section =====================
+
+[ClassInstall32]
+Addreg=SampleClassReg
+
+[SampleClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+Echo.dll = 1,,
+
+;*****************************************
+; ECHO Install Section
+;*****************************************
+
+[Manufacturer]
+%StdMfg%=Standard,NT$ARCH$
+
+[Standard.NT$ARCH$]
+%ECHO.DeviceDesc%=ECHO_Device, root\ECHO
+
+;---------------- copy files
+
+[ECHO_Device.NT]
+CopyFiles=UMDriverCopy
+
+[UMDriverCopy]
+ECHO.dll
+
+[DestinationDirs]
+UMDriverCopy=12,UMDF ; copy to driversMdf
+
+;-------------- Service installation
+[ECHO_Device.NT.Services]
+AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall
+
+[WUDFRD_ServiceInstall]
+DisplayName = %WudfRdDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\WUDFRd.sys
+
+;-------------- WDF specific section -------------
+[ECHO_Device.NT.Wdf]
+UmdfService=Echo, Echo_Install
+UmdfServiceOrder=Echo
+
+[Echo_Install]
+UmdfLibraryVersion=$UMDFVERSION$
+ServiceBinary=%12%\UMDF\echo.dll
+
+[Strings]
+MSFT = "Microsoft"
+StdMfg = "(Standard system devices)"
+DiskId1 = "WDF Sample ECHO Installation Disk #1"
+ECHO.DeviceDesc = "Sample UMDF v2 ECHO Driver"
+ClassName = "Sample Device"
+WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" \ No newline at end of file
diff --git a/general/echo/umdf2/driver/AutoSync/queue.c b/general/echo/umdf2/driver/AutoSync/queue.c
new file mode 100644
index 00000000..3162a683
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/queue.c
@@ -0,0 +1,541 @@
+/*++
+
+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"
+
+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;
+
+ //
+ // 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->WriteMemory = NULL;
+ queueContext->Timer = NULL;
+
+ queueContext->CurrentRequest = NULL;
+ queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Create the Queue timer
+ //
+ status = EchoTimerCreate(&queueContext->Timer, queue);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Error creating timer 0x%x\n",status));
+ return status;
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+EchoTimerCreate(
+ IN WDFTIMER* Timer,
+ IN WDFQUEUE Queue
+ )
+/*++
+
+Routine Description:
+
+ Subroutine to create timer. By associating the timerobject with
+ the queue, we are basically telling the framework to serialize the queue
+ callbacks with the timer 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;
+
+ //
+ // Create a WDFTIMER object
+ //
+ WDF_TIMER_CONFIG_INIT(&timerConfig, EchoEvtTimerFunc);
+
+ //
+ // WDF_OBJECT_ATTRIBUTES_INIT sets AutomaticSerialization to TRUE by default
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+ timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue
+ timerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ //
+ // Create a non-periodic timer since WDF does not allow periodic timer
+ // with autosynchronization at passive level
+ //
+ 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->WriteMemory != NULL ) {
+ WdfObjectDelete(queueContext->WriteMemory);
+ queueContext->WriteMemory = NULL;
+ }
+
+ 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;
+ size_t writeMemoryLength;
+
+ _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->WriteMemory == NULL) ) {
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);
+ return;
+ }
+
+ //
+ // Read what we have
+ //
+ WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength);
+ _Analysis_assume_(writeMemoryLength > 0);
+
+ if( writeMemoryLength < Length ) {
+ Length = writeMemoryLength;
+ }
+
+ //
+ // 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
+ WdfMemoryGetBuffer(queueContext->WriteMemory, NULL),
+ 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);
+ PVOID writeBuffer = NULL;
+
+ _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->WriteMemory != NULL ) {
+ WdfObjectDelete(queueContext->WriteMemory);
+ queueContext->WriteMemory = NULL;
+ }
+
+ Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES,
+ NonPagedPoolNx,
+ 'sam1',
+ Length,
+ &queueContext->WriteMemory,
+ &writeBuffer
+ );
+
+ if(!NT_SUCCESS(Status)) {
+ 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
+ writeBuffer,
+ Length );
+ if( !NT_SUCCESS(Status) ) {
+ KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status));
+ WdfVerifierDbgBreakPoint();
+
+ WdfObjectDelete(queueContext->WriteMemory);
+ queueContext->WriteMemory = NULL;
+
+ WdfRequestComplete(Request, Status);
+ return;
+ }
+
+ // 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));
+ }
+ }
+
+ //
+ // Restart the Timer since WDF does not allow periodic timer
+ // with autosynchronization at passive level
+ //
+ WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(TIMER_PERIOD));
+
+ return;
+}
+
+
diff --git a/general/echo/umdf2/driver/AutoSync/queue.h b/general/echo/umdf2/driver/AutoSync/queue.h
new file mode 100644
index 00000000..580c5b41
--- /dev/null
+++ b/general/echo/umdf2/driver/AutoSync/queue.h
@@ -0,0 +1,62 @@
+/*++
+
+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
+ WDFMEMORY WriteMemory;
+
+ // 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 WDFQUEUE Queue
+ );
+
+EVT_WDF_TIMER EchoEvtTimerFunc;