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 | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'general/echo')
81 files changed, 13276 insertions, 0 deletions
diff --git a/general/echo/kmdf/ReadMe.md b/general/echo/kmdf/ReadMe.md new file mode 100644 index 00000000..05f41f49 --- /dev/null +++ b/general/echo/kmdf/ReadMe.md @@ -0,0 +1,84 @@ +KMDF Echo Sample +================ + +The ECHO (KMDF) sample demonstrates how to use a sequential queue to serialize read and write requests presented to the driver. + +It also shows how to synchronize execution of these events with other asynchronous events such as request cancellation and DPC. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + +Related technologies +-------------------- + +[Kernel-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544396) + +Code Tour +--------- + +DriverEntry - Creates a framework driver object. + +EvtDeviceAdd: Creates a device and registers self managed I/O callbacks so that it can start and stop the periodic timer when the device is entering and leaving D0 state. It registers a device interface so that application can find the device and send I/O. For managing I/O requests, the driver creates a default queue to receive only read & write requests. All other requests sent to the driver will be failed by the framework. Then the driver creates a periodic timer to simulate asynchronous event. The purpose of this timer would be to complete the currently pending request. + +In the AutoSync version of the sample, the queue is created with WdfSynchronizationScopeQueue so that I/O callbacks including cancel routine are synchronized with a queue-level lock. Since timer is parented to queue and by default timer objects are created with AutomaticSerialization set to **TRUE**, timer DPC callbacks will be serialized with EvtIoRead, EvtIoWrite and Cancel Routine. + +In the DriverSync version of the sample, the queue is created with WdfSynchronizationScopeNone, so that the framework does not provide any synchronization. The driver synchronizes the I/O callbacks, cancel routine and the timer DPC using a spinlock that it creates for this purpose. + +EvtIoWrite: Allocates an internal buffer as big as the size of buffer in the write request and copies the data from the request buffer to internal buffer. The internal buffer address is saved in the queue context. If the driver receives another write request, it will free this one and allocate a new buffer to match the size of the incoming request. After copying the data, it will mark the request cancelable and return. The request will be eventually completed either by the timer or by the cancel routine if the application exits. + +EvtIoRead: Retrieves request memory buffer and copies the data from the buffer created by the write handler to the request buffer, and marks the request cancelable. The request will be completed by the timer DPC callback. + +Since the queue is a sequential queue, only one request is outstanding in the driver. + +Testing +------- + +**Usage:** + +Echoapp.exe --- Send single write and read request synchronously + +Echoapp.exe -Async --- Send 100 reads and writes asynchronously + +Exit the app anytime by pressing Ctrl-C + +File Manifest +------------- + +File + +Description + +Echo.htm + +Documentation for this sample (this file). + +***(The AutoSync and DriverSync versions of the sample each have their own version of the following files)*** + +Driver.h, Driver.c + +DriverEntry and Events on the Driver Object. + +Device.h, Device.c + +Events on the Device Object. + +Queue.h, Queue.c + +Contains Events on the I/O Queue Objects. + +Echo.inx + +File that describes the installation of this driver. The build process converts this into an INF file. + +Makefile.inc + +A makefile that defines custom build actions. This includes the conversion of the .INX file into a .INF file + +Makefile + +This file merely redirects to the real makefile that is shared by all the driver components of the Windows NT DDK. + +Sources + +Generic file that lists source files and all the build options. + 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; diff --git a/general/echo/kmdf/exe/echoapp.cpp b/general/echo/kmdf/exe/echoapp.cpp new file mode 100644 index 00000000..9649a407 --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.cpp @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ioctl.cpp + +Abstract: + + A simple asynch test for usb driver. + + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include "public.h" + +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE (40*1024) + +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +#define MAX_DEVPATH_LENGTH 256 + +BOOLEAN G_PerformAsyncIo; +BOOLEAN G_LimitedLoops; +ULONG G_AsyncIoLoopsNum; +CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; + + +ULONG +AsyncIo( + PVOID ThreadParameter + ); + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ); + + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE th1 = NULL; + BOOLEAN result = TRUE; + + + if (argc > 1) { + if(!_strnicmp (argv[1], "-Async", 6) ) { + G_PerformAsyncIo = TRUE; + if (argc > 2) { + G_AsyncIoLoopsNum = atoi(argv[2]); + G_LimitedLoops = TRUE; + } + else { + G_LimitedLoops = FALSE; + } + + } else { + printf("Usage:\n"); + printf(" Echoapp.exe --- Send single write and read request synchronously\n"); + printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); + printf(" Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\n"); + printf("Exit the app anytime by pressing Ctrl-C\n"); + result = FALSE; + goto exit; + } + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_ECHO, + G_DevicePath, + sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) + { + result = FALSE; + goto exit; + } + + printf("DevicePath: %s\n", G_DevicePath); + + hDevice = CreateFile(G_DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + result = FALSE; + goto exit; + } + + printf("Opened device successfully\n"); + + if(G_PerformAsyncIo) { + + printf("Starting AsyncIo\n"); + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + result = FALSE; + goto exit; + } + + // + // Use this thread for peforming write. + // + result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); + + }else { + // + // Write pattern buffers and read them back, then verify them + // + result = PerformWriteReadTest(hDevice, 512); + if(!result) { + goto exit; + } + + result = PerformWriteReadTest(hDevice, 30*1024); + if(!result) { + goto exit; + } + + } + +exit: + + if (th1 != NULL) { + WaitForSingleObject(th1, INFINITE); + CloseHandle(th1); + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + return ((result == TRUE) ? 0 : 1); + +} + +PUCHAR +CreatePatternBuffer( + IN ULONG Length + ) +{ + unsigned int i; + PUCHAR p, pBuf; + + pBuf = (PUCHAR)malloc(Length); + if( pBuf == NULL ) { + printf("Could not allocate %d byte buffer\n",Length); + return NULL; + } + + p = pBuf; + + for(i=0; i < Length; i++ ) { + *p = (UCHAR)i; + p++; + } + + return pBuf; +} + +BOOLEAN +VerifyPatternBuffer( + _In_reads_bytes_(Length) PUCHAR pBuffer, + _In_ ULONG Length + ) +{ + unsigned int i; + PUCHAR p = pBuffer; + + for( i=0; i < Length; i++ ) { + + if( *p != (UCHAR)(i & 0xFF) ) { + printf("Pattern changed. SB 0x%x, Is 0x%x\n", + (UCHAR)(i & 0xFF), *p); + return FALSE; + } + + p++; + } + + return TRUE; +} + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ) +/* +*/ +{ + ULONG bytesReturned =0; + PUCHAR WriteBuffer = NULL, + ReadBuffer = NULL; + BOOLEAN result = TRUE; + + WriteBuffer = CreatePatternBuffer(TestLength); + if( WriteBuffer == NULL ) { + + result = FALSE; + goto Cleanup; + } + + ReadBuffer = (PUCHAR)malloc(TestLength); + if( ReadBuffer == NULL ) { + + printf("PerformWriteReadTest: Could not allocate %d " + "bytes ReadBuffer\n",TestLength); + + result = FALSE; + goto Cleanup; + + } + + // + // Write the pattern to the device + // + bytesReturned = 0; + + if (!WriteFile ( hDevice, + WriteBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: WriteFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes written is not test length! Written %d, " + "SB %d\n",bytesReturned, TestLength); + + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Written successfully\n", + bytesReturned); + } + + bytesReturned = 0; + + if ( !ReadFile (hDevice, + ReadBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: ReadFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes Read is not test length! Read %d, " + "SB %d\n",bytesReturned, TestLength); + + // + // Note: Is this a Failure Case?? + // + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Read successfully\n",bytesReturned); + } + + // + // Now compare + // + if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { + + printf("Verify failed\n"); + + result = FALSE; + goto Cleanup; + } + + printf("Pattern Verified successfully\n"); + +Cleanup: + + // + // Free WriteBuffer if non NULL. + // + if (WriteBuffer) { + free (WriteBuffer); + } + + // + // Free ReadBuffer if non NULL + // + if (ReadBuffer) { + free (ReadBuffer); + } + + return result; +} + + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG numberOfBytesTransferred; + OVERLAPPED *completedOv; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG_PTR key; + ULONG error; + BOOLEAN result = TRUE; + ULONG maxPendingRequests = NUM_ASYNCH_IO; + ULONG remainingRequestsToSend = 0; + ULONG remainingRequestsToReceive = 0; + + hDevice = CreateFile(G_DevicePath, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + result = FALSE; + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + result = FALSE; + goto Error; + } + + // + // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any + // time (whichever is less) + // + if (G_LimitedLoops == TRUE) { + remainingRequestsToReceive = G_AsyncIoLoopsNum; + if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { + // + // After we send the initial NUM_ASYNCH_IO, we will have additional + // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send + // + maxPendingRequests = NUM_ASYNCH_IO; + remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; + } + else { + maxPendingRequests = G_AsyncIoLoopsNum; + remainingRequestsToSend = 0; + + } + } + + pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + result = FALSE; + goto Error; + } + + buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + result = FALSE; + goto Error; + } + + ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); + ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < maxPendingRequests; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Read failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Write failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + result = FALSE; + goto Error; + } + + // + // Read successfully completed. If we're doing unlimited I/Os then Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + printf("Number of bytes read by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%dth Read failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + + printf("%dth write failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + +Error: + if(hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if(hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if(buf) { + free(buf); + } + if(pOvList) { + free(pOvList); + } + + return (ULONG)result; + +} + + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ) +{ + HDEVINFO HardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL; + ULONG Length, RequiredLength = 0; + BOOL bResult; + HRESULT hr; + + HardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed!\n"); + return FALSE; + } + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, + 0, + InterfaceGuid, + 0, + &DeviceInterfaceData); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + printf("SetupDiEnumDeviceInterfaces failed.\n"); + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + return FALSE; + } + + SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + NULL, + 0, + &RequiredLength, + NULL + ); + + DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength); + + if (DeviceInterfaceDetailData == NULL) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Failed to allocate memory.\n"); + return FALSE; + } + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Length = RequiredLength; + + bResult = SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + Length, + &RequiredLength, + NULL); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); + LocalFree(DeviceInterfaceDetailData); + LocalFree(lpMsgBuf); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath) ; + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces + LocalFree(DeviceInterfaceDetailData); + + return ( !FAILED(hr) ); // Result depends on StringCchCopy() +} + diff --git a/general/echo/kmdf/exe/echoapp.vcxproj b/general/echo/kmdf/exe/echoapp.vcxproj new file mode 100644 index 00000000..11b3eb4c --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.vcxproj @@ -0,0 +1,171 @@ +<?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>{684264A6-91C1-4046-AD23-BD823E13EB60}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{C342DB0F-934F-4A0A-90A7-02650E906732}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</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" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp" /> + </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/exe/echoapp.vcxproj.Filters b/general/echo/kmdf/exe/echoapp.vcxproj.Filters new file mode 100644 index 00000000..7e14cf46 --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{A120A502-9177-430F-BAEB-BBE51661EDDD}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{967C5907-C8A7-46F3-B2B7-E3A0BFF110EE}</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>{53BEED44-2F74-4E8F-B7B8-D0BDDB11BEB6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/kmdf/exe/public.h b/general/echo/kmdf/exe/public.h new file mode 100644 index 00000000..d632951d --- /dev/null +++ b/general/echo/kmdf/exe/public.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + + +Environment: + + user and kernel + +--*/ + +#define WHILE(a) \ +__pragma(warning(suppress:4127)) while(a) + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + diff --git a/general/echo/kmdf/kmdfecho.sln b/general/echo/kmdf/kmdfecho.sln new file mode 100644 index 00000000..b9c25c6c --- /dev/null +++ b/general/echo/kmdf/kmdfecho.sln @@ -0,0 +1,63 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{1DD2F948-0799-49E3-A880-35A6215F8479}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{B52DE63E-ED02-41DD-9DAB-53ACE0286663}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{AE9E09B7-46C1-4AA3-9411-F125D9188EFD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DriverSync", "DriverSync", "{F01C6D5C-982E-4AE2-8DDC-0666F3905135}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{684264A6-91C1-4046-AD23-BD823E13EB60}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{C8F9A776-3675-459B-A0A3-BA17D003C70B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_2", "driver\DriverSync\echo_2.vcxproj", "{968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.ActiveCfg = Debug|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.Build.0 = Debug|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.ActiveCfg = Release|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.Build.0 = Release|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.ActiveCfg = Debug|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.Build.0 = Debug|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.ActiveCfg = Release|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.Build.0 = Release|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.ActiveCfg = Debug|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.Build.0 = Debug|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.ActiveCfg = Release|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.Build.0 = Release|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.ActiveCfg = Debug|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.Build.0 = Debug|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.ActiveCfg = Release|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.Build.0 = Release|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.Build.0 = Debug|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.ActiveCfg = Release|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.Build.0 = Release|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.ActiveCfg = Debug|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.Build.0 = Debug|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.ActiveCfg = Release|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {684264A6-91C1-4046-AD23-BD823E13EB60} = {1DD2F948-0799-49E3-A880-35A6215F8479} + {C8F9A776-3675-459B-A0A3-BA17D003C70B} = {B52DE63E-ED02-41DD-9DAB-53ACE0286663} + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3} = {F01C6D5C-982E-4AE2-8DDC-0666F3905135} + {B52DE63E-ED02-41DD-9DAB-53ACE0286663} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} + {F01C6D5C-982E-4AE2-8DDC-0666F3905135} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} + EndGlobalSection +EndGlobal diff --git a/general/echo/umdf/Comsup.cpp b/general/echo/umdf/Comsup.cpp new file mode 100644 index 00000000..fd298470 --- /dev/null +++ b/general/echo/umdf/Comsup.cpp @@ -0,0 +1,344 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.cpp + +Abstract: + + This module contains implementations for the functions and methods + used for providing COM support. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "comsup.tmh" + +// +// Implementation of CUnknown methods. +// + +CUnknown::CUnknown( + VOID + ) : m_ReferenceCount(1) +/*++ + + Routine Description: + + Constructor for an instance of the CUnknown class. This simply initializes + the reference count of the object to 1. The caller is expected to + call Release() if it wants to delete the object once it has been allocated. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + // do nothing. +} + +HRESULT +STDMETHODCALLTYPE +CUnknown::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method provides the basic support for query interface on CUnknown. + If the interface requested is IUnknown it references the object and + returns an interface pointer. Otherwise it returns an error. + + Arguments: + + InterfaceId - the IID being requested + + Object - a location to store the interface pointer to return. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) + { + *Object = QueryIUnknown(); + return S_OK; + } + else + { + *Object = NULL; + return E_NOINTERFACE; + } +} + +IUnknown * +CUnknown::QueryIUnknown( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IUnknown interface. + + This allows other methods to convert a CUnknown pointer into an IUnknown + pointer without a typecast and without calling QueryInterface and dealing + with the return value. + + Arguments: + + None + + Return Value: + + A pointer to the object's IUnknown interface. + +--*/ +{ + AddRef(); + return static_cast<IUnknown *>(this); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::AddRef( + VOID + ) +/*++ + + Routine Description: + + This method adds one to the object's reference count. + + Arguments: + + None + + Return Value: + + The new reference count. The caller should only use this for debugging + as the object's actual reference count can change while the caller + examines the return value. + +--*/ +{ + return InterlockedIncrement(&m_ReferenceCount); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::Release( + VOID + ) +/*++ + + Routine Description: + + This method subtracts one to the object's reference count. If the count + goes to zero, this method deletes the object. + + Arguments: + + None + + Return Value: + + The new reference count. If the caller uses this value it should only be + to check for zero (i.e. this call caused or will cause deletion) or + non-zero (i.e. some other call may have caused deletion, but this one + didn't). + +--*/ +{ + ULONG count = InterlockedDecrement(&m_ReferenceCount); + + if (count == 0) + { + delete this; + } + return count; +} + +// +// Implementation of CClassFactory methods. +// + +// +// Define storage for the factory's static lock count variable. +// + +LONG CClassFactory::s_LockCount = 0; + +IClassFactory * +CClassFactory::QueryIClassFactory( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IClassFactory interface. + + This allows other methods to convert a CClassFactory pointer into an + IClassFactory pointer without a typecast and without dealing with the + return value QueryInterface. + + Arguments: + + None + + Return Value: + + A referenced pointer to the object's IClassFactory interface. + +--*/ +{ + AddRef(); + return static_cast<IClassFactory *>(this); +} + +HRESULT +CClassFactory::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method attempts to retrieve the requested interface from the object. + + If the interface is found then the reference count on that interface (and + thus the object itself) is incremented. + + Arguments: + + InterfaceId - the interface the caller is requesting. + + Object - a location to store the interface pointer. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + // + // This class only supports IClassFactory so check for that. + // + + if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) + { + *Object = QueryIClassFactory(); + return S_OK; + } + else + { + // + // See if the base class supports the interface. + // + + return CUnknown::QueryInterface(InterfaceId, Object); + } +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::CreateInstance( + _In_opt_ IUnknown * /* OuterObject */, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This COM method is the factory routine - it creates instances of the driver + callback class and returns the specified interface on them. + + Arguments: + + OuterObject - only used for aggregation, which our driver callback class + does not support. + + InterfaceId - the interface ID the caller would like to get from our + new object. + + Object - a location to store the referenced interface pointer to the new + object. + + Return Value: + + Status. + +--*/ +{ + HRESULT hr; + + PCMyDriver driver; + + *Object = NULL; + + hr = CMyDriver::CreateInstance(&driver); + + if (SUCCEEDED(hr)) + { + hr = driver->QueryInterface(InterfaceId, Object); + driver->Release(); + } + + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::LockServer( + _In_ BOOL Lock + ) +/*++ + + Routine Description: + + This COM method can be used to keep the DLL in memory. However since the + driver's DllCanUnloadNow function always returns false, this has little + effect. Still it tracks the number of lock and unlock operations. + + Arguments: + + Lock - Whether the caller wants to lock or unlock the "server" + + Return Value: + + S_OK + +--*/ +{ + if (Lock) + { + InterlockedIncrement(&s_LockCount); + } + else + { + InterlockedDecrement(&s_LockCount); + } + return S_OK; +} + diff --git a/general/echo/umdf/Comsup.h b/general/echo/umdf/Comsup.h new file mode 100644 index 00000000..b96fd982 --- /dev/null +++ b/general/echo/umdf/Comsup.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.h + +Abstract: + + This module contains classes and functions use for providing COM support + code. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Forward type declarations. They are here rather than in internal.h as +// you only need them if you choose to use these support classes. +// + +typedef class CUnknown *PCUnknown; +typedef class CClassFactory *PCClassFactory; + +// +// Base class to implement IUnknown. You can choose to derive your COM +// classes from this class, or simply implement IUnknown in each of your +// classes. +// + +class CUnknown : public IUnknown +{ + +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The reference count for this object. Initialized to 1 in the + // constructor. + // + + LONG m_ReferenceCount; + +// +// Protected data members and methods. These are accessible by the subclasses +// but not by other classes. +// +protected: + + // + // The constructor and destructor are protected to ensure that only the + // subclasses of CUnknown can create and destroy instances. + // + + CUnknown( + VOID + ); + + // + // The destructor MUST be virtual. Since any instance of a CUnknown + // derived class should only be deleted from within CUnknown::Release, + // the destructor MUST be virtual or only CUnknown::~CUnknown will get + // invoked on deletion. + // + // If you see that your CMyDevice specific destructor is never being + // called, make sure you haven't deleted the virtual destructor here. + // + + virtual + ~CUnknown( + VOID + ) + { + // Do nothing + } + +// +// Public Methods. These are accessible by any class. +// +public: + + IUnknown * + QueryIUnknown( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ); + + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ); + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; + +// +// Class factory support class. Create an instance of this from your +// DllGetClassObject method and modify the implementation to create +// an instance of your driver event handler class. +// + +class CClassFactory : public CUnknown, public IClassFactory +{ +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The lock count. This is shared across all instances of IClassFactory + // and can be queried through the public IsLocked method. + // + + static LONG s_LockCount; + +// +// Public Methods. These are accessible by any class. +// +public: + + IClassFactory * + QueryIClassFactory( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IClassFactory methods. + // + + virtual + HRESULT + STDMETHODCALLTYPE + CreateInstance( + _In_opt_ IUnknown *OuterObject, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + virtual + HRESULT + STDMETHODCALLTYPE + LockServer( + _In_ BOOL Lock + ); +}; diff --git a/general/echo/umdf/Device.cpp b/general/echo/umdf/Device.cpp new file mode 100644 index 00000000..77110e8e --- /dev/null +++ b/general/echo/umdf/Device.cpp @@ -0,0 +1,415 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the sample driver's + device callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "initguid.h" + +#include "device.tmh" + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + +HRESULT +CMyDevice::CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit, + _Out_ PCMyDevice *Device + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + PCMyDevice device; + HRESULT hr; + + // + // Allocate a new instance of the device class. + // + + device = new CMyDevice(); + + if (NULL == device) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + hr = device->Initialize(FxDriver, FxDeviceInit); + + if (SUCCEEDED(hr)) + { + *Device = device; + } + else + { + device->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver * FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + + Return Value: + + status. + +--*/ +{ + IWDFDevice *fxDevice = NULL; + IWDFDeviceInitialize2 *fxDeviceInit2; + HRESULT hr; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set no locking unless you need an automatic callbacks synchronization + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // TODO: If you're writing a filter driver then indicate that here. + // + // FxDeviceInit->SetFilter(); + // + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // Set retrieval mode to direct I/O. This needs to be done before the call + // to CreateDevice. + // + hr = FxDeviceInit->QueryInterface(IID_PPV_ARGS(&fxDeviceInit2)); + + if (SUCCEEDED(hr)) + { + // + // WdfDeviceIoBufferedOrDirect for read/write and ioctrl operations. + // UMDF defaults to direct-I/O when the device is not running in a shared + // wudfhost process, and it defaults to buffered-I/O otherwise. Direct I/O + // is not allowed when the device is pooled. + // + // + fxDeviceInit2->SetIoTypePreference(WdfDeviceIoBufferRetrievalDeferred, + WdfDeviceIoBufferedOrDirect, + WdfDeviceIoBufferedOrDirect); + + SAFE_RELEASE(fxDeviceInit2); + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + { + IUnknown *unknown = this->QueryIUnknown(); + + hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); + + unknown->Release(); + } + } + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + + // + // Drop the reference we got from CreateDevice. Since this object + // is partnered with the framework object they have the same + // lifespan - there is no need for an additional reference. + // + + fxDevice->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + PCMyQueue defaultQueue; + + HRESULT hr; + + hr = CMyQueue::CreateInstance(m_FxDevice, &defaultQueue); + + if (FAILED(hr)) + { + return hr; + } + + hr = defaultQueue->Configure(); + + if (SUCCEEDED(hr)) + { + // + // In case of success store defaultQueue in our member + // The reference is transferred to m_DefaultQueue + // + + m_Queue = defaultQueue; + } + else + { + // + // In case of failure release the reference + // + + defaultQueue->Release(); + } + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_ECHO, + NULL); + } + + return hr; +} + +HRESULT +CMyDevice::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Since the sample driver doesn't support any of the device events, this + method simply calls the base class's BaseQueryInterface. + + If the sample is extended to include device event interfaces then this + method must be changed to check the IID and return pointers to them as + appropriate. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + HRESULT hr; + + if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackSelfManagedIo))) { + *Object = QueryIPnpCallbackSelfManagedIo(); + hr = S_OK; + } else { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +HRESULT +CMyDevice::OnSelfManagedIoInit( + _In_ IWDFDevice * pWdfDevice + ) +/*++ + + Routine Description: + + This method is called to allow driver to initialize any resources + that driver might need to process I/O. + + Echo driver needs a thread to process completions. We initialize + this thread here + + Arguments: + + pWdfDevice - framework device object for which to initialze resources + + Return Value: + + S_OK in case of success + HRESULT correponding to error returned by CreateThread, in case of failure + +--*/ +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER(pWdfDevice); + + + m_ThreadHandle = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + CMyQueue::CompletionThread, // Thread Func + (LPVOID)m_Queue, // Arg to Thread Func is Queue + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (m_ThreadHandle == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +void +CMyDevice::OnSelfManagedIoCleanup( + _In_ IWDFDevice * pWdfDevice + ) +/*++ + + Routine Description: + + This method is called to allow driver to cleanup any resources + that driver allocated to process I/O. + + It is critical that, in this routine driver wait for all of the + threads which it created to exit. Otherwise those threads could + continue to execute when framework unloads the driver which + would lead to a crash. + + Echo driver created a thread to handle completions. We wait for + that thread to exit in this routine + + Arguments: + + pWdfDevice - framework device object for which to cleanup resources + + Return Value: + + None + +--*/ +{ + // + // Kill the thread and + // wait for the thread to die. + // + + UNREFERENCED_PARAMETER(pWdfDevice); + + if (m_ThreadHandle) { + + // + // Ask queue to set terminate flag which will make + // the thread exit + // + m_Queue->SetExitThread(); + + // + // Wait for the thread to exit + // + + WaitForSingleObject(m_ThreadHandle, INFINITE); + + // + // Close the thread handle + // + + CloseHandle(m_ThreadHandle); + m_ThreadHandle = NULL; + } + + // + // Release the reference we took on the queue callback object + // to keep it alive until the thread exits + // + + SAFE_RELEASE(m_Queue); +} + diff --git a/general/echo/umdf/Device.h b/general/echo/umdf/Device.h new file mode 100644 index 00000000..70147c11 --- /dev/null +++ b/general/echo/umdf/Device.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF Echo sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#include "queue.h" + +// +// Class for the iotrace driver. +// + +class CMyDevice : + public CUnknown, + public IPnpCallbackSelfManagedIo +{ + +// +// Private data members. +// +private: + + IWDFDevice *m_FxDevice; + + // + // Completion Thread handle used by queue callback object + // + HANDLE m_ThreadHandle; + + // + // Our queue callback object + // Strong reference - since we pass it to the thread we create + // + CMyQueue *m_Queue; + +// +// Private methods. +// + +private: + + CMyDevice( + VOID + ) + { + m_FxDevice = NULL; + } + + HRESULT + Initialize( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + IPnpCallbackSelfManagedIo * + QueryIPnpCallbackSelfManagedIo( + VOID + ) + { + AddRef(); + return static_cast<IPnpCallbackSelfManagedIo *>(this); + } + + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit, + _Out_ PCMyDevice *Device + ); + + HRESULT + Configure( + VOID + ); + +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IPnpCallbackSelfManagedIo methods + // + + // + // We implement this interface to create and tear down + // our completion thread + // + // It is critical that we wait for all the threads we create + // to exit during OnSelfManagedIoCleanup, otherwise thread + // may continue to execute when framework unloads the driver, + // leading to a crash + // + // We don't manage any I/O separate from the queue, so apart + // from OnSelfManagedIoInit and OnSelfManagedIoCleanup, other + // methods have token implementations + // + + virtual + void + STDMETHODCALLTYPE + OnSelfManagedIoCleanup( + _In_ IWDFDevice * pWdfDevice + ); + + virtual + void + STDMETHODCALLTYPE + OnSelfManagedIoFlush( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoInit( + _In_ IWDFDevice * pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoSuspend( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoRestart( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoStop( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } +}; diff --git a/general/echo/umdf/Driver.cpp b/general/echo/umdf/Driver.cpp new file mode 100644 index 00000000..1428a08a --- /dev/null +++ b/general/echo/umdf/Driver.cpp @@ -0,0 +1,220 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +HRESULT +CMyDriver::CreateInstance( + _Out_ PCMyDriver *Driver + ) +/*++ + + Routine Description: + + This static method is invoked in order to create and initialize a new + instance of the driver class. The caller should arrange for the object + to be released when it is no longer in use. + + Arguments: + + Driver - a location to store a referenced pointer to the new instance + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ +{ + PCMyDriver driver; + HRESULT hr; + + // + // Allocate the callback object. + // + + driver = new CMyDriver(); + + if (NULL == driver) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the callback object. + // + + hr = driver->Initialize(); + + if (SUCCEEDED(hr)) + { + // + // Store a pointer to the new, initialized object in the output + // parameter. + // + + *Driver = driver; + } + else + { + + // + // Release the reference on the driver object to get it to delete + // itself. + // + + driver->Release(); + } + + return hr; +} + +HRESULT +CMyDriver::Initialize( + VOID + ) +/*++ + + Routine Description: + + This method is called to initialize a newly created driver callback object + before it is returned to the creator. Unlike the constructor, the + Initialize method contains operations which could potentially fail. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + return S_OK; +} + +HRESULT +CMyDriver::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Interface + ) +/*++ + + Routine Description: + + This method returns a pointer to the requested interface on the callback + object.. + + Arguments: + + InterfaceId - the IID of the interface to query/reference + + Interface - a location to store the interface pointer. + + Return Value: + + S_OK if the interface is supported. + E_NOINTERFACE if it is not supported. + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) + { + *Interface = QueryIDriverEntry(); + return S_OK; + } + else + { + return CUnknown::QueryInterface(InterfaceId, Interface); + } +} + +HRESULT +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + HRESULT hr; + + PCMyDevice device = NULL; + + // + // TODO: Do any per-device initialization (reading settings from the + // registry for example) that's necessary before creating your + // device callback object here. Otherwise you can leave such + // initialization to the initialization of the device event + // handler. + // + + // + // Create a new instance of our device callback object + // + + hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); + + // + // TODO: Change any per-device settings that the object exposes before + // calling Configure to let it complete its initialization. + // + + // + // If that succeeded then call the device's construct method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference on the device callback object now that it's been + // associated with an fx device object. + // + + if (NULL != device) + { + device->Release(); + } + + return hr; +} diff --git a/general/echo/umdf/Driver.h b/general/echo/umdf/Driver.h new file mode 100644 index 00000000..643ea5a5 --- /dev/null +++ b/general/echo/umdf/Driver.h @@ -0,0 +1,149 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +class CMyDriver : public CUnknown, public IDriverEntry +{ +// +// Private data members. +// +private: + +// +// Private methods. +// +private: + + // + // Returns a refernced pointer to the IDriverEntry interface. + // + + IDriverEntry * + QueryIDriverEntry( + VOID + ) + { + AddRef(); + return static_cast<IDriverEntry*>(this); + } + + HRESULT + Initialize( + VOID + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _Out_ PCMyDriver *Driver + ); + +// +// COM methods +// +public: + + // + // IDriverEntry methods + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnInitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + virtual + VOID + STDMETHODCALLTYPE + OnDeinitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return; + } + + // + // IUnknown methods. + // + // We have to implement basic ones here that redirect to the + // base class becuase of the multiple inheritance. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; diff --git a/general/echo/umdf/Echo.rc b/general/echo/umdf/Echo.rc new file mode 100644 index 00000000..2a26d85c --- /dev/null +++ b/general/echo/umdf/Echo.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// Echo.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Echo User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "UMDFEcho" +#define VER_ORIGINALFILENAME_STR "UMDFEcho.dll" + +#include "common.ver" diff --git a/general/echo/umdf/Queue.cpp b/general/echo/umdf/Queue.cpp new file mode 100644 index 00000000..f366fe31 --- /dev/null +++ b/general/echo/umdf/Queue.cpp @@ -0,0 +1,545 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + + +#include "internal.h" + +// +// IUnknown implementation +// + +// +// Queue destructor. +// Free up the buffer, wait for thread to terminate and +// delete critical section. +// + + +CMyQueue::~CMyQueue( + VOID + ) +/*++ + +Routine Description: + + + IUnknown implementation of Release + +Arguments: + + +Return Value: + + ULONG (reference count after Release) + +--*/ +{ + if (m_Buffer) { + delete [] m_Buffer; + } + + if (m_InitCritSec) { + ::DeleteCriticalSection(&m_Crit); + } +} + + +// +// Initialize +HRESULT +CMyQueue::CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ PCMyQueue *Queue + ) +/*++ + +Routine Description: + + + CreateInstance creates an instance of the queue object. + +Arguments: + + ppUkwn - OUT parameter is an IUnknown interface to the queue object + +Return Value: + + HRESULT indicating success or failure + +--*/ +{ + CMyQueue *pMyQueue = new CMyQueue; + HRESULT hr; + + if (pMyQueue == NULL) { + return E_OUTOFMEMORY; + } + + hr = pMyQueue->Initialize(FxDevice); + + if (SUCCEEDED(hr)) + { + *Queue = pMyQueue; + } + else + { + pMyQueue->Release(); + } + return hr; +} + +HRESULT +CMyQueue::Initialize( + _In_ IWDFDevice *FxDevice + ) +{ + IWDFIoQueue *fxQueue; + HRESULT hr; + + // + // Initialize the critical section before we continue + // + + if (!InitializeCriticalSectionAndSpinCount(&m_Crit,0x80000400)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Exit; + } + m_InitCritSec = TRUE; + + // + // Create the framework queue + // + + { + IUnknown *unknown = QueryIUnknown(); + hr = FxDevice->CreateIoQueue(unknown, + TRUE, + WdfIoQueueDispatchSequential, + TRUE, + FALSE, + &fxQueue); + unknown->Release(); + } + + if (FAILED(hr)) + { + goto Exit; + } + + m_FxQueue = fxQueue; + + fxQueue->Release(); + +Exit: + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CMyQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + +Routine Description: + + + Query Interface + +Arguments: + + Follows COM specifications + +Return Value: + + HRESULT indicating success or failure + +--*/ +{ + HRESULT hr; + + + if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) { + *Object = QueryIQueueCallbackWrite(); + hr = S_OK; + } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackRead))) { + *Object = QueryIQueueCallbackRead(); + hr = S_OK; + } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDeviceIoControl))) { + *Object = QueryIQueueCallbackDeviceIoControl(); + hr = S_OK; + } else { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnDeviceIoControl( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ) +/*++ + +Routine Description: + + + DeviceIoControl dispatch routine + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + ControlCode - IO Control Code + InputBufferSizeInBytes - Length of input buffer + OutputBufferSizeInBytes - Length of output buffer + + Always succeeds DeviceIoIoctl +Return Value: + + VOID + +--*/ +{ + + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(ControlCode); + UNREFERENCED_PARAMETER(InputBufferSizeInBytes); + UNREFERENCED_PARAMETER(OutputBufferSizeInBytes); + + pWdfRequest->Complete(S_OK); + return; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToWrite + ) +/*++ + +Routine Description: + + + Write dispatch routine + IQueueCallbackWrite + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToWrite - Length of bytes in the write buffer + + Allocate and copy data to local buffer +Return Value: + + VOID + +--*/ +{ + + HRESULT hr; + IWDFMemory* pRequestMemory = NULL; + IWDFIoRequest2 * pWdfRequest2 = NULL; + + UNREFERENCED_PARAMETER(pWdfQueue); + + // + // Handle Zero length writes. + // + + if (!BytesToWrite) { + pWdfRequest->CompleteWithInformation(S_OK, 0); + return; + } + + if( BytesToWrite > MAX_WRITE_LENGTH ) { + + pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0); + return; + } + + // Release previous buffer if set + + if( m_Buffer != NULL ) { + delete [] m_Buffer; + m_Buffer = NULL; + m_Length = 0L; + } + + // Allocate Buffer + + m_Buffer = new UCHAR[BytesToWrite]; + if (m_Buffer == NULL) { + pWdfRequest->Complete(E_OUTOFMEMORY); + m_Length = 0L; + return; + } + + // Get memory object + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2)); + + if (FAILED(hr)) { + goto Exit; + } + + hr = pWdfRequest2->RetrieveInputMemory(&pRequestMemory); + + if (FAILED(hr)) { + goto Exit; + } + + // Copy from memory object to our buffer + + hr = pRequestMemory->CopyToBuffer(0, m_Buffer, BytesToWrite); + + if (FAILED(hr)) { + goto Exit; + } + + // + // Release memory object. + // + SAFE_RELEASE(pRequestMemory); + + // + // Save the information so that we can use it + // to complete the request later. + // + + Lock(); + + m_Length = (ULONG) BytesToWrite; + m_XferredBytes = m_Length; + m_CurrentRequest = pWdfRequest2; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + if (pWdfRequest2) { + pWdfRequest2->CompleteWithInformation(hr, 0); + } + delete [] m_Buffer; + m_Buffer = NULL; + SAFE_RELEASE(pRequestMemory); + } + + // + // This is an early release. pWdfRequest2 will be released, when the request is completed + // + SAFE_RELEASE(pWdfRequest2); + + return; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T SizeInBytes + ) +/*++ + +Routine Description: + + + Read dispatch routine + IQueueCallbackRead + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + SizeInBytes - Length of bytes in the read buffer + + Copy available data into the read buffer +Return Value: + + VOID + +--*/ +{ + IWDFMemory* pRequestMemory = NULL; + IWDFIoRequest2 * pWdfRequest2 = NULL; + HRESULT hr; + + UNREFERENCED_PARAMETER(pWdfQueue); + + // + // Handle Zero length reads. + // + + if (!SizeInBytes) { + pWdfRequest->CompleteWithInformation(S_OK, 0); + return; + } + + if (m_Buffer == NULL) { + pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), SizeInBytes); + return; + } + + if (m_Length < SizeInBytes) { + SizeInBytes = m_Length; + } + + // + // Get memory object + // + + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2)); + + if (FAILED(hr)) { + goto Exit; + } + + hr = pWdfRequest2->RetrieveOutputMemory(&pRequestMemory ); + + if (FAILED(hr)) { + goto Exit; + } + + // Copy from buffer to memory object + + hr = pRequestMemory->CopyFromBuffer(0, m_Buffer, SizeInBytes); + + if (FAILED(hr)) { + goto Exit; + } + + // + // Release memory object. + // + + SAFE_RELEASE(pRequestMemory); + + // + // Save the information so that we can use it + // to complete the request later. + // + + Lock(); + + m_CurrentRequest = pWdfRequest2; + m_XferredBytes = SizeInBytes; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + if (pWdfRequest2) { + pWdfRequest2->CompleteWithInformation(hr, 0); + } + SAFE_RELEASE(pRequestMemory); + } + + // + // This is an early release. pWdfRequest2 will be released, when the request is completed + // + SAFE_RELEASE(pWdfRequest2); + + return; +} + +DWORD +CMyQueue::CompletionThread( + PVOID ThreadParameter + ) +/*++ + +Routine Description: + + + This routine is called from the thread started to complete + I/O requests. It sleeps for TIMER_PERIOD and then completes + the current request. Note that it has to release the lock + before it calls the request complete method. + +Arguments: + + ThreadParameter - This is a pointer to the Queue object. + +Return Value: + + VOID + +--*/ +{ + CMyQueue *pQueue = (CMyQueue *)ThreadParameter; + IWDFIoRequest2 *request; + SIZE_T bytesXferred = 0; + + for (;;) { + + // + // Block for a fixed time and then complete the request. + // + + Sleep(TIMER_PERIOD); + + pQueue->Lock(); + + // + // Process the current request. + // + + request = pQueue->m_CurrentRequest; + + if (request) { + bytesXferred = pQueue->m_XferredBytes; + } + + // + // Reset values. + // + + pQueue->m_CurrentRequest = NULL; + pQueue->m_XferredBytes = 0; + + + pQueue->Unlock(); + + if (request) { + request->CompleteWithInformation(S_OK, bytesXferred); + } + + // + // If thread needs to be terminated + // + + if (pQueue->m_ExitThread) { + ExitThread(0); + } + + } + +} diff --git a/general/echo/umdf/Queue.h b/general/echo/umdf/Queue.h new file mode 100644 index 00000000..c4b28c97 --- /dev/null +++ b/general/echo/umdf/Queue.h @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// Set max write length for testing +#define MAX_WRITE_LENGTH (40*1024) + +// Set timer period in ms +#define TIMER_PERIOD 100 + +// +// Queue Callback Object. +// + +class CMyQueue : + public IQueueCallbackDeviceIoControl, + public IQueueCallbackRead, + public IQueueCallbackWrite, + public CUnknown +{ + PVOID m_Buffer; // Current buffer + ULONG m_Length; // Length of the buffer + SIZE_T m_XferredBytes; // Amount of bytes transferred for the current request + IWDFIoRequest2 *m_CurrentRequest; // Current request + CRITICAL_SECTION m_Crit; // Lock to protect updates to CMyQueue fields + BOOLEAN m_ExitThread; // If TRUE Terminate thread. + BOOLEAN m_InitCritSec; // If TRUE lock initialized + + IWDFIoQueue *m_FxQueue; + + CMyQueue() : + m_Buffer(NULL), + m_Length (0), + m_CurrentRequest(NULL), + m_XferredBytes(0), + m_ExitThread(FALSE), + m_InitCritSec(FALSE), + m_FxQueue(NULL) + { + } + + virtual ~CMyQueue(); + + _Acquires_lock_(this->m_Crit) + __inline + void + Lock( + ) + { + ::EnterCriticalSection(&m_Crit); + } + + _Releases_lock_(this->m_Crit) + __inline + void + Unlock( + ) + { + ::LeaveCriticalSection(&m_Crit); + } + + HRESULT + Initialize( + _In_ IWDFDevice *FxDevice + ); + +public: + + // + // Completion thread routine. + // + + static DWORD CompletionThread( PVOID ThreadParameter); + + // + // Sets the flag to make thread exit + // + + void + SetExitThread() + { + m_ExitThread = TRUE; + } + + static + HRESULT + CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ PCMyQueue *Queue + ); + + HRESULT + Configure( + VOID + ) + { + return S_OK; + } + + + IQueueCallbackDeviceIoControl * + QueryIQueueCallbackDeviceIoControl( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackDeviceIoControl *>(this); + } + + IQueueCallbackRead * + QueryIQueueCallbackRead( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackRead *>(this); + } + + IQueueCallbackWrite * + QueryIQueueCallbackWrite( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackWrite *>(this); + } + + // + // IUnknown + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) { + return CUnknown::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) { + return CUnknown::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // Wdf Callbacks + // + + // IQueueCallbackDeviceIoControl + // + virtual + VOID + STDMETHODCALLTYPE + OnDeviceIoControl( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ); + + // IQueueCallbackWrite + // + virtual + VOID + STDMETHODCALLTYPE + OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToWrite + ); + + // IQueueCallbackRead + // + virtual + VOID + STDMETHODCALLTYPE + OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToRead + ); +}; diff --git a/general/echo/umdf/ReadMe.md b/general/echo/umdf/ReadMe.md new file mode 100644 index 00000000..750d34df --- /dev/null +++ b/general/echo/umdf/ReadMe.md @@ -0,0 +1,124 @@ +Echo Sample (UMDF Version 1) +============================ + +This sample demonstrates how to use User-Mode Driver Framework (UMDF) version 1 to write a driver and demonstrates best practices. + +It also demonstrates the use of a default Serial Dispatch I/O Queue, its request start events, cancellation event, and synchronizing with another thread. The preferred I/O retrieval mode is set to Direct I/O. So, whenever a request is received by the framework, UMDF looks at the size of the buffer and determines, whether it should copy the buffer (if the length is less than 2 full pages) or map it (if the length is greater or equal to 2 full pages). + +This sample driver is a minimal driver meant to demonstrate the usage of the User-Mode Driver Framework. It is not intended for use in a production environment. + + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + +Testing +------- + +To test the Echo driver, you can run echoapp.exe which is built from src\\general\\echo\\exe. + +First install the device as described above. Then run echoapp.exe. + +``` {.syntax xml:space="preserve"} +D:\>echoapp /? +Usage: +Echoapp.exe --- Send single write and read request synchronously +Echoapp.exe -Async --- Send 100 reads and writes asynchronously +Exit the app anytime by pressing Ctrl-C + +D:\>echoapp +DevicePath: \\?\root#sample#0000#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} +Opened device successfully +512 Pattern Bytes Written successfully +512 Pattern Bytes Read successfully +Pattern Verified successfully + +D:\>echoapp -Async +DevicePath: \\?\root#sample#0000#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} +Opened device successfully +Starting AsyncIo +Number of bytes written by request number 0 is 1024 +Number of bytes read by request number 0 is 1024 +Number of bytes read by request number 1 is 1024 +Number of bytes written by request number 2 is 1024 +Number of bytes read by request number 2 is 1024 +Number of bytes written by request number 3 is 1024 +Number of bytes read by request number 3 is 1024 +Number of bytes written by request number 4 is 1024 +Number of bytes read by request number 4 is 1024 +Number of bytes written by request number 5 is 1024 +Number of bytes read by request number 5 is 1024 +Number of bytes written by request number 6 is 1024 +Number of bytes read by request number 6 is 1024 +Number of bytes written by request number 7 is 1024 +Number of bytes read by request number 7 is 1024 +Number of bytes written by request number 8 is 1024 +Number of bytes read by request number 8 is 1024 +Number of bytes written by request number 9 is 1024 +Number of bytes read by request number 9 is 1024 +Number of bytes written by request number 10 is 1024 +Number of bytes read by request number 10 is 1024 +Number of bytes written by request number 11 is 1024 +... +``` + +Note that the reads and writes are performed by independent threads in the echo test application. As a result the order of the output may not exactly match what you see above. + +File Manifest +------------- + +File + +Description + +comsup.cpp & comsup.h + +COM Support code - specifically base classes which provide implementations for the standard COM interfaces IUnknown and IClassFactory which are used throughout this sample. + +The implementation of IClassFactory is designed to create instances of the CMyDriver class. If you should change the name of your base driver class, you would also need to modify this file. + +dllsup.cpp + +DLL Support code - provides the DLL's entry point as well as the single required export (DllGetClassObject). + +These depend on comsup.cpp to perform the necessary class creation. + +exports.def + +This file lists the functions that the driver DLL exports. + +internal.h + +This is the main header file for this driver. + +Driver.cpp and Driver.h + +DriverEntry and events on the driver object. + +Device.cpp and Device.h + +The Events on the device object. + +Queue.cpp and Queue.h + +Contains Events on the I/O Queue Objects. + +Echo.rc + +Resource file for the driver. + +WUDFEchoDriver.inx + +File that describes the installation of this driver. The build process converts this into an INF file. + +makefile.inc + +A makefile that defines custom build actions. This includes the conversion of the .INX file into a .INF file + +echodriver.ctl + +This file lists the WPP trace control GUID(s) for the sample driver. This file can be used with the tracelog command's -guid flag to enable the collection of these trace events within an established trace session. + +These GUIDs must remain in sync with the trace control GUIDs defined in internal.h. + diff --git a/general/echo/umdf/WUDFEchoDriver.inx b/general/echo/umdf/WUDFEchoDriver.inx new file mode 100644 index 00000000..6279783e --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.inx @@ -0,0 +1,87 @@ +; +; WUDFEchoDriver.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFTWUDF% +CatalogFile=WUDF.cat +DriverVer=03/20/2003,5.00.3788 + +[Manufacturer] +%MSFTWUDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%EchoDeviceName%=Echo_Install,WUDF\Echo + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +WUDFEchoDriver.dll=1 +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== WUDF Echo Test Driver ================================== + +[Echo_Install.NT] +CopyFiles=UMDriverCopy + +[Echo_Install.NT.hw] + +[Echo_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[Echo_Install.NT.CoInstallers] +AddReg = CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[Echo_Install.NT.Wdf] +UmdfService=WUDFEchoDriver,WUDFEchoDriver_Install +UmdfServiceOrder=WUDFEchoDriver + +; if device can do either direct i/o or buffered transfer mode, +; umdf defaults to direct i/o if devices is not pooled. +UmdfHostProcessSharing=ProcessSharingDisabled + +[WUDFEchoDriver_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID={7AB7DCF5-D1D4-4085-9547-1DB968CCA720} +ServiceBinary=%12%\UMDF\WUDFEchoDriver.dll + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + +[CoInstallers_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\UMDF +CoInstallers_CopyFiles=11 + +[UMDriverCopy] +WUDFEchoDriver.dll + +; =================== Generic ================================== + +[Strings] +MSFTWUDF="Microsoft Internal (WUDF)" +MediaDescription="Microsoft WUDF Sample Driver Installation Media" +ClassName="Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +EchoDeviceName="Sample WUDF Echo Driver" diff --git a/general/echo/umdf/WUDFEchoDriver.vcxproj b/general/echo/umdf/WUDFEchoDriver.vcxproj new file mode 100644 index 00000000..242f1dda --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj @@ -0,0 +1,256 @@ +<?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>{9E7A6816-063C-4560-A31F-C5472D1CE345}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{164B0F80-BB88-48C9-A03F-3F3937D8CCB6}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; comsup.cpp; driver.cpp; device.cpp; queue.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="WudfEchoDriver.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\WudfEchoDriver.inf</CopyOutput> + </Inf> + <OtherWpp Include="Echo.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="Echo.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters new file mode 100644 index 00000000..b702fb21 --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{0FBE107F-4905-4E97-BFF9-8C2A6B03AED8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{9534FE43-2493-4430-A335-97FC2BE106BD}</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>{A96A2015-2537-47ED-B43D-8C379EDEC69F}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{203FBCD2-49E2-491E-9D3F-03A028ED6CEE}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="comsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\WudfEchoDriver.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="WudfEchoDriver.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Echo.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf/dllsup.cpp b/general/echo/umdf/dllsup.cpp new file mode 100644 index 00000000..e7200a28 --- /dev/null +++ b/general/echo/umdf/dllsup.cpp @@ -0,0 +1,176 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Echo Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the echo driver uses + L"Microsoft\\UMDF\\Echo" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID /* Reserved */ + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER(ModuleHandle); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return TRUE; +} + +HRESULT +STDAPICALLTYPE +DllGetClassObject( + _In_ REFCLSID ClassId, + _In_ REFIID InterfaceId, + _Outptr_ LPVOID *Interface + ) +/*++ + + Routine Description: + + This routine is called by COM in order to instantiate the + driver callback object and do an initial query interface on it. + + This method only creates an instance of the driver's class factory, as this + is the minimum required to support UMDF. + + Arguments: + + ClassId - the CLSID of the object being "gotten" + + InterfaceId - the interface the caller wants from that object. + + Interface - a location to store the referenced interface pointer + + Return Value: + + S_OK if the function succeeds or error indicating the cause of the + failure. + +--*/ +{ + PCClassFactory factory; + + HRESULT hr = S_OK; + + *Interface = NULL; + + // + // If the CLSID doesn't match that of our "coclass" (defined in the IDL + // file) then we can't create the object the caller wants. This may + // indicate that the COM registration is incorrect, and another CLSID + // is referencing this drvier. + // + + if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Called to create instance of unrecognized class (%!GUID!)", + &ClassId + ); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + // + // Create an instance of the class factory for the caller. + // + + factory = new CClassFactory(); + + if (NULL == factory) + { + hr = E_OUTOFMEMORY; + } + + // + // Query the object we created for the interface the caller wants. After + // that we release the object. This will drive the reference count to + // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). + // In the later case the object is automatically deleted. + // + + if (SUCCEEDED(hr)) + { + hr = factory->QueryInterface(InterfaceId, Interface); + factory->Release(); + } + + return hr; +} diff --git a/general/echo/umdf/echo.sln b/general/echo/umdf/echo.sln new file mode 100644 index 00000000..853b7d55 --- /dev/null +++ b/general/echo/umdf/echo.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFEchoDriver", "WUDFEchoDriver.vcxproj", "{9E7A6816-063C-4560-A31F-C5472D1CE345}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.Build.0 = Debug|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.ActiveCfg = Release|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.Build.0 = Release|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.ActiveCfg = Debug|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.Build.0 = Debug|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.ActiveCfg = Release|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/echo/umdf/echodriver.ctl b/general/echo/umdf/echodriver.ctl new file mode 100644 index 00000000..a0ce2089 --- /dev/null +++ b/general/echo/umdf/echodriver.ctl @@ -0,0 +1 @@ +d93fb470-afb1-4af8-860e-75f726c66f6b WudfEchoDriverTraceGuid diff --git a/general/echo/umdf/exports.def b/general/echo/umdf/exports.def new file mode 100644 index 00000000..ec564639 --- /dev/null +++ b/general/echo/umdf/exports.def @@ -0,0 +1,10 @@ +; Echo.def : Declares the module parameters. + +; +; TODO: Change the library name here to match your binary name. +; + +LIBRARY "WUDFEchoDriver.DLL" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/general/echo/umdf/internal.h b/general/echo/umdf/internal.h new file mode 100644 index 00000000..8e5c2d60 --- /dev/null +++ b/general/echo/umdf/internal.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Echo + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Forward definitions of classes in the other header files. +// + +typedef class CMyDriver *PCMyDriver; +typedef class CMyDevice *PCMyDevice; +typedef class CMyQueue *PCMyQueue; + +// +// Define the tracing flags. +// +// TODO: Choose a different trace control GUID +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (d93fb470,afb1,4af8,860e,75f726c66f6b), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// +// TODO: Change these values to be appropriate for your driver. +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\Echo" +#define MYDRIVER_CLASS_ID {0x7ab7dcf5, 0xd1d4, 0x4085, {0x95, 0x47, 0x1d, 0xb9, 0x68, 0xcc, 0xa7, 0x20}} + +// +// Include the type specific headers. +// + +#include "comsup.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_TEST_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} diff --git a/general/echo/umdf2/ReadMe.md b/general/echo/umdf2/ReadMe.md new file mode 100644 index 00000000..e037a8b5 --- /dev/null +++ b/general/echo/umdf2/ReadMe.md @@ -0,0 +1,77 @@ +Echo Sample (UMDF Version 2) +============================ + +The ECHO (UMDF version 2) sample demonstrates how to use a sequential queue to serialize read and write requests presented to the driver. + +It also shows how to synchronize execution of these events with other asynchronous events such as request cancellation and DPC. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + + +Download and extract the sample +------------------------------- + +Click the download button on this page. Click **Save**, and then click **Open Folder**. Right click the zip file, and choose **Extract All**. Specify or browse to a folder for the extracted files. For example, you could extract to c:\\umdf2echo. + +Open the driver solution in Visual Studio +----------------------------------------- + +Navigate to the folder that has the extracted sample. Double click the solution file (umdf2echo.sln). In Microsoft Visual Studio, locate Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that contains 3 projects. There is a driver project (Driver-\>AutoSync-\>echo), an application project (Exe-\>echoapp), and a package project named **package** (lower case). + +Set the configuration and platform in Visual Studio +--------------------------------------------------- + +In Visual Studio, in Solution Explorer, right click **Solution**, and choose **Configuration Manager**. Set the configuration and the platform. Make sure that the configuration and platform are the same for both the driver project and the package project. Do not check the **Deploy** boxes. Because this solution uses UMDF version 2, you cannot select a configuration earlier than Windows 8.1. + + +Locate the built driver package +------------------------------- + +In File Explorer, navigate to the folder that contains your built driver package. The location of this folder varies depending on what you set for configuration and platform. For example, if your settings are Win8.1 Debug and x64, the package is in your solution folder under x64\\Win8.1Debug\\Package. + +Run the sample +-------------- + +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. + +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy a driver sample automatically or manually. + +### Automatic deployment (root enumerated) + +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). + +1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter **root\\ECHO** for the hardware ID. Click **OK**. +3. On the **Build** menu, choose **Build Solution**. + +### Manual deployment (root enumerated) + +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). + +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\umdf2echoPkg). +2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command: + + **devcon install echoum.inf root\\ECHO** + +### View the root enumerated driver in Device Manager + +On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **Sample WDF ECHO Driver** (for example, this might be under the **Sample Device** node). + +In Device Manager, on the **View** menu, choose **Devices by connection**. Locate **Sample WDF ECHO Driver** as a child of the root node of the device tree. + +Build the sample using MSBuild +------------------------------ + +As an alternative to building the driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, umdf2echo.sln. Use the MSBuild command to build the solution. Here is an example: + +**msbuild /p:configuration=”Win8 Release” /p:platform=”Win32” umdf2echo.sln** + +For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + 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; diff --git a/general/echo/umdf2/exe/echoapp.cpp b/general/echo/umdf2/exe/echoapp.cpp new file mode 100644 index 00000000..9649a407 --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.cpp @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ioctl.cpp + +Abstract: + + A simple asynch test for usb driver. + + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include "public.h" + +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE (40*1024) + +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +#define MAX_DEVPATH_LENGTH 256 + +BOOLEAN G_PerformAsyncIo; +BOOLEAN G_LimitedLoops; +ULONG G_AsyncIoLoopsNum; +CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; + + +ULONG +AsyncIo( + PVOID ThreadParameter + ); + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ); + + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE th1 = NULL; + BOOLEAN result = TRUE; + + + if (argc > 1) { + if(!_strnicmp (argv[1], "-Async", 6) ) { + G_PerformAsyncIo = TRUE; + if (argc > 2) { + G_AsyncIoLoopsNum = atoi(argv[2]); + G_LimitedLoops = TRUE; + } + else { + G_LimitedLoops = FALSE; + } + + } else { + printf("Usage:\n"); + printf(" Echoapp.exe --- Send single write and read request synchronously\n"); + printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); + printf(" Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\n"); + printf("Exit the app anytime by pressing Ctrl-C\n"); + result = FALSE; + goto exit; + } + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_ECHO, + G_DevicePath, + sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) + { + result = FALSE; + goto exit; + } + + printf("DevicePath: %s\n", G_DevicePath); + + hDevice = CreateFile(G_DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + result = FALSE; + goto exit; + } + + printf("Opened device successfully\n"); + + if(G_PerformAsyncIo) { + + printf("Starting AsyncIo\n"); + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + result = FALSE; + goto exit; + } + + // + // Use this thread for peforming write. + // + result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); + + }else { + // + // Write pattern buffers and read them back, then verify them + // + result = PerformWriteReadTest(hDevice, 512); + if(!result) { + goto exit; + } + + result = PerformWriteReadTest(hDevice, 30*1024); + if(!result) { + goto exit; + } + + } + +exit: + + if (th1 != NULL) { + WaitForSingleObject(th1, INFINITE); + CloseHandle(th1); + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + return ((result == TRUE) ? 0 : 1); + +} + +PUCHAR +CreatePatternBuffer( + IN ULONG Length + ) +{ + unsigned int i; + PUCHAR p, pBuf; + + pBuf = (PUCHAR)malloc(Length); + if( pBuf == NULL ) { + printf("Could not allocate %d byte buffer\n",Length); + return NULL; + } + + p = pBuf; + + for(i=0; i < Length; i++ ) { + *p = (UCHAR)i; + p++; + } + + return pBuf; +} + +BOOLEAN +VerifyPatternBuffer( + _In_reads_bytes_(Length) PUCHAR pBuffer, + _In_ ULONG Length + ) +{ + unsigned int i; + PUCHAR p = pBuffer; + + for( i=0; i < Length; i++ ) { + + if( *p != (UCHAR)(i & 0xFF) ) { + printf("Pattern changed. SB 0x%x, Is 0x%x\n", + (UCHAR)(i & 0xFF), *p); + return FALSE; + } + + p++; + } + + return TRUE; +} + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ) +/* +*/ +{ + ULONG bytesReturned =0; + PUCHAR WriteBuffer = NULL, + ReadBuffer = NULL; + BOOLEAN result = TRUE; + + WriteBuffer = CreatePatternBuffer(TestLength); + if( WriteBuffer == NULL ) { + + result = FALSE; + goto Cleanup; + } + + ReadBuffer = (PUCHAR)malloc(TestLength); + if( ReadBuffer == NULL ) { + + printf("PerformWriteReadTest: Could not allocate %d " + "bytes ReadBuffer\n",TestLength); + + result = FALSE; + goto Cleanup; + + } + + // + // Write the pattern to the device + // + bytesReturned = 0; + + if (!WriteFile ( hDevice, + WriteBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: WriteFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes written is not test length! Written %d, " + "SB %d\n",bytesReturned, TestLength); + + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Written successfully\n", + bytesReturned); + } + + bytesReturned = 0; + + if ( !ReadFile (hDevice, + ReadBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: ReadFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes Read is not test length! Read %d, " + "SB %d\n",bytesReturned, TestLength); + + // + // Note: Is this a Failure Case?? + // + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Read successfully\n",bytesReturned); + } + + // + // Now compare + // + if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { + + printf("Verify failed\n"); + + result = FALSE; + goto Cleanup; + } + + printf("Pattern Verified successfully\n"); + +Cleanup: + + // + // Free WriteBuffer if non NULL. + // + if (WriteBuffer) { + free (WriteBuffer); + } + + // + // Free ReadBuffer if non NULL + // + if (ReadBuffer) { + free (ReadBuffer); + } + + return result; +} + + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG numberOfBytesTransferred; + OVERLAPPED *completedOv; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG_PTR key; + ULONG error; + BOOLEAN result = TRUE; + ULONG maxPendingRequests = NUM_ASYNCH_IO; + ULONG remainingRequestsToSend = 0; + ULONG remainingRequestsToReceive = 0; + + hDevice = CreateFile(G_DevicePath, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + result = FALSE; + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + result = FALSE; + goto Error; + } + + // + // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any + // time (whichever is less) + // + if (G_LimitedLoops == TRUE) { + remainingRequestsToReceive = G_AsyncIoLoopsNum; + if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { + // + // After we send the initial NUM_ASYNCH_IO, we will have additional + // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send + // + maxPendingRequests = NUM_ASYNCH_IO; + remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; + } + else { + maxPendingRequests = G_AsyncIoLoopsNum; + remainingRequestsToSend = 0; + + } + } + + pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + result = FALSE; + goto Error; + } + + buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + result = FALSE; + goto Error; + } + + ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); + ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < maxPendingRequests; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Read failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Write failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + result = FALSE; + goto Error; + } + + // + // Read successfully completed. If we're doing unlimited I/Os then Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + printf("Number of bytes read by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%dth Read failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + + printf("%dth write failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + +Error: + if(hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if(hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if(buf) { + free(buf); + } + if(pOvList) { + free(pOvList); + } + + return (ULONG)result; + +} + + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ) +{ + HDEVINFO HardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL; + ULONG Length, RequiredLength = 0; + BOOL bResult; + HRESULT hr; + + HardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed!\n"); + return FALSE; + } + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, + 0, + InterfaceGuid, + 0, + &DeviceInterfaceData); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + printf("SetupDiEnumDeviceInterfaces failed.\n"); + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + return FALSE; + } + + SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + NULL, + 0, + &RequiredLength, + NULL + ); + + DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength); + + if (DeviceInterfaceDetailData == NULL) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Failed to allocate memory.\n"); + return FALSE; + } + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Length = RequiredLength; + + bResult = SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + Length, + &RequiredLength, + NULL); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); + LocalFree(DeviceInterfaceDetailData); + LocalFree(lpMsgBuf); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath) ; + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces + LocalFree(DeviceInterfaceDetailData); + + return ( !FAILED(hr) ); // Result depends on StringCchCopy() +} + diff --git a/general/echo/umdf2/exe/echoapp.vcxproj b/general/echo/umdf2/exe/echoapp.vcxproj new file mode 100644 index 00000000..c8b2000b --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.vcxproj @@ -0,0 +1,171 @@ +<?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>{2744B9D7-C918-4979-AF41-3DC6B305BA72}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{725C57DF-D40D-4503-ADBE-A694D0AC15A8}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</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" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp" /> + </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/exe/echoapp.vcxproj.Filters b/general/echo/umdf2/exe/echoapp.vcxproj.Filters new file mode 100644 index 00000000..1b67a921 --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{A27E5252-132E-4B45-BC34-E21958A5A7B8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{21C62558-1F78-4174-BB6A-42FE9F273912}</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>{D51D868F-D9FD-45A5-B7C1-50CBFF474959}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf2/exe/public.h b/general/echo/umdf2/exe/public.h new file mode 100644 index 00000000..d632951d --- /dev/null +++ b/general/echo/umdf2/exe/public.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + + +Environment: + + user and kernel + +--*/ + +#define WHILE(a) \ +__pragma(warning(suppress:4127)) while(a) + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + diff --git a/general/echo/umdf2/umdf2echo.sln b/general/echo/umdf2/umdf2echo.sln new file mode 100644 index 00000000..f7467745 --- /dev/null +++ b/general/echo/umdf2/umdf2echo.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{5B8D0286-7445-4569-84C3-D5616997F792}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{0E50C291-4877-4FE5-A66C-EDEFF747DA75}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{2744B9D7-C918-4979-AF41-3DC6B305BA72}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{95360722-8B66-4DD4-957A-DF8B7CA700FB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.ActiveCfg = Debug|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.Build.0 = Debug|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.ActiveCfg = Release|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.Build.0 = Release|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.ActiveCfg = Debug|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.Build.0 = Debug|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.ActiveCfg = Release|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.Build.0 = Release|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.ActiveCfg = Debug|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.Build.0 = Debug|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.ActiveCfg = Release|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.Build.0 = Release|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.ActiveCfg = Debug|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.Build.0 = Debug|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.ActiveCfg = Release|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2744B9D7-C918-4979-AF41-3DC6B305BA72} = {5B8D0286-7445-4569-84C3-D5616997F792} + {95360722-8B66-4DD4-957A-DF8B7CA700FB} = {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} + {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} = {0E50C291-4877-4FE5-A66C-EDEFF747DA75} + EndGlobalSection +EndGlobal diff --git a/general/echo/umdfSocketEcho/Driver/Connection.cpp b/general/echo/umdfSocketEcho/Driver/Connection.cpp new file mode 100644 index 00000000..e28d0c56 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Connection.cpp @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Connection.cpp + +Abstract: + + Module for the socket connection specfic routines in the driver. + Makes Connection to the server given server host and port address. + +Environment: + + User mode only + + +--*/ + +#include "internal.h" +#include "connection.tmh" + + +CConnection::CConnection() +/*++ + +Routine Description: + + Constructor for connection object + +Arguments: + + None + +Return Value: + + VOID + +--*/ +{ + + // Initialize the socket member as Invalid + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + m_socket = INVALID_SOCKET; +} + +HRESULT +CConnection::Connect( + IN IWDFDevice *pDevice + ) +/*++ + +Routine Description: + + This routine is for the initialization of the connection object associated with + the File Object . It is invoked from the dispatch OnCreateFile on the default + queue callback of the driver. It socket connection to the client. + +Arguments: + + pDevice = Wdf Device Object + +Return Value: + + S_OK if success , error HRESULT otherwise + +--*/ +{ + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + addrinfoW* info = NULL ; + + PWSTR hostStr = NULL; + + PWSTR portStr = NULL; + + // + // Reads the host and port strings stored in the device context. + // + + DeviceContext *pContext = NULL; + + hr = pDevice->RetrieveContext((void**)&pContext); + + if ( FAILED(hr) ) + { + + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: unable to retrieve context from wdf device object %!hresult!", + hr + ); + goto Clean0; + + } + + hostStr = pContext->hostStr; + + portStr = pContext->portStr; + + // + // lookup hostname with addrinfo hints; + // + + addrinfoW hints; + + ZeroMemory(&hints,sizeof(hints)); + + hints.ai_family = AF_INET; + + hints.ai_socktype = SOCK_STREAM; + + hints.ai_protocol = IPPROTO_TCP; + + int n = GetAddrInfoW(hostStr, portStr, &hints, &info); + + if (n != 0) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to find address/port of host %!winerr!", + err + ); + hr = HRESULT_FROM_WIN32(err); + goto Clean0; + } + + // + // Create a socket with this infomation recvd in getaddrinfo + // + m_socket = socket(info->ai_family,info->ai_socktype,info->ai_protocol); + + if (m_socket == INVALID_SOCKET) + { + DWORD err = WSAGetLastError(); + + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to create socket %!winerr!", + err + ); + + hr = HRESULT_FROM_WIN32(err); + + goto Clean0; + } + + // + // If that succeeds , proceed to connect to the socket + // + + + ATLASSERT(info->ai_addrlen <= 0x7fffffff); + + int nret = connect(m_socket,info->ai_addr,(int)info->ai_addrlen); + + if (nret == SOCKET_ERROR) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to connect to host %!winerr!", + err + ); + hr = HRESULT_FROM_WIN32(err); + + goto Clean0; + } + + +Clean0: + + if (info != NULL) + { + FreeAddrInfoW(info); + + } + + if (FAILED(hr) && m_socket != INVALID_SOCKET) + { + closesocket(m_socket); + m_socket = INVALID_SOCKET; + } + + return hr; + +} + +HANDLE +CConnection::GetSocketHandle( + ) +/*++ + +Routine Description: + + Function returns the socket handle associated with this connection object + +Arguments: + + None + +Return Value: + + Socket handle if valid socket + INVALID_HANDLE_VALUE otherwise + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + if ( INVALID_SOCKET != m_socket ) + { + return (HANDLE)m_socket ; + } + else + { + return INVALID_HANDLE_VALUE; + } + +} + + +VOID +CConnection::Close() +/*++ + +Routine Description: + + Closes the socket connection to the server associated with this connection object + +Arguments: + + None + +Return Value: + + None +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + if (m_socket != INVALID_SOCKET) + { + closesocket(m_socket); + m_socket = INVALID_SOCKET; + } + +} diff --git a/general/echo/umdfSocketEcho/Driver/FileContext.h b/general/echo/umdfSocketEcho/Driver/FileContext.h new file mode 100644 index 00000000..dbdda2e4 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/FileContext.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + filecontext.h + +Abstract: + + This header file defines the structure type for file context associated with the file object + +Environment: + + user mode only + +Revision History: + +--*/ + + +#pragma once + +typedef struct _FileContext +{ + CConnection *pConnection ; + + CComPtr<IWDFIoTarget> pFileTarget; + +}FileContext; diff --git a/general/echo/umdfSocketEcho/Driver/Queue.cpp b/general/echo/umdfSocketEcho/Driver/Queue.cpp new file mode 100644 index 00000000..242925d4 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Queue.cpp @@ -0,0 +1,580 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "internal.h" + +#include "queue.tmh" + +CMyQueue::CMyQueue( + ) : + m_FxQueue(NULL), + m_Device(NULL) +{ +} + +// +// Queue destructor. +// + +CMyQueue::~CMyQueue( + VOID + ) +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); +} + +// +// Initialize +// + +HRESULT +CMyQueue::Initialize( + _In_ CMyDevice * Device + ) +/*++ + +Routine Description: + + Queue Initialize helper routine. + This routine will Create a default parallel queue associated with the Fx device object + and pass the IUnknown for this queue + +Aruments: + Device - Device object pointer + +Return Value: + + S_OK if Initialize succeeds + +--*/ +{ + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + CComPtr<IWDFIoQueue> fxQueue; + + HRESULT hr; + + m_Device = Device; + + // + // Create the I/O Queue object. + // + + { + CComPtr<IUnknown> pUnk; + + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = m_Device->GetFxDevice()->CreateIoQueue( + pUnk, + TRUE, + WdfIoQueueDispatchParallel, + TRUE, + FALSE, + &fxQueue + ); + } + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + "Failed to initialize driver queue %!hresult!", + hr + ); + goto Exit; + } + + m_FxQueue = fxQueue; + + +Exit: + + return hr; +} + +HRESULT +CMyQueue::Configure( + VOID + ) +/*++ + +Routine Description: + + Queue configuration function . + It is called after queue object has been succesfully initialized. + +Aruments: + + NONE + + Return Value: + + S_OK if succeeds. + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + return hr; +} + + +STDMETHODIMP_(void) +CMyQueue::OnCreateFile( + _In_ IWDFIoQueue* pWdfQueue, + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFFile* pWdfFileObject + ) + +/*++ + +Routine Description: + + Create callback from the framework for this default parallel queue + + The create request will create a socket connection , create a file i/o target associated + with the socket handle for this connection and store in the file object context. + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + pWdfFileObject - WDF file object for this create + + Return Value: + + VOID + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + CComPtr<IWDFFileHandleTargetFactory> spFileHandleTargetFactory; + + CComPtr<IWDFIoTarget> pFileTarget; + + CComPtr<IWDFDevice> pDevice; + + HANDLE SocketHandle = NULL; + + pWdfQueue->GetDevice(&pDevice); + + FileContext *pContext = NULL; + + // + // Create new connection object + // + + CConnection *pConnection = new CConnection(); + + if (NULL == pConnection ) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not create connection object %!hresult!", + hr + ); + goto Exit; + } + + // + // Connect to the socket server + // + + hr = pConnection->Connect(pDevice); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not connect %!hresult!", + hr + ); + + goto Exit; + + } + + // + // If that succeeds, get socket handle for the connection + // + + if ( NULL == (SocketHandle = pConnection->GetSocketHandle()) ) + { + hr = E_FAIL; + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to obtain valid Socket Handle %!hresult!", + hr + ); + goto Exit; + } + + // + // Create file context for this file object + // + + pContext = new FileContext; + + if (NULL == pContext) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not create file context %!hresult!", + hr + ); + goto Exit; + + } + + // + // QI for IWDFFileHandleTargetFactory from the framework device object. + // Note UmdfDispatcher in Wdf Section in the Inf + // + + hr = pDevice->QueryInterface(IID_PPV_ARGS(&spFileHandleTargetFactory)); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to obtain target factory for creating FileHandle based I/O target %!hresult!", + hr + ); + goto Exit; + } + + // + // If that succeeds, Create a File Handle I/O Target and associate the socket handle with this target + // + + hr = spFileHandleTargetFactory->CreateFileHandleTarget(SocketHandle ,&pFileTarget); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to create framework I/O target %!hresult!", + hr + ); + goto Exit; + } + + + pContext->pFileTarget = pFileTarget; + + pContext->pConnection = pConnection; + + hr = pWdfFileObject->AssignContext(NULL,(void*)pContext); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to Assign Context to this File Object %!hresult!", + hr + ); + goto Exit; + } + + + +Exit: + + if (FAILED(hr)) + { + + if ( pFileTarget ) + { + pFileTarget->DeleteWdfObject(); + } + + if (pConnection != NULL) + { + delete pConnection; + pConnection = NULL; + } + + if (pContext != NULL) + { + delete pContext; + pContext = NULL; + } + + } + + pWdfRequest->Complete(hr); + +} + + +STDMETHODIMP_ (void) +CMyQueue::OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToWrite + ) +/*++ + +Routine Description: + + Write callback from the framework for this default parallel queue + + The write request needs to be sent to the file handle i/o target associated with this fileobject + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToWrite - Lenth of bytes in the write buffer + + Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(BytesToWrite); + + // Call helper function to send request to i/o target + + SendRequestToFileTarget(pWdfRequest); + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + return; +} + +STDMETHODIMP_ (void) +CMyQueue::OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToRead + ) +/*++ + +Routine Description: + + Read callback from the framework for this default parallel queue + + The read request needs to be sent to the file handle i/o target associated with this fileobject + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToRead - Lenth of bytes in the read buffer + + +Return Value: + + VOID + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(BytesToRead); + + // + // Call helper function to send request to i/o target + // + + SendRequestToFileTarget(pWdfRequest); + + return; +} + +STDMETHODIMP_(void) +CMyQueue::OnCompletion( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFIoTarget* pTarget, + _In_ IWDFRequestCompletionParams* pCompletionParams, + _In_ void* pContext +) +/*++ + +Routine Description: + + This routine is invoked when the request is completed by the lower stack location, + in this case the win32 i/o target associated with the file object of this request + + + Arguments: + + pWdfRequest - wdf request + pTarget - wdf target to which request was earlier sent + pCompletionParams - wdf request completion parameters + pContext - Context information , if any + + +Return Value: + + None +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pTarget); + UNREFERENCED_PARAMETER(pContext); + + // Complete request from the driver + pWdfRequest->CompleteWithInformation( + pCompletionParams->GetCompletionStatus(), + pCompletionParams->GetInformation()); +} + +VOID +CMyQueue::SendRequestToFileTarget( + _In_ IWDFIoRequest* pWdfRequest +) +/*++ + +Routine Description: + + This is a helper functiom to send R/W requests to the win32 file i/o target + associated with the socket connection for this request. + First, filecontext is retrieved which has the file i/o target where this request needs to be sent. + + +Arguments: + + pWdfRequest - wdf request + +Return Value: + + None + +--*/ +{ + + HRESULT hr; + + FileContext *pContext = NULL; + CComPtr<IWDFFile> pWdfFile = NULL; + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + // + // Get the file object for this request + // + + pWdfRequest->GetFileObject(&pWdfFile); + + // + // Retrieve Context from file object + // + + hr = pWdfFile->RetrieveContext((void**)&pContext); + + if (pContext == NULL) + { + if ( SUCCEEDED(hr) ) + { + hr = E_FAIL; + Trace(TRACE_LEVEL_ERROR, + " No Context associated with this file object %!hresult!", + hr); + } + goto Exit; + } + + // + // If that succeeds, set completion callback for the request + // + pWdfRequest->SetCompletionCallback(CComQIPtr<IRequestCallbackRequestCompletion>(this), + NULL); + + // + // Do not modify the request, format using current type + // + + pWdfRequest->FormatUsingCurrentType(); + + // + // Send the request to the win32 i/o target . This was created in OnCreateFile + // + + hr = pWdfRequest->Send(pContext->pFileTarget, + 0, + 0); +Exit: + + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Could not send request to i/o target %!hresult!", + hr); + pWdfRequest->Complete(hr); + } + + return ; +} + +STDMETHODIMP_(void) +CMyQueue::OnCleanup( + _In_ IWDFObject* /*pWdfObject*/ + ) +{ + // + // CMyQueue has a reference to framework device object via m_FxQueue. + // Framework queue object has a reference to CMyQueue object via the callbacks. + // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. + // To break the circular reference we release the reference to the framework queue object here in OnCleanup. + // + m_FxQueue = NULL; +} diff --git a/general/echo/umdfSocketEcho/Driver/Queue.h b/general/echo/umdfSocketEcho/Driver/Queue.h new file mode 100644 index 00000000..952e1e0d --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Queue.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + user mode only + +Revision History: + +--*/ + +#pragma once + +// +// Queue Callback Object. +// + +class ATL_NO_VTABLE CMyQueue : + public CComObjectRootEx<CComMultiThreadModel>, + public IQueueCallbackCreate, + public IQueueCallbackRead, + public IQueueCallbackWrite, + public IRequestCallbackRequestCompletion, + public IObjectCleanup +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyQueue) + +BEGIN_COM_MAP(CMyQueue) + COM_INTERFACE_ENTRY(IQueueCallbackCreate) + COM_INTERFACE_ENTRY(IQueueCallbackRead) + COM_INTERFACE_ENTRY(IQueueCallbackWrite) + COM_INTERFACE_ENTRY(IRequestCallbackRequestCompletion) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + //IQueueCallbackRead + STDMETHOD_(void,OnRead)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWdfRequest,_In_ SIZE_T NumOfBytesToRead); + + //IQueueCallbackWrite + STDMETHOD_(void,OnWrite)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWdfRequest,_In_ SIZE_T NumOfBytesToWrite); + + //IQueueCallbackCreate + STDMETHOD_(void,OnCreateFile)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWDFRequest,_In_ IWDFFile* pWdfFileObject); + + // IRequestCallbackRequestCompletion + STDMETHOD_(void,OnCompletion)(_In_ IWDFIoRequest* pWdfRequest,_In_ IWDFIoTarget* pTarget,_In_ IWDFRequestCompletionParams* pCompletionParams,_In_ void* pContext); + + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + +public: + CMyQueue(); + ~CMyQueue(); + + STDMETHOD(Initialize)(_In_ CMyDevice * Device); + + HRESULT + Configure( + ); + +private: + CComPtr<IWDFIoQueue> m_FxQueue; + + // + // Unreferenced pointer to the parent device. + // + + CMyDevice * m_Device; + + VOID SendRequestToFileTarget( _In_ IWDFIoRequest* pWdfRequest); +}; diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.inx b/general/echo/umdfSocketEcho/Driver/SocketEcho.inx new file mode 100644 index 00000000..d9ed27ea --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.inx @@ -0,0 +1,89 @@ +; +; SocketEcho.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +CatalogFile=wudf.cat +DriverVer=03/20/2003,5.00.3788 + +[Manufacturer] +%MSFTWUDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%SocketEchoName%=SocketEcho_Install,WUDF\SocketEcho + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 +SocketEcho.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== WUDF SocketEcho Test Driver ================================== + +[SocketEcho_Install] +CopyFiles=UMDFDriverCopy + +[SocketEcho_Install.hw] +AddReg=SocketEcho_AddReg + +[SocketEcho_Install.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[SocketEcho_Install.CoInstallers] +AddReg = SocketEcho_Install.CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[SocketEcho_Install.CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + + + +[CoInstallers_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[SocketEcho_Install.Wdf] +UmdfService=SocketEcho, SocketEcho_Driver_Install +UmdfServiceOrder=SocketEcho +UmdfDispatcher=FileHandle + +[SocketEcho_AddReg] +HKR,"SocketEcho","Host",0x00000000,"localhost" +HKR,"SocketEcho","Port",0x00000000,"6000" + +[WUDFRD_ServiceInstall] +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\WUDFRd.sys + +[SocketEcho_Driver_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID="{83B87D35-76B8-4920-B43C-3BDE6B0EC5B8}" +ServiceBinary="%12%\UMDF\SocketEcho.dll" + +[DestinationDirs] +UMDFDriverCopy=12,UMDF + +[UMDFDriverCopy] +SocketEcho.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +; =================== Generic ================================== + +[Strings] +MSFT="Microsoft" +MSFTWUDF="Microsoft Internal (WUDF)" +MediaDescription="Microsoft WUDF Sample Driver Installation Media" +ClassName="Sample Device" +SocketEchoName="Sample WUDF SocketEcho Driver" diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.rc b/general/echo/umdfSocketEcho/Driver/SocketEcho.rc new file mode 100644 index 00000000..cc27b15f --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// Skeleton.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Sample WUDF SocketEcho Driver" +#define VER_INTERNALNAME_STR "SocketEcho" +#define VER_ORIGINALFILENAME_STR "SocketEcho.dll" + +#include "common.ver" diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj new file mode 100644 index 00000000..d9930170 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj @@ -0,0 +1,245 @@ +<?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>{ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{DA04694B-6179-416F-83FF-53A671E51B26}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; driver.cpp; device.cpp; queue.cpp; connection.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="SocketEcho.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\SocketEcho.inf</CopyOutput> + </Inf> + <OtherWpp Include="SocketEcho.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="SocketEcho.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters new file mode 100644 index 00000000..539cbe3b --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{BEDB1CCE-4E58-4AE0-B5B6-C54C6159232D}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{07B8152F-B3FA-4EA1-BBCD-EABDD1B7FCAB}</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>{61C11142-602D-496E-B9EB-516ED5D7685B}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{2BB65E51-CB92-4484-AD29-5ED2A6007684}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="connection.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\SocketEcho.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="SocketEcho.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="SocketEcho.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdfSocketEcho/Driver/connection.h b/general/echo/umdfSocketEcho/Driver/connection.h new file mode 100644 index 00000000..2b7e23c6 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/connection.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Connection.h + +Abstract: + + Header file for the socketecho connection class + +Environment: + + User mode only + + +--*/ +#pragma once + +class CConnection +{ +public: + CConnection(); + HRESULT Connect(IN IWDFDevice *pDevice); + VOID Close(); + HANDLE GetSocketHandle( ); + +private: + SOCKET m_socket; +}; + diff --git a/general/echo/umdfSocketEcho/Driver/device.cpp b/general/echo/umdfSocketEcho/Driver/device.cpp new file mode 100644 index 00000000..9c3e4db1 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/device.cpp @@ -0,0 +1,469 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF socketecho sample + driver's device callback object. + + It does not implement either of the PNP interfaces so once the device + is setup, it won't ever get any callbacks until the device is removed. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "device.tmh" + +const GUID GUID_DEVINTERFACE_SOCKETECHO = + {0xcdc35b6e, 0xbe4, 0x4936, { 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a }}; + + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver* FxDriver, + _In_ IWDFDeviceInitialize* FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + FxDriver - IWDF Driver for this device. + + Return Value: + + status. + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + CComPtr<IWDFDevice> fxDevice; + HRESULT hr; + BOOL bFilter = FALSE; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set the locking model + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // Mark filter if we are a filter + // + + if (bFilter) + { + FxDeviceInit->SetFilter(); + } + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + CComPtr<IUnknown> pUnk; + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = FxDriver->CreateDevice(FxDeviceInit, pUnk, &fxDevice); + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + None + + Return Value: + + status + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr; + CComObject<CMyQueue> * defaultQueue = NULL; + + // + // Create a new instance of our queue callback object + // + hr = CComObject<CMyQueue>::CreateInstance(&defaultQueue); + + if (SUCCEEDED(hr)) + { + defaultQueue->AddRef(); + hr = defaultQueue->Initialize(this); + } + + if (SUCCEEDED(hr)) + { + hr = defaultQueue->Configure(); + } + + // + // Create and Enable Device Interface for this device. + // + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_SOCKETECHO, + NULL); + } + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_SOCKETECHO, + NULL, + TRUE); + } + + if (SUCCEEDED(hr)) + { + hr = ReadAndAssignPropertyStoreValue(); + } + + // + // Release the reference we took on the queue callback object. + // The framework took its own references on the object's callback interfaces + // when we called m_FxDevice->CreateIoQueue, and will manage the object's lifetime. + // + SAFE_RELEASE(defaultQueue); + + return hr; +} + +STDMETHODIMP_(void) +CMyDevice::OnCloseFile( + _In_ IWDFFile* pWdfFileObject + ) +/*++ + + Routine Description: + + This method is called when an app closes the file handle to this device. + This will free the context memory associated with this file object, close + the connection object associated with this file object and delete the file + handle i/o target object associated with this file object. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr = S_OK ; + FileContext *pContext = NULL; + + hr = pWdfFileObject->RetrieveContext((void**)&pContext); + + if (SUCCEEDED(hr) && (pContext != NULL ) ) + { + pContext->pConnection->Close(); + pContext->pFileTarget->DeleteWdfObject(); + + delete pContext->pConnection; + delete pContext; + } + + return ; +} + + +STDMETHODIMP_(void) +CMyDevice::OnCleanupFile( + _In_ IWDFFile* pWdfFileObject + ) +/*++ + + Routine Description: + + This method is when app with open handle device terminates. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfFileObject); +} + +STDMETHODIMP_(void) +CMyDevice::OnCleanup( + _In_ IWDFObject* pWdfObject + ) +/*++ + + Routine Description: + + This device callback method is invoked by the framework when the WdfObject + is about to be released by the framework. This will free the context memory + associated with the device object. + + Arguments: + + pWdfObject - the framework device object for which OnCleanup. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr ; + DeviceContext *pContext = NULL; + + WUDF_SAMPLE_DRIVER_ASSERT(pWdfObject == m_FxDevice); + + hr = pWdfObject->RetrieveContext((void**)&pContext); + + if (SUCCEEDED(hr) && (pContext != NULL)) + { + // hostStr is allocated through StrDup, and thus need be freed through LocalFree + // + if (pContext->hostStr != NULL) + { + LocalFree( pContext->hostStr ); + } + + if (pContext->portStr != NULL) + { + LocalFree( pContext->portStr ); + } + + delete pContext; + } +// +//CMyDevice has a reference to framework device object via m_Device. +//Framework device object has a reference to CMyDevice object via the callbacks. +//This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. +//To break the circular reference we release the reference to the framework device object here in OnCleanup. + + m_FxDevice = NULL; +} + +HRESULT +CMyDevice::ReadAndAssignPropertyStoreValue( + VOID + ) +/*++ + + Routine Description: + Helper function for reading property store values and storing them in the + device level context. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + CComPtr<IWDFNamedPropertyStore> pPropStore; + WDF_PROPERTY_STORE_DISPOSITION disposition; + PROPVARIANT val; + HRESULT hr ; + + PropVariantInit(&val); + + DeviceContext *pContext = new DeviceContext; + if (pContext == NULL) + { + hr = E_OUTOFMEMORY; + Trace(TRACE_LEVEL_ERROR, + L"ERROR: Could not create device context object %!hresult!", + hr); + + goto CleanUp; + } + + pContext->hostStr = NULL; + pContext->portStr = NULL; + + // + // Retreive property store for reading drivers custom settings as specified + // in the INF + // + hr = m_FxDevice->RetrieveDevicePropertyStore(L"SocketEcho", + WdfPropertyStoreNormal, + &pPropStore, + &disposition); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to retrieve device property store for reading custom " + "settings as specified in the INF %!hresult!", + hr); + + goto CleanUp; + } + + // + // Get the key for this device with Named value "host" + // + hr = pPropStore->GetNamedValue(L"Host", &val); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to get \"Host\" key value %!hresult!", + hr); + + goto CleanUp; + } + + if (val.vt != VT_LPWSTR) + { + hr = HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION); + Trace(TRACE_LEVEL_ERROR, + "Unexpected string format for value in \"Host\" key %!hresult!", + hr); + + goto CleanUp; + } + + pContext->hostStr = StrDup(val.pwszVal); + + // + // Clear property variant for reading next key + // + PropVariantClear(&val); + + // + // Get the key for this device with Named value "Port" + // + hr = pPropStore->GetNamedValue(L"Port", &val); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to get \"Port\" key value %!hresult!", + hr); + + goto CleanUp; + } + + if (val.vt != VT_LPWSTR) + { + hr = HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION); + Trace(TRACE_LEVEL_ERROR, + "Unexpected string format for value in \"Port\" key %!hresult!", + hr); + + goto CleanUp; + } + + pContext->portStr = StrDup(val.pwszVal); + + hr = m_FxDevice->AssignContext(NULL, (void*)pContext); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to assign property store value to device %!hresult!", + hr); + + // + // Fall through to clean up and exit ... + // + } + +CleanUp: + + PropVariantClear(&val); + + if (FAILED(hr)) + { + if (pContext != NULL) + { + // hostStr is allocated through StrDup, and thus need be freed through LocalFree + // + if (pContext->hostStr != NULL) + { + LocalFree( pContext->hostStr ); + } + + if (pContext->portStr != NULL) + { + LocalFree( pContext->portStr ); + } + + delete pContext; + } + } + + return hr; +} + diff --git a/general/echo/umdfSocketEcho/Driver/device.h b/general/echo/umdfSocketEcho/Driver/device.h new file mode 100644 index 00000000..176f10e6 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/device.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF Skeleton sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Class for the iotrace driver. +// + +class ATL_NO_VTABLE CMyDevice : + public CComObjectRootEx<CComMultiThreadModel>, + public IFileCallbackCleanup, + public IFileCallbackClose, + public IObjectCleanup +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDevice) + +BEGIN_COM_MAP(CMyDevice) + COM_INTERFACE_ENTRY(IFileCallbackCleanup) + COM_INTERFACE_ENTRY(IFileCallbackClose) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + + //IFileCallbackCleanup + STDMETHOD_(void,OnCleanupFile)(_In_ IWDFFile* pWdfFileObject); + //IFileCallbackClose + STDMETHOD_(void,OnCloseFile)(_In_ IWDFFile* pWdfFileObject); + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + +public: + + STDMETHOD(Initialize)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + + HRESULT + Configure( + ); + + IWDFDevice * + GetFxDevice( + ) + { + return m_FxDevice; + } + +private: + CComPtr<IWDFDevice> m_FxDevice; + HRESULT ReadAndAssignPropertyStoreValue(); + +}; diff --git a/general/echo/umdfSocketEcho/Driver/devicecontext.h b/general/echo/umdfSocketEcho/Driver/devicecontext.h new file mode 100644 index 00000000..2bf10d2e --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/devicecontext.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + devicecontext.h + +Abstract: + + This header file defines the structure type for device context associated with the device object + +Environment: + + user mode only + +Revision History: + +--*/ + + +#pragma once + + +typedef struct _DeviceContext +{ + PWSTR hostStr; + + PWSTR portStr; + +}DeviceContext; + diff --git a/general/echo/umdfSocketEcho/Driver/dllsup.cpp b/general/echo/umdfSocketEcho/Driver/dllsup.cpp new file mode 100644 index 00000000..5ec3eb33 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/dllsup.cpp @@ -0,0 +1,111 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Socktecho Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the socktecho uses + L"Microsoft\\UMDF\\Socketecho" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +class CSocketEchoModule : public CAtlDllModuleT< CSocketEchoModule > +{ +}; + + +OBJECT_ENTRY_AUTO(CLSID_MyDriverCoClass, CMyDriver) + + +CSocketEchoModule _AtlModule; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID Reserved + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER( ModuleHandle ); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return _AtlModule.DllMain(Reason, Reserved); +; +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) +{ + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} diff --git a/general/echo/umdfSocketEcho/Driver/driver.cpp b/general/echo/umdfSocketEcho/Driver/driver.cpp new file mode 100644 index 00000000..4f93691c --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/driver.cpp @@ -0,0 +1,174 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Socketecho Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +STDMETHODIMP +CMyDriver::OnInitialize( + _In_ IWDFDriver* pWdfDriver + ) + + +/*++ + + Routine Description: + + This routine is invoked by the framework at driver load . + This method will invoke the Winsock Library for using + Winsock API in this driver. + + Arguments: + + pWdfDriver - Framework driver object + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ + +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + UNREFERENCED_PARAMETER(pWdfDriver); + + WORD sockVersion; + WSADATA wsaData; + + sockVersion = MAKEWORD(2, 0); + + int result = WSAStartup(sockVersion, &wsaData); + + if (result != 0) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Failed to initialize Winsock 2.0 %!winerr!", + err + ); + return HRESULT_FROM_WIN32(err); + } + + return S_OK; +} + +STDMETHODIMP_(void) +CMyDriver::OnDeinitialize( + _In_ IWDFDriver* pWdfDriver + ) + +/*++ + Routine Description: + + The FX invokes this method when it unloads the driver. + This routine will Cleanup Winsock library + + Arguments: + + pWdfDriver - the Fx driver object. + + Return Value: + + None + + + --*/ + +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pWdfDriver); + + WSACleanup(); +} + +STDMETHODIMP +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr; + + CComObject<CMyDevice> * device = NULL; + + // + // Create a new instance of our device callback object + // + + hr = CComObject<CMyDevice>::CreateInstance(&device); + + if (SUCCEEDED(hr)) + { + device->AddRef(); + hr = device->Initialize(FxWdfDriver, FxDeviceInit); + } + + // + // If that succeeded then call the device's configure method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference we took on the device callback object. + // The framework took its own references on the object's callback interfaces + // when we called FxWdfDriver->CreateDevice, and will manage the object's lifetime. + // + SAFE_RELEASE(device); + + return hr; +} diff --git a/general/echo/umdfSocketEcho/Driver/driver.h b/general/echo/umdfSocketEcho/Driver/driver.h new file mode 100644 index 00000000..6affa20f --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/driver.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF Socketecho sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the socktecho sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +extern const GUID CLSID_MyDriverCoClass; + +class ATL_NO_VTABLE CMyDriver : + public CComObjectRootEx<CComMultiThreadModel>, + public CComCoClass<CMyDriver, &CLSID_MyDriverCoClass>, + public IDriverEntry +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDriver) + +DECLARE_CLASSFACTORY(); + +DECLARE_NO_REGISTRY(); + +BEGIN_COM_MAP(CMyDriver) + COM_INTERFACE_ENTRY(IDriverEntry) +END_COM_MAP() + +public: + // IDriverEntry + STDMETHOD(OnInitialize)(_In_ IWDFDriver* pWdfDriver); + STDMETHOD(OnDeviceAdd)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + STDMETHOD_(void,OnDeinitialize)(_In_ IWDFDriver* pWdfDriver); +}; + diff --git a/general/echo/umdfSocketEcho/Driver/exports.def b/general/echo/umdfSocketEcho/Driver/exports.def new file mode 100644 index 00000000..2c0b7d49 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/exports.def @@ -0,0 +1,6 @@ +; Socketecho.def : Declares the module parameters. + +LIBRARY "SocketEcho" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/general/echo/umdfSocketEcho/Driver/internal.h b/general/echo/umdfSocketEcho/Driver/internal.h new file mode 100644 index 00000000..a7875468 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/internal.h @@ -0,0 +1,117 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Socketecho sample + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the winsock headers before any other windows headers. +// +#include <winsock2.h> +#include <ws2tcpip.h> + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Define the tracing flags. +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (64316518,DFE2,42B6,8786,4995E5EC435), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\SocketEcho" +#define MYDRIVER_CLASS_ID { 0x83B87D35, 0x76B8, 0x4920, {0xB4, 0x3C, 0x3B, 0xDE, 0x6B, 0x0E, 0xC5, 0xB8} } + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} +#endif + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_SAMPLE_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +// +// Include the type specific headers. +// +#include <atlbase.h> +#include <atlcom.h> + +#include "connection.h" +#include "filecontext.h" +#include "devicecontext.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +_Analysis_mode_(_Analysis_operator_new_null_) + diff --git a/general/echo/umdfSocketEcho/Exe/internal.h b/general/echo/umdfSocketEcho/Exe/internal.h new file mode 100644 index 00000000..ff1cd863 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/internal.h @@ -0,0 +1,18 @@ +// internal.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include <driverspecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_); +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <strsafe.h> +#include <setupapi.h> + +#include "socketechoserver.h" diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp new file mode 100644 index 00000000..bfe5f546 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp @@ -0,0 +1,512 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + socketserver.cpp + +Abstract: + + A simple socket server application that listens on a specified port and echoes back data + received. + +Environment: + + User Mode + +--*/ + +#include "internal.h" + + +DWORD +Run( + LPVOID lpThreadParameter + ) + /*++ + +Routine Description: + + This routine is invoked for each thread created for a new connection accepted by the server. + The rcv and send to socket happen in this thread routine. + + +Arguments: + + lpThreadParameter , The Thread parameter which contains socket information + +Return Value: + + Thread Exit Code + + +--*/ +{ + #define DeleteBufferExitThread(dwExitCode) \ + delete[] buffer; \ + buffer = NULL; \ + ExitThread(dwExitCode); + + #define DeleteBufferReturn(dwExitCode) \ + delete[] buffer; \ + buffer = NULL; \ + return dwExitCode; + + int count =0; + + char *buffer = new char[DATA_LENGTH]; + if (NULL == buffer) + { + ExitThread(1); + } + + DWORD Event; + + // + // Look at socket information from thread arg. + // + + + CEchoServer *pThreadData = (CEchoServer*)lpThreadParameter; + if (pThreadData==NULL) + { + DeleteBufferExitThread(1); + } + + SOCKET sClient = pThreadData->m_socket; + HANDLE NetworkEvent = pThreadData->m_NetworkEvent; + WSANETWORKEVENTS NetworkEvents; + printf("Client Start: 0x%Ix\n", sClient); + int actual = 0; + for(;;) + { + if ((Event = WSAWaitForMultipleEvents( + 1, + &NetworkEvent, + FALSE, + WSA_INFINITE, + FALSE)) == WSA_WAIT_FAILED) + { + printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError()); + DeleteBufferReturn(0); + } + + if (WSAEnumNetworkEvents(sClient ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR) + { + printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError()); + DeleteBufferReturn(0); + } + + if (NetworkEvents.lNetworkEvents & FD_READ) + { + if (NetworkEvents.lNetworkEvents & FD_READ && NetworkEvents.iErrorCode[FD_READ_BIT] != 0) + { + printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]); + } + else + { + + actual = recv(sClient,buffer,DATA_LENGTH*sizeof(char),0); + // + // socket connection has been reset ,so bail out . + // + if (actual == 0 || actual == WSAECONNRESET ) + { + printf(" Could not get data , Error : 0x%lx \n",WSAGetLastError()); + break; // socket shut-down + + } + printf("FD_READ read buffer on client 0x%Ix with length %d \n",sClient,actual); + count = send(sClient, (const char*)buffer,actual,0); + if ( count == SOCKET_ERROR ) + { + if ( WSAGetLastError()== WSAEWOULDBLOCK ) + { + printf(" Could not send data as resource is unavaliable , do not retry until next Write event \n"); + } + else + { + printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError()); + break; + } + } + else + { + printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count); + } + } + } + // + // if there is a write network event and there is data to write , write that + // + if (NetworkEvents.lNetworkEvents & FD_WRITE) + { + if (NetworkEvents.lNetworkEvents & FD_WRITE && NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0) + { + printf("FD_WRITE failed with error %d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]); + } + else + { + count = send(sClient, (const char*)buffer,actual,0); + if ( count == SOCKET_ERROR ) + { + if ( WSAGetLastError()== WSAEWOULDBLOCK ) + { + printf(" Could not send data as resource is unavaliable , do not retry until next Write event "); + } + else + { + printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError()); + break; + } + } + else + { + printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count); + } + actual = 0; + } + } + if (NetworkEvents.lNetworkEvents & FD_CLOSE) + { + shutdown(sClient,FD_READ|FD_WRITE); + printf(" recived a close from client : 0x%Ix \n",sClient); + closesocket(sClient); + DeleteBufferExitThread(0); + } + } + + DeleteBufferReturn(1); + +} + +CEchoServer::CEchoServer( + SOCKET socketclient + ) +/*++ + +Routine Description: + + This is the constructor routine for CEchoServer class. This is called for each instance of new + connection accepted by the server . + +Arguments: + + Socket received from the accept + +Return Value: + + None . + +--*/ +{ + m_socket = socketclient; + m_NetworkEvent = WSACreateEvent(); + printf("socket created : 0x%Ix \n", m_socket); + +} + +void +CEchoServer::Start() +/*++ + +Routine Description: + + This routine is to Start the thread which will rcv and send the data recieved on this instance of socket connection. + + +Arguments: + + None. + +Return Value: + + None. +--*/ +{ + + + if(WSAEventSelect( + m_socket, + m_NetworkEvent, + FD_READ|FD_WRITE|FD_CLOSE)== SOCKET_ERROR) + { + printf("Error in Event Select,Cannot start Server thread for this socket \n"); + closesocket(m_socket); + goto Exit; + } +// +// Create thread to read/write data to this socket +// + + HANDLE hRunThread = CreateThread( + NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) Run, // Thread Func + this, // Arg to Thread Func. + 0, // Creation Flags + NULL // Don't need the Thread Id. + ); + if (NULL == hRunThread) + { + printf(" Could not create socket server run thread : 0x%lx \n", GetLastError()); + closesocket(m_socket); + goto Exit; + } + +Exit: + + return ; + } + +void +SocketServerMain( + _In_ unsigned short uPort + ) +/*++ + +Routine Description: + + This routine is the main entry for the app when the app is configured to + be a socket server. + It creates a a listening socket for incoming conenctions. + + +Arguments: + + uPort - Port Number that the socket server binds to + +Return Value: + + None. +--*/ +{ + + + SOCKET ListenSocket; + int iResult; + #pragma warning( suppress: 24002 ) // suppress warning for IPv6 ,currently IPv4 specific + sockaddr_in service ; + + // Initialize Winsock 2.2 + WSADATA wsaData; + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if ( NO_ERROR != iResult ) + { + printf("Error at WSAStartup() \n"); + goto Exit; + } + // + // Create a SOCKET for listening for incoming connection requests. + // + ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if ( INVALID_SOCKET == ListenSocket) + { + printf("Error at socket(): %ld\n ", WSAGetLastError()); + goto Cleanup; + } + // The sockaddr_in structure specifies the address family, + // IP address, and port for the socket that is being bound. + service.sin_family = AF_INET; + // + // Suppress overflow warning. + // inet_pton is annotated to write sizeof(IN6_ADDR) bytes to pAddrBuf, + // but it only writes sizeof(IN_ADDR) bytes when Family is AF_INET (IPv4). + // https://msdn.microsoft.com/en-us/library/windows/desktop/cc805844(v=vs.85).aspx + // + #pragma warning( suppress: 26000 ) + iResult = inet_pton(AF_INET, "127.0.0.1", &service.sin_addr); + if (iResult != 1) + { + printf("Error at inet_pton(): %ld\n ", WSAGetLastError()); + closesocket(ListenSocket); + goto Cleanup; + } + service.sin_port = htons(uPort); + if (SOCKET_ERROR == bind( + ListenSocket, + (SOCKADDR*) &service, + sizeof(service) ) ) + { + printf("bind() failed. \n"); + closesocket(ListenSocket); + goto Cleanup; + } + + // + // Listen for incoming connection requests + // on the created socket upto MAX_CONNECTIONS + // + if ( SOCKET_ERROR == listen( + ListenSocket, + MAX_CONNECTIONS ) ) + { + printf("Error listening on socket.\n"); + } + printf("Listening on socket...\n"); + + // + // Set Socket RCVBUF and SNDBUF size to DATA_LENGTH , so large requests are not fragmented . + // + int iOptVal; + int iOptLen = sizeof(int); + + if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_RCVBUF value: %ld\n", iOptVal); + } + iOptVal = DATA_LENGTH; + iOptLen = sizeof(int); + if (setsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR) + { + printf("Set SO_RCVBUF: ON\n"); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_RCVBUF Value: %ld\n", iOptVal); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_SNDBUF value: %ld\n", iOptVal); + } + iOptVal = DATA_LENGTH; + iOptLen = sizeof(int); + if (setsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR) + { + printf("Set SO_SNDBUF: ON\n"); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_SNDBUF Value: %ld\n", iOptVal); + } + +// +// Loop the server to start accepting connections from clients on this socket +// + + for(;;) + { + CEchoServer *client = new CEchoServer(accept(ListenSocket,NULL,NULL)); + + if (client) + { + printf("Client connected.\n"); + client->Start(); // Start receiving/sending data on the socket + } + } + +Cleanup: + // + // Invoke Winsock Cleanup + // + + WSACleanup(); + + Exit: + return; + +} +void +Usage() + +/*++ + +Routine Description: + + This routine is invoked to display the usage of this application + +Arguments: + + None. + +Return Value: + + None . +--*/ + +{ + printf("\n\n Usage: \n"); + printf(" ------ \n\n"); + printf(" socketechoapp Display Usage \n"); + printf(" socketechoapp -h Display Usage\n"); + printf(" socketechoapp -p Start the app as server listening on default port\n"); + printf(" socketechoapp -p [port#] Start the app as server listening on this port \n"); + + + +} + + +/* */ +void __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) + +/*++ + +Routine Description: + + + +Arguments: + + None. + +Return Value: + + None. +--*/ +{ + unsigned short argIndex = 1 ; + unsigned short uPort = DEFAULT_PORT_ADDRESS ; + + + if (argc < 2) + { + Usage(); + goto Exit; + } + +// +// look at second arg and check for either -h which indicates user asked for help in Usage +// of this commandline +// + + if (!strcmp(*(argv+argIndex),"-h")) + { + Usage(); + goto Exit; + } +// +// check if its -p and proceed with otherwise show usage +// + else if (!strcmp(*(argv+argIndex),"-p")) + { + // + // look at third arg, which should be the port# + // + if ( ++argIndex < argc ) + { + uPort = (unsigned short)atoi(*(argv+(argIndex))); + } + SocketServerMain(uPort); + + } + else + { + Usage(); + goto Exit; + } + +Exit: + return; + +} + + diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.h b/general/echo/umdfSocketEcho/Exe/socketechoserver.h new file mode 100644 index 00000000..f71bc48b --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + sockechoserver.h + +Abstract: + + Header file for the socket server module of the socketecho application + +Environment: + + User mode only + +--*/ + +#pragma once + + +#define MAX_CONNECTIONS 5 +#define DEFAULT_PORT_ADDRESS 6000 +#define DATA_LENGTH 1024*40 + +void +SocketServerMain( + _In_ unsigned short uPort + ); + + // + // Class definition for CEchoServer Class + // +class CEchoServer +{ + + public: + + SOCKET m_socket; + HANDLE m_NetworkEvent; + + + + CEchoServer(SOCKET socketclient); + void Start(); + +}; + diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj new file mode 100644 index 00000000..ea299161 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj @@ -0,0 +1,179 @@ +<?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>{4237BF5F-1426-45DD-96E0-74DEADFA24C6}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{13151EE8-4C58-4284-BA01-C4B9431C6B06}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</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" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="socketechoserver.cpp" /> + </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/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters new file mode 100644 index 00000000..035fba1a --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{1BEC8228-FE60-4512-B036-885F56208A4B}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{E4060FEA-373E-4AE6-94B7-FF878D406EAE}</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>{181042B8-D282-46BA-B9D7-BDEE33402D00}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="socketechoserver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdfSocketEcho/ReadMe.md b/general/echo/umdfSocketEcho/ReadMe.md new file mode 100644 index 00000000..12515365 --- /dev/null +++ b/general/echo/umdfSocketEcho/ReadMe.md @@ -0,0 +1,184 @@ +UMDF SocketEcho Sample (UMDF Version 1) +======================================= + +The UMDF SocketEcho sample demonstrates how to use the User-Mode Driver Framework (UMDF) to write a driver and demonstrates best practices. + +This sample also demonstrates how to use a default parallel dispatch I/O queue, use a Microsoft Win32 dispatcher, and handle a socket handle by using a Win32 file I/O target. + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + +Code Tour +--------- + +Parts of this code sample are generated from the ATL Project Wizard in Microsoft Visual Studio 2005. This sample driver is a minimal driver that is intended to demonstrate how to use UMDF. It is not intended for use in a production environment. + +CMyDriver::OnInitialize in driver.cpp is called by the framework when the driver loads. This method initiates use of the Winsock Library. CMyDriver::OnDeviceAdd in driver.cpp is called by the framework to install the driver on a device stack. OnDeviceAdd creates a device callback object, and then calls IWDFDriver::CreateDevice to create an framework device object and to associate the device callback object with the framework device object. + +CMyQueue::OnCreateFile in queue.cpp is called by the framework to create a socket connection, create a file i/o target that is associated with the socket handle for this connection, and store the socket handle in the file object context. + +Installation +------------ + +In Visual Studio, you can press F5 to build the sample and then deploy it to a target machine. For more information, see [Deploying a Driver to a Test Computer](http://msdn.microsoft.com/en-us/library/windows/hardware/hh454834). Alternatively, you can install the sample from the command line. + +To test this sample, you must have a test computer that is running Windows Vista or later. This test computer can be a second computer or, if necessary, your development computer. + +To install the UMDF Echo sample driver from the command line, do the following: + +1. Copy the driver binary and the socketecho.inf file to a directory on your test computer (for example, C:\\ socketechoSample.) + +2. Copy the UMDF coinstaller, WUDFUpdate\_*MMmmmm*.dll, from the \\redist\\wdf\\\<architecture\> directory to the same directory (for example, C:\\socketechoSample). + + **Note** + + You can obtain redistributable framework updates by downloading the *wdfcoinstaller.msi* package from [WDK 8 Redistributable Components](http://go.microsoft.com/fwlink/p/?LinkID=226396). This package performs a silent install into the directory of your Windows Driver Kit (WDK) installation. You will see no confirmation that the installation has completed. You can verify that the redistributables have been installed on top of the WDK by ensuring there is a redist\\wdf directory under the root directory of the WDK, %ProgramFiles(x86)%\\Windows Kits\\8.0. + +3. + + Navigate to the directory that contains the INF file and binaries (for example, cd /d c:\\socketechoSample), and run DevCon.exe as follows: + + **devcon.exe install socketecho.inf WUDF\\socketecho** + + You can find DevCon.exe in the \\tools directory of the WDK (for example, \\tools\\devcon\\i386\\devcon.exe). + +To update the socketecho driver after you make any changes, do the following: + +1. Increment the version number in the INF file. This change is not necessary, but it will help ensure that Plug and Play (PnP) selects your new driver as a better match for the device. + +2. Copy the updated driver binary and the socketecho.inf file to a directory on your test computer (for example, C:\\ socketechoSample.) + +3. Navigate to the directory that contains the INF file and binaries (for example, cd /d c:\\ socketechoSample), and run devcon.exe as follows: + + devcon.exe update socketecho.inf WUDF\\socketecho + +To test this sample drivers on a checked operating system that you have installed (in contrast to the standard retail installations), you must modify the INF file to use the checked version of the UMDF co-installer. That is, you must do the following: + +1. In the INX file, replace all occurrences of WudfUpdate\_*MMmmmm*.dll with WudfUpdate\_*MMmmmm*\_chk.dll. + +2. Copy the WudfUpdate\_*MMmmmm*\_chk.dll file from the \\redist\\wdf\\\<architecture\> directory to your driver package instead of WudfUpdate\_*MMmmmm*.dll. + +3. If WdfCoinstaller*MMmmmm*.dll or WinUsbCoinstaller.dll is included in your driver package, repeat step 1 and step 2 for them. + +Testing +------- + +To test the SocketEcho driver, you can run socketechoserver.exe, which is built from the src\\general\\echo\\umdfSocketEcho\\Exe directory, and echoapp.exe, which is built from the Kernel-Mode Driver Framework (KMDF) samples in the src\\general\\echo\\kmdf directory. + +First, you must install the device as described earlier. Then, run socketechoserver.exe from a Command Prompt window. + +D:\\\>socketechoserver -h + +Usage: + +------ + +socketechoserver Display Usage + +socketechoserver -h Display Usage + +socketechoserver -p Start the app as server listening on default port + +socketechoserver -p [port\#] Start the app as server listening on this port + +D:\\\>socketechoserver -p + +Listening on socket... + +In another Command Prompt window, run echoapp.exe. + +D:\\\>echoapp + +DevicePath: \\\\?\\root\#sample\#0000\#{ e5e65b0c-82c8-4689-96d4-f77837971990} + +Opened device successfully + +512 Pattern Bytes Written successfully + +512 Pattern Bytes Read successfully + +Pattern Verified successfully + +D:\\\>echoapp -Async + +DevicePath: \\\\?\\root\#sample\#0000\#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} + +Opened device successfully + +Starting AsyncIo + +Number of bytes written by request number 0 is 1024 + +Number of bytes read by request number 0 is 1024 + +Number of bytes read by request number 1 is 1024 + +Number of bytes written by request number 2 is 1024 + +Number of bytes read by request number 2 is 1024 + +Number of bytes written by request number 3 is 1024 + +Number of bytes read by request number 3 is 1024 + +Number of bytes written by request number 4 is 1024 + +Number of bytes read by request number 4 is 1024 + +Number of bytes written by request number 5 is 1024 + +Number of bytes read by request number 5 is 1024 + +Number of bytes written by request number 6 is 1024 + +Number of bytes read by request number 6 is 1024 + +Number of bytes written by request number 7 is 1024 + +Number of bytes read by request number 7 is 1024 + +Number of bytes written by request number 8 is 1024 + +Number of bytes read by request number 8 is 1024 + +Number of bytes written by request number 9 is 1024 + +Number of bytes read by request number 9 is 1024 + +Number of bytes written by request number 10 is 1024 + +Number of bytes read by request number 10 is 1024 + +Number of bytes written by request number 11 is 1024 + +... + +Note that independent threads perform the reads and writes in the echo test application. As a result, the order of the output might not exactly match what you see in the preceding output. + +File Manifest +------------- + +<table> +<colgroup> +<col width="50%" /> +<col width="50%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">File +Description</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left"><p>Socketecho.htm</p> +<p>The documentation for this sample.</p></td> +<td align="left"><p>Dllsup.cpp</p> +<p>The DLL support code that provides the DLL's entry point and the single required export (DllGetClassObject).</p></td> +</tr> +</tbody> +</table> + + diff --git a/general/echo/umdfSocketEcho/umdfsocketecho.sln b/general/echo/umdfSocketEcho/umdfsocketecho.sln new file mode 100644 index 00000000..9cd8f76d --- /dev/null +++ b/general/echo/umdfSocketEcho/umdfsocketecho.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{C4B24CED-B58F-47D1-8FC0-778610EF84CF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{AFCDA28A-1D07-410D-BA77-47E637336CA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketEcho", "Driver\SocketEcho.vcxproj", "{ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socketechoserver", "Exe\socketechoserver.vcxproj", "{4237BF5F-1426-45DD-96E0-74DEADFA24C6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.Build.0 = Debug|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.ActiveCfg = Release|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.Build.0 = Release|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.ActiveCfg = Debug|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.Build.0 = Debug|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.ActiveCfg = Release|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.Build.0 = Release|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.ActiveCfg = Debug|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.Build.0 = Debug|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.ActiveCfg = Release|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.Build.0 = Release|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.ActiveCfg = Debug|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.Build.0 = Debug|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.ActiveCfg = Release|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3} = {C4B24CED-B58F-47D1-8FC0-778610EF84CF} + {4237BF5F-1426-45DD-96E0-74DEADFA24C6} = {AFCDA28A-1D07-410D-BA77-47E637336CA6} + EndGlobalSection +EndGlobal |
