diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /general/echo/umdf2/driver/AutoSync | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'general/echo/umdf2/driver/AutoSync')
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/device.c | 202 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/device.h | 48 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/driver.c | 192 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/driver.h | 46 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/echo.vcxproj | 180 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters | 40 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/echoum.inx | 89 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/queue.c | 541 | ||||
| -rw-r--r-- | general/echo/umdf2/driver/AutoSync/queue.h | 62 |
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; |
