summaryrefslogtreecommitdiff
path: root/serial/VirtualSerial2
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /serial/VirtualSerial2
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'serial/VirtualSerial2')
-rw-r--r--serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj194
-rw-r--r--serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters48
-rw-r--r--serial/VirtualSerial2/ComPort/virtualserial2um.inx73
-rw-r--r--serial/VirtualSerial2/ComPort/virtualserial2um.rc17
-rw-r--r--serial/VirtualSerial2/FakeModem/fakemodem2um.inx193
-rw-r--r--serial/VirtualSerial2/FakeModem/fakemodem2um.rc17
-rw-r--r--serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj194
-rw-r--r--serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters48
-rw-r--r--serial/VirtualSerial2/ReadMe.md59
-rw-r--r--serial/VirtualSerial2/VirtualSerial.sln46
-rw-r--r--serial/VirtualSerial2/device.c449
-rw-r--r--serial/VirtualSerial2/device.h122
-rw-r--r--serial/VirtualSerial2/driver.c72
-rw-r--r--serial/VirtualSerial2/driver.h30
-rw-r--r--serial/VirtualSerial2/internal.h58
-rw-r--r--serial/VirtualSerial2/queue.c963
-rw-r--r--serial/VirtualSerial2/queue.h113
-rw-r--r--serial/VirtualSerial2/ringbuffer.c338
-rw-r--r--serial/VirtualSerial2/ringbuffer.h117
-rw-r--r--serial/VirtualSerial2/serial.h128
20 files changed, 3279 insertions, 0 deletions
diff --git a/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj
new file mode 100644
index 00000000..3b3a3606
--- /dev/null
+++ b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj
@@ -0,0 +1,194 @@
+<?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>{9C376D98-E44B-44C6-BA97-C41F501548E6}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{C1C1FD00-5B5C-4F07-AB92-50461FEE885F}</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="VirtualSerial2um.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\VirtualSerial2um.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>VirtualSerial2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>VirtualSerial2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>VirtualSerial2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>VirtualSerial2um</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\device.c" />
+ <ClCompile Include="..\driver.c" />
+ <ClCompile Include="..\queue.c" />
+ <ClCompile Include="..\ringbuffer.c" />
+ <ResourceCompile Include="virtualserial2um.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/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters
new file mode 100644
index 00000000..de01b778
--- /dev/null
+++ b/serial/VirtualSerial2/ComPort/VirtualSerial2um.vcxproj.Filters
@@ -0,0 +1,48 @@
+<?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>{74E463E8-2208-4136-9C1D-4160F1D7A44A}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{86516042-B85B-4491-8ACF-5B7E87D1FB11}</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>{1B09240F-68FE-4973-8631-0BFDDF0CEAB9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{85FCBC36-920C-4155-96D9-7C492514995E}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\VirtualSerial2um.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="VirtualSerial2um.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>
+ <ClCompile Include="..\ringbuffer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="virtualserial2um.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/serial/VirtualSerial2/ComPort/virtualserial2um.inx b/serial/VirtualSerial2/ComPort/virtualserial2um.inx
new file mode 100644
index 00000000..312c950c
--- /dev/null
+++ b/serial/VirtualSerial2/ComPort/virtualserial2um.inx
@@ -0,0 +1,73 @@
+;
+; Copyright (C) Microsoft Corporation, All Rights Reserved.
+;
+; VirtualSerial.inf
+;
+;Installation Notes:
+; Type "devcon install VirtualSerial2um.inf UMDF\VirtualSerial2um" to install
+
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%MSFTUMDF%
+CatalogFile=WUDF.cat
+DriverVer=03/25/2005,0.0.0.1
+
+[Manufacturer]
+%MSFTUMDF%=Microsoft,NT$ARCH$
+
+[Microsoft.NT$ARCH$]
+%VirtualSerialDeviceName%=VirtualSerial_Install,UMDF\VirtualSerial2um
+
+[SourceDisksFiles]
+Virtualserial2um.dll=1
+
+[SourceDisksNames]
+1 = %MediaDescription%
+
+; =================== UMDF VirtualSerial Device ==================================
+
+[VirtualSerial_Install.NT]
+CopyFiles=UMDriverCopy
+
+[VirtualSerial_Install.NT.hw]
+AddReg=SetDeviceType_AddReg
+
+[VirtualSerial_Install.NT.Services]
+AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall
+
+[VirtualSerial_Install.NT.Wdf]
+UmdfService = VirtualSerial, VirtualSerial_Install
+UmdfServiceOrder = VirtualSerial
+UmdfKernelModeClientPolicy = AllowKernelModeClients
+UmdfFileObjectPolicy = AllowNullAndUnknownFileObjects
+UmdfFsContextUsePolicy = CannotUseFsContexts
+
+[VirtualSerial_Install]
+UmdfLibraryVersion=$UMDFVERSION$
+ServiceBinary=%12%\UMDF\Virtualserial2um.dll
+
+[WUDFRD_ServiceInstall]
+DisplayName = %WudfRdDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\WUDFRd.sys
+
+[SetDeviceType_AddReg]
+HKR,,DeviceType,0x10001,0x0000001b ; 0x1b = FILE_DEVICE_SERIAL_PORT
+
+[DestinationDirs]
+UMDriverCopy=12,UMDF ; copy to drivers\UMDF
+
+[UMDriverCopy]
+Virtualserial2um.dll
+
+; =================== Generic ==================================
+
+[Strings]
+MSFTUMDF="Microsoft"
+MediaDescription="Microsoft Sample Driver Installation Media"
+WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector"
+VirtualSerialDeviceName="Microsoft VirtualSerial Sample (UMDF 2)"
diff --git a/serial/VirtualSerial2/ComPort/virtualserial2um.rc b/serial/VirtualSerial2/ComPort/virtualserial2um.rc
new file mode 100644
index 00000000..f9f0a8d0
--- /dev/null
+++ b/serial/VirtualSerial2/ComPort/virtualserial2um.rc
@@ -0,0 +1,17 @@
+//---------------------------------------------------------------------------
+// Virtualserial.rc
+//
+// Copyright (c) Microsoft Corporation, All Rights Reserved
+//---------------------------------------------------------------------------
+
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "WDF:UMDF VirtualSerial User-Mode v2 Driver Sample"
+#define VER_INTERNALNAME_STR "VirtualSerial2um"
+#define VER_ORIGINALFILENAME_STR "Virtualserial2um.dll"
+
+#include "common.ver"
diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.inx b/serial/VirtualSerial2/FakeModem/fakemodem2um.inx
new file mode 100644
index 00000000..31fe730d
--- /dev/null
+++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.inx
@@ -0,0 +1,193 @@
+;
+; Copyright (C) Microsoft Corporation, All Rights Reserved.
+;
+; FakeModem.inf
+; "Fakemodem" Controllerless driver illustrative example
+;
+; Installation Notes:
+; Use toaster dynambus.sys and notify.exe to plug in a fake modem device
+
+[Version]
+Signature="$Windows NT$"
+Class=Modem
+ClassGuid={4D36E96D-E325-11CE-BFC1-08002BE10318}
+Provider=%MSFTUMDF%
+CatalogFile=WUDF.cat
+DriverVer=12/30/2010,0.0.0.1
+
+[Manufacturer]
+%MSFTUMDF%=Microsoft,NT$ARCH$
+
+[Microsoft.NT$ARCH$]
+%FakeModemDeviceName%=FakeModem_Install,{b85b7c50-6a01-11d2-b841-00c04fad5171}\fakemodem
+
+[SourceDisksFiles]
+FakeModem2um.dll=1
+
+[SourceDisksNames]
+1 = %MediaDescription%
+
+; =================== UMDF FakeModem Device ==================================
+
+; The AddReg line below instructs the installer to add the registry
+; entries listed in the following sections of this INF file:
+; [All], [MfgAddReg], [ExtraCRLFResponses], [ModemX.AddReg], [INTERNAL]
+
+[FakeModem_Install.NT]
+CopyFiles=UMDriverCopy
+AddReg = All, MfgAddReg, ExtraCRLFResponses, ModemX.AddReg, INTERNAL
+
+[FakeModem_Install.NT.hw]
+AddReg = LowerFilterAddReg
+
+[LowerFilterAddReg]
+HKR,,"LowerFilters",0x00010000,WUDFRd
+
+[FakeModem_Install.NT.Services]
+AddService=WUDFRd,0x00000000,WUDFRD_ServiceInstall
+
+[WUDFRD_ServiceInstall]
+DisplayName = %WudfRdDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\WUDFRd.sys
+
+[FakeModem_Install.NT.Wdf]
+UmdfService = FakeModem, FakeModem_Install
+UmdfServiceOrder = FakeModem
+UmdfKernelModeClientPolicy = AllowKernelModeClients
+UmdfFsContextUsePolicy = CannotUseFsContexts
+
+[FakeModem_Install]
+UmdfLibraryVersion=$UMDFVERSION$
+ServiceBinary=%12%\UMDF\FakeModem2um.dll
+
+[DestinationDirs]
+UMDriverCopy=12,UMDF ; copy to drivers\UMDF
+
+[UMDriverCopy]
+FakeModem2um.dll
+
+;-------------------------------------------------------------------------------------------------------
+; DDK procalc tool can be used to check properties settings which describes modem' properties.
+; Generally, customization entries are added here which override commands from the All section
+
+[ModemX.AddReg]
+HKR,,Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00
+HKR,,InactivityScale, 1, 0a,00,00,00
+HKR, Settings, InactivityTimeout,, "S30=<#>"
+HKR, Settings, ErrorControl_On,, "\N3"
+HKR, Settings, ErrorControl_Forced,, "\N2"
+HKR, Settings, Compression_On,, "%%C3"
+HKR, Settings, SpeedNegotiation_Off,, "N0"
+HKR, Settings, SpeedNegotiation_On,, "N1"
+
+;--------------------------------------------------------------------------------------------------------------------------
+;This section will define the type of modem and thus present the appropriate icon in the Device manager
+
+[INTERNAL]
+HKR,, DeviceType, 1, 02
+
+;-------------------------------------------------------------------------------------------------------------------------
+; Responses section contains all of the appropriate and required responses in order for the O/S to understand the
+; Modem responses to system queries.
+
+[All]
+HKR,,ConfigDialog,,modemui.dll
+HKR,,EnumPropPages,,"modemui.dll,EnumPropPages"
+HKR,,PortSubClass,1,02
+HKR,Init,1,,"AT<cr>"
+HKR,Init, 2,, "AT &F E0 V1 &D2 &C1 S0=0 W2 S95=47<cr>"
+
+[MfgAddReg]
+HKR,, InactivityScale, 1, 01,00,00,00
+HKR, Monitor, 1,, "ATS0=0<cr>"
+HKR, Monitor, 2,, "None"
+HKR, Hangup, 1,, "ATH<cr>"
+HKR, Answer, 1,, "ATA<cr>"
+HKR,, Reset,, "ATZ<cr>"
+HKR, Settings, Prefix,, "AT"
+HKR, Settings, Terminator,, "<cr>"
+HKR, Settings, DialPrefix,, "D"
+HKR, Settings, DialSuffix,, ";"
+HKR, Settings, SpeakerVolume_Low,, "L1"
+HKR, Settings, SpeakerVolume_Med,, "L2"
+HKR, Settings, SpeakerVolume_High,, "L3"
+HKR, Settings, SpeakerMode_Off,, "M0"
+HKR, Settings, SpeakerMode_Dial,, "M1"
+HKR, Settings, SpeakerMode_On,, "M2"
+HKR, Settings, SpeakerMode_Setup,, "M3"
+HKR, Settings, FlowControl_Off,, "&K0"
+HKR, Settings, FlowControl_Hard,, "&K3"
+HKR, Settings, FlowControl_Soft,, "&K4"
+HKR, Settings, ErrorControl_On,, "\N5"
+HKR, Settings, ErrorControl_Off,, "\N0"
+HKR, Settings, ErrorControl_Forced,, "\N4"
+HKR, Settings, Compression_On,, "%%C1"
+HKR, Settings, Compression_Off,, "%%C0"
+HKR, Settings, Modulation_CCITT,, "B0 "
+HKR, Settings, Modulation_Bell,, "B1 "
+HKR, Settings, SpeedNegotiation_Off,, "*S0"
+HKR, Settings, SpeedNegotiation_On,, "*S1"
+HKR, Settings, Pulse,, "P"
+HKR, Settings, Tone,, "T"
+HKR, Settings, Blind_Off,, "X4"
+HKR, Settings, Blind_On,, "X3"
+HKR, Settings, CallSetupFailTimer,, "S7=<#>"
+
+HKR, Responses, "<cr><lf>+FCERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>BLACKLISTED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00
+
+HKR, Responses, "<cr><lf>CONNECT<cr><lf>", 1, 02, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>DATA<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>DELAYED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+
+HKR, Responses, "<cr><lf>FAX<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NOTUSED<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>RING<cr><lf>", 1, 08, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>RINGING<cr><lf>", 1, 01, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "0<cr>", 1, 00, 00, 00,00,00,00, 00,00,00,00 ; OK
+HKR, Responses, "1<cr>", 1, 02, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "10<cr>", 1, 02, 00, 60,09,00,00, 00,00,00,00
+HKR, Responses, "11<cr>", 1, 02, 00, c0,12,00,00, 00,00,00,00
+HKR, Responses, "12<cr>", 1, 02, 00, 80,25,00,00, 00,00,00,00
+HKR, Responses, "13<cr>", 1, 02, 00, 20,1c,00,00, 00,00,00,00
+HKR, Responses, "14<cr>", 1, 02, 00, e0,2e,00,00, 00,00,00,00
+HKR, Responses, "15<cr>", 1, 02, 00, 40,38,00,00, 00,00,00,00 ; connect at 14400
+HKR, Responses, "2<cr>", 1, 08, 00, 00,00,00,00, 00,00,00,00 ; RING
+HKR, Responses, "3<cr>", 1, 04, 00, 00,00,00,00, 00,00,00,00 ; NO CARRIER
+HKR, Responses, "4<cr>", 1, 03, 00, 00,00,00,00, 00,00,00,00 ; ERROR
+HKR, Responses, "5<cr>", 1, 02, 00, b0,04,00,00, 00,00,00,00
+HKR, Responses, "6<cr>", 1, 05, 00, 00,00,00,00, 00,00,00,00 ; NO DIALTONE
+HKR, Responses, "69<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00
+HKR, Responses, "7<cr>", 1, 06, 00, 00,00,00,00, 00,00,00,00 ; BUSY
+HKR, Responses, "70<cr>", 1, 01, 01, 00,00,00,00, 00,00,00,00 ; Protocol:None
+HKR, Responses, "77<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:LAPM
+HKR, Responses, "78<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00 ; Connect V42BIS
+HKR, Responses, "8<cr>", 1, 07, 00, 00,00,00,00, 00,00,00,00 ; NO ANSWER
+HKR, Responses, "80<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:ALT
+HKR, Responses, "81<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00
+
+[ExtraCRLFResponses]
+HKR, Responses, "<cr><lf><cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00
+
+
+; =================== Generic ==================================
+
+[Strings]
+MSFTUMDF="Microsoft"
+MediaDescription="Microsoft Sample Driver Installation Media"
+WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector"
+FakeModemDeviceName="Microsoft Fake Modem User-Mode Device Sample"
diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.rc b/serial/VirtualSerial2/FakeModem/fakemodem2um.rc
new file mode 100644
index 00000000..7d916be2
--- /dev/null
+++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.rc
@@ -0,0 +1,17 @@
+//---------------------------------------------------------------------------
+// FakeModem.rc
+//
+// Copyright (c) Microsoft Corporation, All Rights Reserved
+//---------------------------------------------------------------------------
+
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "WDF:UMDF Fake Modem User-Mode Driver Sample"
+#define VER_INTERNALNAME_STR "FakeModem2um"
+#define VER_ORIGINALFILENAME_STR "FakeModem2um.dll"
+
+#include "common.ver"
diff --git a/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj
new file mode 100644
index 00000000..584aa824
--- /dev/null
+++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj
@@ -0,0 +1,194 @@
+<?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>{6F515009-0F48-480C-8EDC-4423269D1076}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{69E9B9C0-51CD-40CF-BFBA-291563913487}</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="fakemodem2um.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\fakemodem2um.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>fakemodem2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>fakemodem2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>fakemodem2um</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>fakemodem2um</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;_FAKE_MODEM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\wdm;..\..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\device.c" />
+ <ClCompile Include="..\driver.c" />
+ <ClCompile Include="..\queue.c" />
+ <ClCompile Include="..\ringbuffer.c" />
+ <ResourceCompile Include="fakemodem2um.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/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters
new file mode 100644
index 00000000..5067a79b
--- /dev/null
+++ b/serial/VirtualSerial2/FakeModem/fakemodem2um.vcxproj.Filters
@@ -0,0 +1,48 @@
+<?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>{6E68FD79-4D9F-4503-A0B5-3EFA5BC16118}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{009A35E7-F389-45E7-87EF-C71F6ED40D4A}</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>{6351F996-859F-4432-9FE1-82A5C2B6D89B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{42391772-ED65-4368-9478-D821892B39BA}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\fakemodem2um.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="fakemodem2um.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>
+ <ClCompile Include="..\ringbuffer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="fakemodem2um.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/serial/VirtualSerial2/ReadMe.md b/serial/VirtualSerial2/ReadMe.md
new file mode 100644
index 00000000..2b1bc513
--- /dev/null
+++ b/serial/VirtualSerial2/ReadMe.md
@@ -0,0 +1,59 @@
+Virtual serial driver sample
+============================
+
+This sample demonstrates these two serial drivers:
+
+- A simple virtual serial driver (ComPort)
+- A controller-less modem driver (FakeModem).This driver supports sending and receiving AT commands using the ReadFile and WriteFile calls or via a TAPI interface using an application such as, HyperTerminal.
+
+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.
+
+For more information, see [Serial Controller and Device Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff546939) in the WDK documentation.
+
+Code tour
+---------
+
+File manifest
+
+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 the 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 the sample driver.
+
+driver.cpp & driver.h
+
+Definition and implementation of the driver callback class (CMyDriver) for the sample. This includes **DriverEntry** and events on the framework driver object.
+
+device.cpp & driver.h
+
+Definition and implementation of the device callback class (CMyDriver) for the sample. This includes events on the framework device object.
+
+queue.cpp & queue.h
+
+Definition and implementation of the base queue callback class (CMyQueue). This includes events on the framework I/O queue object.
+
+VirtualSerial.rc /FakeModem.rc
+
+This file defines resource information for the sample driver.
+
+VirtualSerial.inf / FakeModem.inf
+
+INF file that contains installation information for this driver.
+
diff --git a/serial/VirtualSerial2/VirtualSerial.sln b/serial/VirtualSerial2/VirtualSerial.sln
new file mode 100644
index 00000000..79e3f2b0
--- /dev/null
+++ b/serial/VirtualSerial2/VirtualSerial.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}") = "ComPort", "ComPort", "{69B24279-DAE7-4F6B-AB01-D5399C616D6F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FakeModem", "FakeModem", "{231410A2-76BA-4213-95C7-523B902B21E1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VirtualSerial2um", "ComPort\VirtualSerial2um.vcxproj", "{9C376D98-E44B-44C6-BA97-C41F501548E6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem2um", "FakeModem\fakemodem2um.vcxproj", "{6F515009-0F48-480C-8EDC-4423269D1076}"
+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
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|Win32.Build.0 = Debug|Win32
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|Win32.ActiveCfg = Release|Win32
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|Win32.Build.0 = Release|Win32
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|x64.ActiveCfg = Debug|x64
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Debug|x64.Build.0 = Debug|x64
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|x64.ActiveCfg = Release|x64
+ {9C376D98-E44B-44C6-BA97-C41F501548E6}.Release|x64.Build.0 = Release|x64
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|Win32.Build.0 = Debug|Win32
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Release|Win32.ActiveCfg = Release|Win32
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Release|Win32.Build.0 = Release|Win32
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|x64.ActiveCfg = Debug|x64
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Debug|x64.Build.0 = Debug|x64
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Release|x64.ActiveCfg = Release|x64
+ {6F515009-0F48-480C-8EDC-4423269D1076}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9C376D98-E44B-44C6-BA97-C41F501548E6} = {69B24279-DAE7-4F6B-AB01-D5399C616D6F}
+ {6F515009-0F48-480C-8EDC-4423269D1076} = {231410A2-76BA-4213-95C7-523B902B21E1}
+ EndGlobalSection
+EndGlobal
diff --git a/serial/VirtualSerial2/device.c b/serial/VirtualSerial2/device.c
new file mode 100644
index 00000000..78bd463b
--- /dev/null
+++ b/serial/VirtualSerial2/device.c
@@ -0,0 +1,449 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Device.c
+
+Abstract:
+
+ This module contains the implementation of the VirtualSerial sample
+ driver's device callback object.
+
+ The VirtualSerial sample device does very little. 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 Driver Framework
+
+--*/
+
+#include "internal.h"
+
+NTSTATUS
+DeviceCreate(
+ _In_ WDFDRIVER Driver,
+ _In_ PWDFDEVICE_INIT DeviceInit,
+ _Out_ PDEVICE_CONTEXT *DeviceContext
+ )
+/*++
+
+ Routine Description:
+
+ This method creates and initializs an instance of the VirtualSerial 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
+
+--*/
+{
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ WDFDEVICE device;
+ PDEVICE_CONTEXT deviceContext;
+ UNREFERENCED_PARAMETER (Driver);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
+ &deviceAttributes,
+ DEVICE_CONTEXT);
+
+ deviceAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;
+ deviceAttributes.EvtCleanupCallback = EvtDeviceCleanup;
+
+ status = WdfDeviceCreate(&DeviceInit,
+ &deviceAttributes,
+ &device);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfDeviceCreate failed 0x%x", status);
+ return status;
+ }
+
+ deviceContext = GetDeviceContext(device);
+ deviceContext->Device = device;
+
+ *DeviceContext = deviceContext;
+
+ return status;
+}
+
+
+NTSTATUS
+DeviceConfigure(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+/*++
+
+ 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
+
+--*/
+{
+ NTSTATUS status;
+ WDFDEVICE device = DeviceContext->Device;
+ WDFKEY key;
+ LPGUID guid;
+ errno_t errorNo;
+
+ DECLARE_CONST_UNICODE_STRING(portName, REG_VALUENAME_PORTNAME);
+ DECLARE_UNICODE_STRING_SIZE (comPort, 10);
+ DECLARE_UNICODE_STRING_SIZE (symbolicLinkName, SYMBOLIC_LINK_NAME_LENGTH);
+
+#ifdef _FAKE_MODEM
+ //
+ // Compiled as fake modem
+ //
+ guid = (LPGUID) &GUID_DEVINTERFACE_MODEM;
+#else
+ //
+ // Compiled as virtual serial port
+ //
+ guid = (LPGUID) &GUID_DEVINTERFACE_COMPORT;
+#endif
+
+ //
+ // Create device interface
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ guid,
+ NULL);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Cannot create device interface");
+ goto Exit;
+ }
+
+ //
+ // Read the COM port number from the registry, which has been automatically
+ // created by "MsPorts!PortsClassInstaller" if INF file says "Class=Ports"
+ //
+ status = WdfDeviceOpenRegistryKey(
+ device,
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_QUERY_VALUE,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &key);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to retrieve device hardware key root");
+ goto Exit;
+ }
+
+ status = WdfRegistryQueryUnicodeString(
+ key,
+ &portName,
+ NULL,
+ &comPort);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to read PortName");
+ goto Exit;
+ }
+
+ //
+ // Manually create the symbolic link name. Length is the length in
+ // bytes not including the NULL terminator.
+ //
+ // 6054 and 26035 are code analysis warnings that comPort.Buffer might
+ // not be NULL terminated, while we know that they are.
+ //
+ #pragma warning(suppress: 6054 26035)
+ symbolicLinkName.Length = (USHORT)((wcslen(comPort.Buffer) * sizeof(wchar_t))
+ + sizeof(SYMBOLIC_LINK_NAME_PREFIX) - sizeof(UNICODE_NULL));
+
+ if (symbolicLinkName.Length >= symbolicLinkName.MaximumLength) {
+
+ Trace(TRACE_LEVEL_ERROR, "Error: Buffer overflow when creating COM port name. Size"
+ " is %d, buffer length is %d", symbolicLinkName.Length, symbolicLinkName.MaximumLength);
+ status = STATUS_BUFFER_OVERFLOW;
+ goto Exit;
+ }
+
+ errorNo = wcscpy_s(symbolicLinkName.Buffer,
+ SYMBOLIC_LINK_NAME_LENGTH,
+ SYMBOLIC_LINK_NAME_PREFIX);
+
+ if (errorNo != 0) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Failed to copy %ws to buffer with error %d",
+ SYMBOLIC_LINK_NAME_PREFIX, errorNo);
+ status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ errorNo = wcscat_s(symbolicLinkName.Buffer,
+ SYMBOLIC_LINK_NAME_LENGTH,
+ comPort.Buffer);
+
+ if (errorNo != 0) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Failed to copy %ws to buffer with error %d",
+ comPort.Buffer, errorNo);
+ status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Create symbolic link
+ //
+ status = WdfDeviceCreateSymbolicLink(
+ device,
+ &symbolicLinkName);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Cannot create symbolic link %ws", symbolicLinkName.Buffer);
+ goto Exit;
+ }
+
+ status = DeviceGetPdoName(DeviceContext);
+ if (!NT_SUCCESS(status)) {
+ goto Exit;
+ }
+
+ status = DeviceWriteLegacyHardwareKey(
+ DeviceContext->PdoName,
+ comPort.Buffer,
+ DeviceContext->Device);
+ if (NT_SUCCESS(status)) {
+ DeviceContext->CreatedLegacyHardwareKey = TRUE;
+ }
+
+ status = QueueCreate(DeviceContext);
+ if (!NT_SUCCESS(status)) {
+ goto Exit;
+ }
+
+Exit:
+ return status;
+}
+
+
+NTSTATUS
+DeviceGetPdoName(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device = DeviceContext->Device;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDFMEMORY memory;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = device;
+
+ status = WdfDeviceAllocAndQueryProperty(
+ device,
+ DevicePropertyPhysicalDeviceObjectName,
+ NonPagedPool,
+ &attributes,
+ &memory);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to query PDO name");
+ goto Exit;
+ }
+
+ DeviceContext->PdoName = (PWCHAR) WdfMemoryGetBuffer(memory, NULL);
+ Trace(TRACE_LEVEL_ERROR,
+ "PDO Name is %ws", DeviceContext->PdoName);
+
+Exit:
+ return status;
+}
+
+
+NTSTATUS
+DeviceWriteLegacyHardwareKey(
+ _In_ PWSTR PdoName,
+ _In_ PWSTR ComPort,
+ _In_ WDFDEVICE Device
+ )
+{
+ WDFKEY key = NULL;
+ NTSTATUS status;
+ UNICODE_STRING pdoString = {0};
+ UNICODE_STRING comPort = {0};
+
+ DECLARE_CONST_UNICODE_STRING(deviceSubkey, SERIAL_DEVICE_MAP);
+
+ RtlInitUnicodeString(&pdoString, PdoName);
+ RtlInitUnicodeString(&comPort, ComPort);
+
+ status = WdfDeviceOpenDevicemapKey(Device,
+ &deviceSubkey,
+ KEY_SET_VALUE,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &key);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to open DEVICEMAP\\SERIALCOMM key 0x%x", status);
+ goto exit;
+ }
+
+ status = WdfRegistryAssignUnicodeString(key,
+ &pdoString,
+ &comPort);
+
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to write to DEVICEMAP\\SERIALCOMM key 0x%x", status);
+ goto exit;
+ }
+
+exit:
+
+ if (key != NULL) {
+ WdfRegistryClose(key);
+ key = NULL;
+ }
+
+ return status;
+}
+
+
+VOID
+EvtDeviceCleanup(
+ _In_ WDFOBJECT Object
+ )
+{
+ WDFDEVICE device = (WDFDEVICE) Object;
+ PDEVICE_CONTEXT deviceContext = GetDeviceContext(device);
+ NTSTATUS status;
+ WDFKEY key = NULL;
+ UNICODE_STRING pdoString = {0};
+
+ DECLARE_CONST_UNICODE_STRING(deviceSubkey, SERIAL_DEVICE_MAP);
+
+ if (deviceContext->CreatedLegacyHardwareKey == TRUE) {
+
+ RtlInitUnicodeString(&pdoString, deviceContext->PdoName);
+
+ status = WdfDeviceOpenDevicemapKey(device,
+ &deviceSubkey,
+ KEY_SET_VALUE,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &key);
+
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to open DEVICEMAP\\SERIALCOMM key 0x%x", status);
+ goto exit;
+ }
+
+ status = WdfRegistryRemoveValue(key,
+ &pdoString);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to delete %S key, 0x%x", pdoString.Buffer, status);
+ goto exit;
+ }
+
+ status = WdfRegistryRemoveKey(key);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: Failed to delete %S, 0x%x", SERIAL_DEVICE_MAP, status);
+ goto exit;
+ }
+ }
+
+exit:
+
+ if (key != NULL) {
+ WdfRegistryClose(key);
+ key = NULL;
+ }
+
+ return;
+}
+
+
+ULONG
+GetBaudRate(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ return DeviceContext->BaudRate;
+}
+
+VOID
+SetBaudRate(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ ULONG BaudRate
+ )
+{
+ DeviceContext->BaudRate = BaudRate;
+}
+
+ULONG *
+GetModemControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ return &DeviceContext->ModemControlRegister;
+}
+
+ULONG *
+GetFifoControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ return &DeviceContext->FifoControlRegister;
+}
+
+ULONG *
+GetLineControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ return &DeviceContext->LineControlRegister;
+}
+
+VOID
+SetValidDataMask(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ UCHAR Mask
+ )
+{
+ DeviceContext->ValidDataMask = Mask;
+}
+
+VOID
+SetTimeouts(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ SERIAL_TIMEOUTS Timeouts
+ )
+{
+ DeviceContext->Timeouts = Timeouts;
+}
+
+VOID
+GetTimeouts(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _Out_ SERIAL_TIMEOUTS *Timeouts
+ )
+{
+ *Timeouts = DeviceContext->Timeouts;
+}
diff --git a/serial/VirtualSerial2/device.h b/serial/VirtualSerial2/device.h
new file mode 100644
index 00000000..e2718841
--- /dev/null
+++ b/serial/VirtualSerial2/device.h
@@ -0,0 +1,122 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Device.h
+
+Abstract:
+
+ This module contains the type definitions for the VirtualSerial sample
+ driver's device callback class.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+#pragma once
+
+#define SYMBOLIC_LINK_NAME_LENGTH 32
+#define SYMBOLIC_LINK_NAME_PREFIX L"\\DosDevices\\Global\\"
+#define REG_PATH_DEVICEMAP L"HARDWARE\\DEVICEMAP"
+#define SERIAL_DEVICE_MAP L"SERIALCOMM"
+#define REG_VALUENAME_PORTNAME L"PortName"
+#define REG_PATH_SERIALCOMM REG_PATH_DEVICEMAP L"\\" SERIAL_DEVICE_MAP
+
+typedef struct _DEVICE_CONTEXT
+{
+ WDFDEVICE Device;
+
+ ULONG BaudRate;
+
+ ULONG ModemControlRegister;
+
+ ULONG FifoControlRegister;
+
+ ULONG LineControlRegister;
+
+ UCHAR ValidDataMask;
+
+ SERIAL_TIMEOUTS Timeouts;
+
+ BOOLEAN CreatedLegacyHardwareKey;
+
+ PWSTR PdoName;
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext);
+
+
+NTSTATUS
+DeviceCreate(
+ _In_ WDFDRIVER Driver,
+ _In_ PWDFDEVICE_INIT DeviceInit,
+ _Out_ PDEVICE_CONTEXT *DeviceContext
+ );
+
+NTSTATUS
+DeviceConfigure(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+DeviceGetPdoName(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+DeviceWriteLegacyHardwareKey(
+ _In_ PWSTR PdoName,
+ _In_ PWSTR ComPort,
+ _In_ WDFDEVICE Device
+ );
+
+EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDeviceCleanup;
+
+ULONG
+GetBaudRate(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+SetBaudRate(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ ULONG BaudRate
+ );
+
+ULONG *
+GetModemControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+ULONG *
+GetFifoControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+ULONG *
+GetLineControlRegisterPtr(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+SetValidDataMask(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ UCHAR Mask
+ );
+
+VOID
+SetTimeouts(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _In_ SERIAL_TIMEOUTS Timeouts
+ );
+
+VOID
+GetTimeouts(
+ _In_ PDEVICE_CONTEXT DeviceContext,
+ _Out_ SERIAL_TIMEOUTS *Timeouts
+ ); \ No newline at end of file
diff --git a/serial/VirtualSerial2/driver.c b/serial/VirtualSerial2/driver.c
new file mode 100644
index 00000000..bb7f4c73
--- /dev/null
+++ b/serial/VirtualSerial2/driver.c
@@ -0,0 +1,72 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Driver.c
+
+Abstract:
+
+ This module contains the implementation of the VirtualSerial Sample's
+ core driver callback object.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+#include <initguid.h>
+#include "internal.h"
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG driverConfig;
+
+ WDF_DRIVER_CONFIG_INIT(&driverConfig,
+ EvtDeviceAdd);
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &driverConfig,
+ WDF_NO_HANDLE);
+ if (!NT_SUCCESS(status)) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfDriverCreate failed 0x%x", status);
+ return status;
+ }
+
+ return status;
+}
+
+NTSTATUS
+EvtDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+{
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+
+ status = DeviceCreate(Driver,
+ DeviceInit,
+ &deviceContext);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ status = DeviceConfigure(deviceContext);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ return status;
+}
+
diff --git a/serial/VirtualSerial2/driver.h b/serial/VirtualSerial2/driver.h
new file mode 100644
index 00000000..787cef02
--- /dev/null
+++ b/serial/VirtualSerial2/driver.h
@@ -0,0 +1,30 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Driver.h
+
+Abstract:
+
+ This module contains the type definitions for the VirtualSerial sample's
+ driver callback class.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+#pragma once
+
+//
+// This class handles driver events for the VirtualSerial 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.
+//
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd;
diff --git a/serial/VirtualSerial2/internal.h b/serial/VirtualSerial2/internal.h
new file mode 100644
index 00000000..82c149e3
--- /dev/null
+++ b/serial/VirtualSerial2/internal.h
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Internal.h
+
+Abstract:
+
+ This module contains the local type definitions for the VirtualSerial
+ driver sample.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+#pragma once
+
+#ifdef _KERNEL_MODE
+#include <ntddk.h>
+#else
+#include <windows.h>
+#endif
+
+#include <wdf.h>
+
+#define _NTDEF_
+
+//
+// Include the type specific headers.
+//
+#include "serial.h"
+#include "driver.h"
+#include "device.h"
+#include "ringbuffer.h"
+#include "queue.h"
+
+//
+// Tracing and Assert
+//
+
+#define Trace(level, _fmt_, ...) \
+ DbgPrintEx(DPFLTR_DEFAULT_ID, level, \
+ _fmt_ "\n", __VA_ARGS__)
+
+#define TRACE_LEVEL_ERROR DPFLTR_ERROR_LEVEL
+#define TRACE_LEVEL_INFO DPFLTR_INFO_LEVEL
+
+#ifndef ASSERT
+#define ASSERT(exp) { \
+ if (!(exp)) { \
+ RtlAssert(#exp, __FILE__, __LINE__, NULL); \
+ } \
+}
+#endif \ No newline at end of file
diff --git a/serial/VirtualSerial2/queue.c b/serial/VirtualSerial2/queue.c
new file mode 100644
index 00000000..80571b42
--- /dev/null
+++ b/serial/VirtualSerial2/queue.c
@@ -0,0 +1,963 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Queue.c
+
+Abstract:
+
+ This file implements the I/O queue interface and performs
+ the read/write/ioctl operations.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+
+#include "internal.h"
+
+NTSTATUS
+QueueCreate(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device = DeviceContext->Device;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+ WDF_OBJECT_ATTRIBUTES queueAttributes;
+ WDFQUEUE queue;
+ PQUEUE_CONTEXT queueContext;
+
+ //
+ // Create the default queue
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel);
+
+ queueConfig.EvtIoRead = EvtIoRead;
+ queueConfig.EvtIoWrite = EvtIoWrite;
+ queueConfig.EvtIoDeviceControl = EvtIoDeviceControl;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
+ &queueAttributes,
+ QUEUE_CONTEXT);
+
+ status = WdfIoQueueCreate(
+ device,
+ &queueConfig,
+ &queueAttributes,
+ &queue);
+
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfIoQueueCreate failed 0x%x", status);
+ return status;
+ }
+
+ queueContext = GetQueueContext(queue);
+ queueContext->Queue = queue;
+ queueContext->DeviceContext = DeviceContext;
+
+ //
+ // Create a manual queue to hold pending read requests. By keeping
+ // them in the queue, framework takes care of cancelling them if the app
+ // exits
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &queueConfig,
+ WdfIoQueueDispatchManual);
+
+ status = WdfIoQueueCreate(
+ device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue);
+
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfIoQueueCreate manual queue failed 0x%x", status);
+ return status;
+ }
+
+ queueContext->ReadQueue = queue;
+
+ //
+ // Create another manual queue to hold pending IOCTL_SERIAL_WAIT_ON_MASK
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &queueConfig,
+ WdfIoQueueDispatchManual);
+
+ status = WdfIoQueueCreate(
+ device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue);
+
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfIoQueueCreate manual queue failed 0x%x", status);
+ return status;
+ }
+
+ queueContext->WaitMaskQueue = queue;
+
+ RingBufferInitialize(&queueContext->RingBuffer,
+ queueContext->Buffer,
+ sizeof(queueContext->Buffer));
+
+ return status;
+}
+
+
+NTSTATUS
+RequestCopyFromBuffer(
+ _In_ WDFREQUEST Request,
+ _In_ PVOID SourceBuffer,
+ _In_ size_t NumBytesToCopyFrom
+ )
+{
+ NTSTATUS status;
+ WDFMEMORY memory;
+
+ status = WdfRequestRetrieveOutputMemory(Request, &memory);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestRetrieveOutputMemory failed 0x%x", status);
+ return status;
+ }
+
+ status = WdfMemoryCopyFromBuffer(memory, 0,
+ SourceBuffer, NumBytesToCopyFrom);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfMemoryCopyFromBuffer failed 0x%x", status);
+ return status;
+ }
+
+ WdfRequestSetInformation(Request, NumBytesToCopyFrom);
+ return status;
+}
+
+
+NTSTATUS
+RequestCopyToBuffer(
+ _In_ WDFREQUEST Request,
+ _In_ PVOID DestinationBuffer,
+ _In_ size_t NumBytesToCopyTo
+ )
+{
+ NTSTATUS status;
+ WDFMEMORY memory;
+
+ status = WdfRequestRetrieveInputMemory(Request, &memory);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestRetrieveInputMemory failed 0x%x", status);
+ return status;
+ }
+
+ status = WdfMemoryCopyToBuffer(memory, 0,
+ DestinationBuffer, NumBytesToCopyTo);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfMemoryCopyToBuffer failed 0x%x", status);
+ return status;
+ }
+
+ WdfRequestSetInformation(Request, NumBytesToCopyTo);
+ return status;
+}
+
+
+VOID
+EvtIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+{
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext = GetQueueContext(Queue);
+ PDEVICE_CONTEXT deviceContext = queueContext->DeviceContext;
+ UNREFERENCED_PARAMETER (OutputBufferLength);
+ UNREFERENCED_PARAMETER (InputBufferLength);
+
+ Trace(TRACE_LEVEL_INFO,
+ "EvtIoDeviceControl 0x%x", IoControlCode);
+
+ switch (IoControlCode)
+ {
+
+ case IOCTL_SERIAL_SET_BAUD_RATE:
+ {
+ //
+ // This is a driver for a virtual serial port. Since there is no
+ // actual hardware, we just store the baud rate and don't do
+ // anything with it.
+ //
+ SERIAL_BAUD_RATE baudRateBuffer = {0};
+
+ status = RequestCopyToBuffer(Request,
+ &baudRateBuffer,
+ sizeof(baudRateBuffer));
+
+ if( NT_SUCCESS(status) ) {
+ SetBaudRate(deviceContext, baudRateBuffer.BaudRate);
+ };
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_BAUD_RATE:
+ {
+ SERIAL_BAUD_RATE baudRateBuffer = {0};
+
+ baudRateBuffer.BaudRate = GetBaudRate(deviceContext);
+
+ status = RequestCopyFromBuffer(Request,
+ &baudRateBuffer,
+ sizeof(baudRateBuffer));
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_MODEM_CONTROL:
+ {
+ //
+ // This is a driver for a virtual serial port. Since there is no
+ // actual hardware, we just store the modem control register
+ // configuration and don't do anything with it.
+ //
+ ULONG *modemControlRegister = GetModemControlRegisterPtr(deviceContext);
+
+ ASSERT(modemControlRegister);
+
+ status = RequestCopyToBuffer(Request,
+ modemControlRegister,
+ sizeof(ULONG));
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_MODEM_CONTROL:
+ {
+ ULONG *modemControlRegister = GetModemControlRegisterPtr(deviceContext);
+
+ ASSERT(modemControlRegister);
+
+ status = RequestCopyFromBuffer(Request,
+ modemControlRegister,
+ sizeof(ULONG));
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_FIFO_CONTROL:
+ {
+ //
+ // This is a driver for a virtual serial port. Since there is no
+ // actual hardware, we just store the FIFO control register
+ // configuration and don't do anything with it.
+ //
+ ULONG *fifoControlRegister = GetFifoControlRegisterPtr(deviceContext);
+
+ ASSERT(fifoControlRegister);
+
+ status = RequestCopyToBuffer(Request,
+ fifoControlRegister,
+ sizeof(ULONG));
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_LINE_CONTROL:
+ {
+ status = QueueProcessGetLineControl(
+ queueContext,
+ Request);
+ break;
+ }
+
+
+ case IOCTL_SERIAL_SET_LINE_CONTROL:
+ {
+ status = QueueProcessSetLineControl(
+ queueContext,
+ Request);
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_TIMEOUTS:
+ {
+ SERIAL_TIMEOUTS timeoutValues = {0};
+
+ status = RequestCopyFromBuffer(Request,
+ (void*) &timeoutValues,
+ sizeof(timeoutValues));
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_TIMEOUTS:
+ {
+ SERIAL_TIMEOUTS timeoutValues = {0};
+
+ status = RequestCopyToBuffer(Request,
+ (void*) &timeoutValues,
+ sizeof(timeoutValues));
+
+ if( NT_SUCCESS(status) )
+ {
+ if ((timeoutValues.ReadIntervalTimeout == MAXULONG) &&
+ (timeoutValues.ReadTotalTimeoutMultiplier == MAXULONG) &&
+ (timeoutValues.ReadTotalTimeoutConstant == MAXULONG))
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if( NT_SUCCESS(status) ) {
+ SetTimeouts(deviceContext, timeoutValues);
+ }
+
+ break;
+ }
+
+ case IOCTL_SERIAL_WAIT_ON_MASK:
+ {
+ //
+ // NOTE: A wait-on-mask request should not be completed until either:
+ // 1) A wait event occurs; or
+ // 2) A set-wait-mask request is received
+ //
+ // This is a driver for a virtual serial port. Since there is no
+ // actual hardware, we complete the request with some failure code.
+ //
+ WDFREQUEST savedRequest;
+
+ status = WdfIoQueueRetrieveNextRequest(
+ queueContext->WaitMaskQueue,
+ &savedRequest);
+
+ if (NT_SUCCESS(status)) {
+ WdfRequestComplete(savedRequest,
+ STATUS_UNSUCCESSFUL);
+ }
+
+ //
+ // Keep the request in a manual queue and the framework will take
+ // care of cancelling them when the app exits
+ //
+ status = WdfRequestForwardToIoQueue(
+ Request,
+ queueContext->WaitMaskQueue);
+
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestForwardToIoQueue failed 0x%x", status);
+ WdfRequestComplete(Request, status);
+ }
+
+ //
+ // Instead of "break", use "return" to prevent the current request
+ // from being completed.
+ //
+ return;
+ }
+
+ case IOCTL_SERIAL_SET_WAIT_MASK:
+ {
+ //
+ // NOTE: If a wait-on-mask request is already pending when set-wait-mask
+ // request is processed, the pending wait-on-event request is completed
+ // with STATUS_SUCCESS and the output wait event mask is set to zero.
+ //
+ WDFREQUEST savedRequest;
+
+ status = WdfIoQueueRetrieveNextRequest(
+ queueContext->WaitMaskQueue,
+ &savedRequest);
+
+ if (NT_SUCCESS(status)) {
+
+ ULONG eventMask = 0;
+ status = RequestCopyFromBuffer(
+ savedRequest,
+ &eventMask,
+ sizeof(eventMask));
+
+ WdfRequestComplete(savedRequest, status);
+ }
+
+ //
+ // NOTE: The application expects STATUS_SUCCESS for these IOCTLs.
+ //
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_QUEUE_SIZE:
+ case IOCTL_SERIAL_SET_DTR:
+ case IOCTL_SERIAL_SET_RTS:
+ case IOCTL_SERIAL_CLR_RTS:
+ case IOCTL_SERIAL_SET_XON:
+ case IOCTL_SERIAL_SET_XOFF:
+ case IOCTL_SERIAL_SET_CHARS:
+ case IOCTL_SERIAL_GET_CHARS:
+ case IOCTL_SERIAL_GET_HANDFLOW:
+ case IOCTL_SERIAL_SET_HANDFLOW:
+ case IOCTL_SERIAL_RESET_DEVICE:
+ //
+ // NOTE: The application expects STATUS_SUCCESS for these IOCTLs.
+ //
+ status = STATUS_SUCCESS;
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // complete the request
+ //
+ WdfRequestComplete(Request, status);
+}
+
+
+VOID
+EvtIoWrite(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t Length
+ )
+{
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext = GetQueueContext(Queue);
+ WDFMEMORY memory;
+ WDFREQUEST savedRequest;
+ size_t availableData = 0;
+
+ Trace(TRACE_LEVEL_INFO,
+ "EvtIoWrite 0x%p", Request);
+
+ status = WdfRequestRetrieveInputMemory(Request, &memory);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestRetrieveInputMemory failed 0x%x", status);
+ return;
+ }
+
+ //
+ // Process input
+ //
+ status = QueueProcessWriteBytes(
+ queueContext,
+ (PUCHAR)WdfMemoryGetBuffer(memory, NULL),
+ Length);
+ if( !NT_SUCCESS(status) ) {
+ return;
+ }
+
+ WdfRequestCompleteWithInformation(Request, status, Length);
+
+ //
+ // Get the amount of data available in the ring buffer
+ //
+ RingBufferGetAvailableData(
+ &queueContext->RingBuffer,
+ &availableData);
+
+ if (availableData == 0) {
+ return;
+ }
+
+ //
+ // Continue with the next request, if there is one pending
+ //
+ for ( ; ; ) {
+
+ status = WdfIoQueueRetrieveNextRequest(
+ queueContext->ReadQueue,
+ &savedRequest);
+
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+
+ status = WdfRequestForwardToIoQueue(
+ savedRequest,
+ Queue);
+
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestForwardToIoQueue failed 0x%x", status);
+ WdfRequestComplete(savedRequest, status);
+ }
+ }
+}
+
+
+VOID
+EvtIoRead(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t Length
+ )
+{
+ NTSTATUS status;
+ PQUEUE_CONTEXT queueContext = GetQueueContext(Queue);
+ WDFMEMORY memory;
+ size_t bytesCopied = 0;
+
+ Trace(TRACE_LEVEL_INFO,
+ "EvtIoRead 0x%p", Request);
+
+ status = WdfRequestRetrieveOutputMemory(Request, &memory);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestRetrieveOutputMemory failed 0x%x", status);
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ status = RingBufferRead(&queueContext->RingBuffer,
+ (BYTE*)WdfMemoryGetBuffer(memory, NULL),
+ Length,
+ &bytesCopied);
+ if( !NT_SUCCESS(status) ) {
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ if (bytesCopied > 0) {
+ //
+ // Data was read from buffer succesfully
+ //
+ WdfRequestCompleteWithInformation(Request, status, bytesCopied);
+ return;
+ }
+ else {
+ //
+ // No data to read. Queue the request for later processing.
+ //
+ status = WdfRequestForwardToIoQueue(Request,
+ queueContext->ReadQueue);
+ if( !NT_SUCCESS(status) ) {
+ Trace(TRACE_LEVEL_ERROR,
+ "Error: WdfRequestForwardToIoQueue failed 0x%x", status);
+ WdfRequestComplete(Request, status);
+ }
+ }
+}
+
+
+NTSTATUS
+QueueProcessWriteBytes(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_reads_bytes_(Length)
+ PUCHAR Characters,
+ _In_ size_t Length
+ )
+/*++
+Routine Description:
+
+ This function is called when the framework receives IRP_MJ_WRITE
+ requests from the system. The write event handler(FmEvtIoWrite) calls ProcessWriteBytes.
+ It parses the Characters passed in and looks for the for sequences "AT" -ok ,
+ "ATA" --CONNECT, ATD<number> -- CONNECT and sets the state of the device appropriately.
+ These bytes are placed in the read Buffer to be processed later since this device
+ works in a loopback fashion.
+
+Arguments:
+
+ Characters - Pointer to the write IRP's system buffer.
+
+ Length - Length of the IO operation
+ 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.
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UCHAR currentCharacter;
+ UCHAR connectString[] = "\r\nCONNECT\r\n";
+ UCHAR connectStringCch = ARRAY_SIZE(connectString) - 1;
+ UCHAR okString[] = "\r\nOK\r\n";
+ UCHAR okStringCch = ARRAY_SIZE(okString) - 1;
+
+ while (Length != 0) {
+
+ currentCharacter = *(Characters++);
+ Length--;
+
+ if(currentCharacter == '\0') {
+ continue;
+ }
+
+ status = RingBufferWrite(&QueueContext->RingBuffer,
+ &currentCharacter,
+ sizeof(currentCharacter));
+ if( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ switch (QueueContext->CommandMatchState) {
+
+ case COMMAND_MATCH_STATE_IDLE:
+
+ if ((currentCharacter == 'a') || (currentCharacter == 'A')) {
+ //
+ // got an A
+ //
+ QueueContext->CommandMatchState = COMMAND_MATCH_STATE_GOT_A;
+ QueueContext->ConnectCommand = FALSE;
+ QueueContext->IgnoreNextChar = FALSE;
+ }
+ break;
+
+ case COMMAND_MATCH_STATE_GOT_A:
+
+ if ((currentCharacter == 't') || (currentCharacter == 'T')) {
+ //
+ // got a T
+ //
+ QueueContext->CommandMatchState = COMMAND_MATCH_STATE_GOT_T;
+ }
+ else {
+ QueueContext->CommandMatchState = COMMAND_MATCH_STATE_IDLE;
+ }
+
+ break;
+
+ case COMMAND_MATCH_STATE_GOT_T:
+
+ if (! QueueContext->IgnoreNextChar) {
+ //
+ // the last char was not a special char
+ // check for CONNECT command
+ //
+ if ((currentCharacter == 'A') || (currentCharacter == 'a')) {
+ QueueContext->ConnectCommand = TRUE;
+ }
+
+ if ((currentCharacter == 'D') || (currentCharacter == 'd')) {
+ QueueContext->ConnectCommand = TRUE;
+ }
+ }
+
+ QueueContext->IgnoreNextChar = TRUE;
+
+ if (currentCharacter == '\r') {
+ //
+ // got a CR, send a response to the command
+ //
+ QueueContext->CommandMatchState = COMMAND_MATCH_STATE_IDLE;
+
+ if (QueueContext->ConnectCommand) {
+ //
+ // place <cr><lf>CONNECT<cr><lf> in the buffer
+ //
+ status = RingBufferWrite(&QueueContext->RingBuffer,
+ connectString,
+ connectStringCch);
+ if( !NT_SUCCESS(status) ) {
+ return status;
+ }
+ //
+ // connected now raise CD
+ //
+ QueueContext->CurrentlyConnected = TRUE;
+ QueueContext->ConnectionStateChanged = TRUE;
+ }
+ else {
+ //
+ // place <cr><lf>OK<cr><lf> in the buffer
+ //
+ status = RingBufferWrite(&QueueContext->RingBuffer,
+ okString,
+ okStringCch);
+ if( !NT_SUCCESS(status) ) {
+ return status;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return status;
+}
+
+
+NTSTATUS
+QueueProcessGetLineControl(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_ WDFREQUEST Request
+ )
+{
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+ SERIAL_LINE_CONTROL lineControl = {0};
+ ULONG lineControlSnapshot;
+ ULONG *lineControlRegister;
+
+ deviceContext = QueueContext->DeviceContext;
+ lineControlRegister = GetLineControlRegisterPtr(deviceContext);
+
+ ASSERT(lineControlRegister);
+
+ //
+ // Take a snapshot of the line control register variable
+ //
+ lineControlSnapshot = *lineControlRegister;
+
+ //
+ // Decode the word length
+ //
+ if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_5_DATA)
+ {
+ lineControl.WordLength = 5;
+ }
+ else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_6_DATA)
+ {
+ lineControl.WordLength = 6;
+ }
+ else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_7_DATA)
+ {
+ lineControl.WordLength = 7;
+ }
+ else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_8_DATA)
+ {
+ lineControl.WordLength = 8;
+ }
+
+ //
+ // Decode the parity
+ //
+ if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY)
+ {
+ lineControl.Parity = NO_PARITY;
+ }
+ else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY)
+ {
+ lineControl.Parity = ODD_PARITY;
+ }
+ else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY)
+ {
+ lineControl.Parity = EVEN_PARITY;
+ }
+ else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY)
+ {
+ lineControl.Parity = MARK_PARITY;
+ }
+ else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY)
+ {
+ lineControl.Parity = SPACE_PARITY;
+ }
+
+ //
+ // Decode the length of the stop bit
+ //
+ if (lineControlSnapshot & SERIAL_2_STOP)
+ {
+ if (lineControl.WordLength == 5)
+ {
+ lineControl.StopBits = STOP_BITS_1_5;
+ }
+ else
+ {
+ lineControl.StopBits = STOP_BITS_2;
+ }
+ }
+ else
+ {
+ lineControl.StopBits = STOP_BIT_1;
+ }
+
+ //
+ // Copy the information that was decoded to the caller's buffer
+ //
+ status = RequestCopyFromBuffer(Request,
+ (void*) &lineControl,
+ sizeof(lineControl));
+ return status;
+}
+
+
+NTSTATUS
+QueueProcessSetLineControl(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_ WDFREQUEST Request
+ )
+{
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+ SERIAL_LINE_CONTROL lineControl = {0};
+ ULONG *lineControlRegister;
+ UCHAR lineControlData = 0;
+ UCHAR lineControlStop = 0;
+ UCHAR lineControlParity = 0;
+ ULONG lineControlSnapshot;
+ ULONG lineControlNew;
+ ULONG lineControlPrevious;
+ ULONG i;
+
+ deviceContext = QueueContext->DeviceContext;
+ lineControlRegister = GetLineControlRegisterPtr(deviceContext);
+
+ ASSERT(lineControlRegister);
+
+ //
+ // This is a driver for a virtual serial port. Since there is no
+ // actual hardware, we just store the line control register
+ // configuration and don't do anything with it.
+ //
+ status = RequestCopyToBuffer(Request,
+ (void*) &lineControl,
+ sizeof(lineControl));
+
+ //
+ // Bits 0 and 1 of the line control register
+ //
+ if( NT_SUCCESS(status) )
+ {
+ switch (lineControl.WordLength)
+ {
+ case 5:
+ lineControlData = SERIAL_5_DATA;
+ SetValidDataMask(deviceContext, 0x1f);
+ break;
+
+ case 6:
+ lineControlData = SERIAL_6_DATA;
+ SetValidDataMask(deviceContext, 0x3f);
+ break;
+
+ case 7:
+ lineControlData = SERIAL_7_DATA;
+ SetValidDataMask(deviceContext, 0x7f);
+ break;
+
+ case 8:
+ lineControlData = SERIAL_8_DATA;
+ SetValidDataMask(deviceContext, 0xff);
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ //
+ // Bit 2 of the line control register
+ //
+ if( NT_SUCCESS(status) )
+ {
+ switch (lineControl.StopBits)
+ {
+ case STOP_BIT_1:
+ lineControlStop = SERIAL_1_STOP;
+ break;
+
+ case STOP_BITS_1_5:
+ if (lineControlData != SERIAL_5_DATA)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ lineControlStop = SERIAL_1_5_STOP;
+ break;
+
+ case STOP_BITS_2:
+ if (lineControlData == SERIAL_5_DATA)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ lineControlStop = SERIAL_2_STOP;
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ //
+ // Bits 3, 4 and 5 of the line control register
+ //
+ if( NT_SUCCESS(status) )
+ {
+ switch (lineControl.Parity)
+ {
+ case NO_PARITY:
+ lineControlParity = SERIAL_NONE_PARITY;
+ break;
+
+ case EVEN_PARITY:
+ lineControlParity = SERIAL_EVEN_PARITY;
+ break;
+
+ case ODD_PARITY:
+ lineControlParity = SERIAL_ODD_PARITY;
+ break;
+
+ case SPACE_PARITY:
+ lineControlParity = SERIAL_SPACE_PARITY;
+ break;
+
+ case MARK_PARITY:
+ lineControlParity = SERIAL_MARK_PARITY;
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ //
+ // Update our line control register variable atomically
+ //
+ i=0;
+ do {
+ i++;
+ if ((i & 0xf) == 0) {
+ //
+ // We've been spinning in a loop for a while trying to
+ // update the line control register variable atomically.
+ // Yield the CPU for other threads for a while.
+ //
+#ifdef _KERNEL_MODE
+ LARGE_INTEGER interval;
+ interval.QuadPart = 0;
+ KeDelayExecutionThread(UserMode, FALSE, &interval);
+#else
+ SwitchToThread();
+#endif
+ }
+
+ lineControlSnapshot = *lineControlRegister;
+
+ lineControlNew = (lineControlSnapshot & SERIAL_LCR_BREAK) |
+ (lineControlData | lineControlParity | lineControlStop);
+
+ lineControlPrevious = InterlockedCompareExchange(
+ (LONG *) lineControlRegister,
+ lineControlNew,
+ lineControlSnapshot);
+
+ } while (lineControlPrevious != lineControlSnapshot);
+
+ return status;
+}
diff --git a/serial/VirtualSerial2/queue.h b/serial/VirtualSerial2/queue.h
new file mode 100644
index 00000000..909d699b
--- /dev/null
+++ b/serial/VirtualSerial2/queue.h
@@ -0,0 +1,113 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file defines the queue callback interface.
+
+Environment:
+
+ Windows Driver Framework
+
+--*/
+
+#pragma once
+
+#include "internal.h"
+
+// Set ring buffer size
+#define DATA_BUFFER_SIZE 1024
+
+//
+// Device states
+//
+#define COMMAND_MATCH_STATE_IDLE 0
+#define COMMAND_MATCH_STATE_GOT_A 1
+#define COMMAND_MATCH_STATE_GOT_T 2
+
+//
+// Define useful macros
+//
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+#define MAXULONG 0xffffffff
+
+typedef struct _QUEUE_CONTEXT
+{
+ UCHAR CommandMatchState;
+
+ BOOLEAN ConnectCommand;
+
+ BOOLEAN IgnoreNextChar;
+
+ BOOLEAN ConnectionStateChanged;
+
+ BOOLEAN CurrentlyConnected;
+
+ RING_BUFFER RingBuffer; // Ring buffer for pending data
+
+ BYTE Buffer[DATA_BUFFER_SIZE];
+
+ WDFQUEUE Queue; // Default parallel queue
+
+ WDFQUEUE ReadQueue; // Manual queue for pending reads
+
+ WDFQUEUE WaitMaskQueue; // Manual queue for pending ioctl wait-on-mask
+
+ PDEVICE_CONTEXT DeviceContext;
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, GetQueueContext);
+
+EVT_WDF_IO_QUEUE_IO_READ EvtIoRead;
+EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite;
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl;
+
+NTSTATUS
+QueueCreate(
+ _In_ PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+QueueProcessWriteBytes(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_reads_bytes_(Length)
+ PUCHAR Characters,
+ _In_ size_t Length
+ );
+
+NTSTATUS
+QueueProcessGetLineControl(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_ WDFREQUEST Request
+ );
+
+NTSTATUS
+QueueProcessSetLineControl(
+ _In_ PQUEUE_CONTEXT QueueContext,
+ _In_ WDFREQUEST Request
+ );
+
+NTSTATUS
+RequestCopyFromBuffer(
+ _In_ WDFREQUEST Request,
+ _In_ PVOID SourceBuffer,
+ _In_ size_t NumBytesToCopyFrom
+ );
+
+NTSTATUS
+RequestCopyToBuffer(
+ _In_ WDFREQUEST Request,
+ _In_ PVOID DestinationBuffer,
+ _In_ size_t NumBytesToCopyTo
+ );
+
diff --git a/serial/VirtualSerial2/ringbuffer.c b/serial/VirtualSerial2/ringbuffer.c
new file mode 100644
index 00000000..0efbe821
--- /dev/null
+++ b/serial/VirtualSerial2/ringbuffer.c
@@ -0,0 +1,338 @@
+/*++
+
+Copyright (c) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ RingBuffer.c
+
+Abstract:
+
+ This file implements the Ring Buffer
+
+Environment:
+
+--*/
+
+#include "internal.h"
+
+VOID
+RingBufferInitialize(
+ _In_ PRING_BUFFER Self,
+ _In_reads_bytes_(BufferSize)
+ BYTE* Buffer,
+ _In_ size_t BufferSize
+ )
+{
+ Self->Size = BufferSize;
+ Self->Base = Buffer;
+ Self->End = Buffer + BufferSize;
+ Self->Head = Buffer;
+ Self->Tail = Buffer;
+}
+
+
+VOID
+RingBufferGetAvailableSpace(
+ _In_ PRING_BUFFER Self,
+ _Out_ size_t *AvailableSpace
+ )
+{
+ BYTE* headSnapshot = NULL;
+ BYTE* tailSnapshot = NULL;
+ BYTE* tailPlusOne = NULL;
+
+ ASSERT(AvailableSpace);
+
+ //
+ // Take a snapshot of the head and tail pointers. We will compute the
+ // available space based on this snapshot. This is safe to do in a
+ // single-producer, single-consumer model, because -
+ // * A producer will call GetAvailableSpace() to determine whether
+ // there is enough space to write the data it is trying to write.
+ // The only other thread that could modify the amount of space
+ // available is the consumer thread, which can only increase the
+ // amount of space available. Hence it is safe for the producer
+ // to write based on this snapshot.
+ // * A consumer thread will call GetAvailableSpace() to determine
+ // whether there is enough data in the buffer for it to read.
+ // (Available data = Buffer size - Available space). The only
+ // other thread that could modify the amount of space available
+ // is the producer thread, which can only decrease the amount of
+ // space available (thereby increasing the amount of data
+ // available. Hence it is safe for the consumer to read based on
+ // this snapshot.
+ //
+ headSnapshot = Self->Head;
+ tailSnapshot = Self->Tail;
+
+ //
+ // In order to distinguish between a full buffer and an empty buffer,
+ // we always leave the last byte of the buffer unused. So, an empty
+ // buffer is denoted by -
+ // tail == head
+ // ... and a full buffer is denoted by -
+ // (tail+1) == head
+ //
+ tailPlusOne = ((tailSnapshot+1) == Self->End) ? Self->Base : (tailSnapshot+1);
+
+ if (tailPlusOne == headSnapshot)
+ {
+ //
+ // Buffer full
+ //
+ *AvailableSpace = 0;
+ }
+ else if (tailSnapshot == headSnapshot)
+ {
+ //
+ // Buffer empty
+ // The -1 in the computation below is to account for the fact that
+ // we always leave the last byte of the ring buffer unused in order
+ // to distinguish between an empty buffer and a full buffer.
+ //
+ *AvailableSpace = Self->Size - 1;
+ }
+ else
+ {
+ if (tailSnapshot > headSnapshot)
+ {
+ //
+ // Data has not wrapped around the end of the buffer
+ // The -1 in the computation below is to account for the fact
+ // that we always leave the last byte of the ring buffer unused
+ // in order to distinguish between an empty buffer and a full
+ // buffer.
+ //
+ *AvailableSpace = Self->Size - (tailSnapshot - headSnapshot) - 1;
+ }
+ else
+ {
+ //
+ // Data has wrapped around the end of the buffer
+ // The -1 in the computation below is to account for the fact
+ // that we always leave the last byte of the ring buffer unused
+ // in order to distinguish between an empty buffer and a full
+ // buffer.
+ //
+ *AvailableSpace = (headSnapshot - tailSnapshot) - 1;
+ }
+ }
+}
+
+
+VOID
+RingBufferGetAvailableData(
+ _In_ PRING_BUFFER Self,
+ _Out_ size_t *AvailableData
+ )
+{
+ size_t availableSpace;
+
+ ASSERT(AvailableData);
+
+ RingBufferGetAvailableSpace(Self, &availableSpace);
+
+ //
+ // The -1 in the arithmetic below accounts for the fact that we always
+ // keep 1 byte of the ring buffer unused in order to distinguish
+ // between a full buffer and an empty buffer.
+ //
+ *AvailableData = Self->Size - availableSpace - 1;
+}
+
+
+NTSTATUS
+RingBufferWrite(
+ _In_ PRING_BUFFER Self,
+ _In_reads_bytes_(DataSize)
+ BYTE* Data,
+ _In_ size_t DataSize
+ )
+{
+ size_t availableSpace;
+ size_t bytesToCopy;
+ size_t spaceFromCurrToEnd;
+
+ ASSERT(Data && (0 != DataSize));
+
+ if (Self->Tail >= Self->End)
+ {
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ //
+ // Get the amount of space available in the buffer
+ //
+ RingBufferGetAvailableSpace(Self, &availableSpace);
+
+ //
+ // If there is not enough space to fit in all the data passed in by the
+ // caller then copy as much as possible and throw away the rest
+ //
+ if (availableSpace < DataSize)
+ {
+ bytesToCopy = availableSpace;
+ }
+ else
+ {
+ bytesToCopy = DataSize;
+ }
+
+ if (bytesToCopy)
+ {
+ //
+ // The buffer has some space at least
+ //
+ if ((Self->Tail + bytesToCopy) > Self->End)
+ {
+ //
+ // The data being written will wrap around the end of the buffer.
+ // So the copy has to be done in two steps -
+ // * X bytes from current position to end of the buffer
+ // * the remaining (bytesToCopy - X) from the start of the buffer
+ //
+
+ //
+ // The first step of the copy ...
+ //
+ spaceFromCurrToEnd = Self->End - Self->Tail;
+
+ RtlCopyMemory(Self->Tail, Data, spaceFromCurrToEnd);
+
+ Data += spaceFromCurrToEnd;
+
+ bytesToCopy -= spaceFromCurrToEnd;
+
+ //
+ // The second step of the copy ...
+ //
+ RtlCopyMemory(Self->Base, Data, bytesToCopy);
+
+ //
+ // Advance the tail pointer
+ //
+ Self->Tail = Self->Base + bytesToCopy;
+ }
+ else
+ {
+ //
+ // Data does NOT wrap around the end of the buffer. Just copy it
+ // over in a single step
+ //
+ RtlCopyMemory(Self->Tail, Data, bytesToCopy);
+
+ //
+ // Advance the tail pointer
+ //
+ Self->Tail += bytesToCopy;
+ if (Self->Tail == Self->End)
+ {
+ //
+ // We have exactly reached the end of the buffer. The next
+ // write should wrap around and start from the beginning.
+ //
+ Self->Tail = Self->Base;
+ }
+ }
+
+ ASSERT(Self->Tail < Self->End);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+RingBufferRead(
+ _In_ PRING_BUFFER Self,
+ _Out_writes_bytes_to_(DataSize, *BytesCopied)
+ BYTE* Data,
+ _In_ size_t DataSize,
+ _Out_ size_t *BytesCopied
+ )
+{
+ size_t availableData;
+ size_t dataFromCurrToEnd;
+
+ ASSERT(Data && (DataSize != 0));
+
+ if (Self->Head >= Self->End)
+ {
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ //
+ // Get the amount of data available in the buffer
+ //
+ RingBufferGetAvailableData(Self, &availableData);
+
+ if (availableData == 0)
+ {
+ *BytesCopied = 0;
+ return STATUS_SUCCESS;
+ }
+
+ if (DataSize > availableData)
+ {
+ DataSize = availableData;
+ }
+
+ *BytesCopied = DataSize;
+
+ if ((Self->Head + DataSize) > Self->End)
+ {
+ //
+ // The data requested by the caller is wrapped around the end of the
+ // buffer. So we'll do the copy in two steps -
+ // * Copy X bytes from the current position to the end buffer into
+ // the caller's buffer
+ // * Copy (DataSize - X) bytes from the beginning to the buffer into
+ // the caller's buffer
+ //
+
+ //
+ // The first step of the copy ...
+ //
+ dataFromCurrToEnd = Self->End - Self->Head;
+ RtlCopyMemory(Data, Self->Head, dataFromCurrToEnd);
+ Data += dataFromCurrToEnd;
+ DataSize -= dataFromCurrToEnd;
+
+ //
+ // The second step of the copy ...
+ //
+ RtlCopyMemory(Data, Self->Base, DataSize);
+
+ //
+ // Advance the head pointer
+ //
+ Self->Head = Self->Base + DataSize;
+ }
+ else
+ {
+ //
+ // The data in the buffer is NOT wrapped around the end of the buffer.
+ // Simply copy the data over to the caller's buffer in a single step.
+ //
+ RtlCopyMemory(Data, Self->Head, DataSize);
+
+ //
+ // Advance the head pointer
+ //
+ Self->Head += DataSize;
+ if (Self->Head == Self->End)
+ {
+ //
+ // We have exactly reached the end of the buffer. The next
+ // read should wrap around and start from the beginning.
+ //
+ Self->Head = Self->Base;
+ }
+ }
+
+ ASSERT(Self->Head < Self->End);
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/serial/VirtualSerial2/ringbuffer.h b/serial/VirtualSerial2/ringbuffer.h
new file mode 100644
index 00000000..8c5e3e39
--- /dev/null
+++ b/serial/VirtualSerial2/ringbuffer.h
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Ringbuffer.h
+
+--*/
+
+#pragma once
+
+typedef struct _RING_BUFFER
+{
+ //
+ // The size in bytes of the ring buffer.
+ //
+ size_t Size;
+
+ //
+ // A pointer to the base of the ring buffer.
+ //
+ BYTE* Base;
+
+ //
+ // A pointer to the byte beyond the end of the ring buffer. Used for
+ // quick comparisons when determining if we need to wrap.
+ //
+ BYTE* End;
+
+ //
+ // A pointer to the current read point in the ring buffer.
+ //
+ // Updates to this are not protected by any lock. This is different from
+ // the write pointer, which is protected by the "pending read pointer"
+ // lock. The reason for this difference is that in this driver, we do not
+ // keep write requests pending. If there is not enough space to write all
+ // the data that was requested, we write as much as we can and drop the
+ // rest (lossy data transfer).
+ //
+ // If we had multiple threads modifying this pointer, then that would
+ // provide yet another reason for protecting updates to the pointer using a
+ // lock. However, in this driver, at any given time we have only one thread
+ // that modifies this pointer (the thread that runs the read callback).
+ // This is true because we use a sequential queue for read requests. If we
+ // were to change our read queue to be a parallel queue, this would no
+ // longer be true.
+ //
+ //
+ BYTE* Head;
+
+ //
+ // A pointer to the current write point in the ring buffer.
+ //
+ // Updates to this pointer are protected by the "pending read pointer
+ // lock", because we do not want a consumer thread to mark a read request
+ // as pending while we are in the process of writing data to the buffer.
+ // The reason is that the write that we are currently performing might
+ // actually supply enough data to satisfy the read request, in which case
+ // it should not be marked pending at all.
+ // If the read request were to be marked pending in the situation described
+ // above, then we would need some trigger to later retrieve the request and
+ // complete it. In our driver, arrival of data is the only event that can
+ // trigger this. So if no more data arrives, the request will remain
+ // pending forever, even though there is enough data in the buffer to
+ // complete it. Hence we do not keep a read request pending in situations
+ // where the read buffer contains enough data to satisfy it.
+ //
+ // If we had multiple threads modifying this pointer, then that would
+ // provide yet another reason for protecting updates to the pointer using a
+ // lock. However, in this driver, at any given time we have only one thread
+ // that modifies this pointer (the thread that runs the write callback).
+ // This is true because we use a sequential queue for write requests. If we
+ // were to change our write queue to be a parallel queue, this would no
+ // longer be true.
+ //
+ BYTE* Tail;
+
+} RING_BUFFER, *PRING_BUFFER;
+
+
+VOID
+RingBufferInitialize(
+ _In_ PRING_BUFFER Self,
+ _In_reads_bytes_(BufferSize)
+ BYTE* Buffer,
+ _In_ size_t BufferSize
+ );
+
+NTSTATUS
+RingBufferWrite(
+ _In_ PRING_BUFFER Self,
+ _In_reads_bytes_(DataSize)
+ BYTE* Data,
+ _In_ size_t DataSize
+ );
+
+NTSTATUS
+RingBufferRead(
+ _In_ PRING_BUFFER Self,
+ _Out_writes_bytes_to_(DataSize, *BytesCopied)
+ BYTE* Data,
+ _In_ size_t DataSize,
+ _Out_ size_t *BytesCopied
+ );
+
+VOID
+RingBufferGetAvailableSpace(
+ _In_ PRING_BUFFER Self,
+ _Out_ size_t *AvailableSpace
+ );
+
+VOID
+RingBufferGetAvailableData(
+ _In_ PRING_BUFFER Self,
+ _Out_ size_t *AvailableData
+ );
diff --git a/serial/VirtualSerial2/serial.h b/serial/VirtualSerial2/serial.h
new file mode 100644
index 00000000..223c1ceb
--- /dev/null
+++ b/serial/VirtualSerial2/serial.h
@@ -0,0 +1,128 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Serial.h
+
+Abstract:
+
+ Type definitions and data for the serial port driver
+
+--*/
+
+#pragma once
+
+//
+// This defines the bit used to control whether the device is sending
+// a break. When this bit is set the device is sending a space (logic 0).
+//
+// Most protocols will assume that this is a hangup.
+//
+#define SERIAL_LCR_BREAK 0x40
+
+//
+// These defines are used to set the line control register.
+//
+#define SERIAL_5_DATA ((UCHAR)0x00)
+#define SERIAL_6_DATA ((UCHAR)0x01)
+#define SERIAL_7_DATA ((UCHAR)0x02)
+#define SERIAL_8_DATA ((UCHAR)0x03)
+#define SERIAL_DATA_MASK ((UCHAR)0x03)
+
+#define SERIAL_1_STOP ((UCHAR)0x00)
+#define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits
+#define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits
+#define SERIAL_STOP_MASK ((UCHAR)0x04)
+
+#define SERIAL_NONE_PARITY ((UCHAR)0x00)
+#define SERIAL_ODD_PARITY ((UCHAR)0x08)
+#define SERIAL_EVEN_PARITY ((UCHAR)0x18)
+#define SERIAL_MARK_PARITY ((UCHAR)0x28)
+#define SERIAL_SPACE_PARITY ((UCHAR)0x38)
+#define SERIAL_PARITY_MASK ((UCHAR)0x38)
+
+#ifdef _KERNEL_MODE
+
+#include <ntddser.h>
+
+#else
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Instead of #include <ntddser.h>, the following are copied from that header,
+// as ntddser.h is conflicted with winioctl.h which is included from wdf.h
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#define IOCTL_SERIAL_SET_BAUD_RATE CTL_CODE(FILE_DEVICE_SERIAL_PORT, 1,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_QUEUE_SIZE CTL_CODE(FILE_DEVICE_SERIAL_PORT, 2,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_LINE_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT, 3,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_BREAK_ON CTL_CODE(FILE_DEVICE_SERIAL_PORT, 4,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_BREAK_OFF CTL_CODE(FILE_DEVICE_SERIAL_PORT, 5,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_IMMEDIATE_CHAR CTL_CODE(FILE_DEVICE_SERIAL_PORT, 6,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_TIMEOUTS CTL_CODE(FILE_DEVICE_SERIAL_PORT, 7,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_TIMEOUTS CTL_CODE(FILE_DEVICE_SERIAL_PORT, 8,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_DTR CTL_CODE(FILE_DEVICE_SERIAL_PORT, 9,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_CLR_DTR CTL_CODE(FILE_DEVICE_SERIAL_PORT,10,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_RESET_DEVICE CTL_CODE(FILE_DEVICE_SERIAL_PORT,11,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_RTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,12,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_CLR_RTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,13,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_XOFF CTL_CODE(FILE_DEVICE_SERIAL_PORT,14,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_XON CTL_CODE(FILE_DEVICE_SERIAL_PORT,15,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_WAIT_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,16,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_WAIT_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,17,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_WAIT_ON_MASK CTL_CODE(FILE_DEVICE_SERIAL_PORT,18,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_PURGE CTL_CODE(FILE_DEVICE_SERIAL_PORT,19,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_BAUD_RATE CTL_CODE(FILE_DEVICE_SERIAL_PORT,20,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_LINE_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,21,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_CHARS CTL_CODE(FILE_DEVICE_SERIAL_PORT,22,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_CHARS CTL_CODE(FILE_DEVICE_SERIAL_PORT,23,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_HANDFLOW CTL_CODE(FILE_DEVICE_SERIAL_PORT,24,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_HANDFLOW CTL_CODE(FILE_DEVICE_SERIAL_PORT,25,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_MODEMSTATUS CTL_CODE(FILE_DEVICE_SERIAL_PORT,26,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_COMMSTATUS CTL_CODE(FILE_DEVICE_SERIAL_PORT,27,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_XOFF_COUNTER CTL_CODE(FILE_DEVICE_SERIAL_PORT,28,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_PROPERTIES CTL_CODE(FILE_DEVICE_SERIAL_PORT,29,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_GET_DTRRTS CTL_CODE(FILE_DEVICE_SERIAL_PORT,30,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+#define IOCTL_SERIAL_GET_MODEM_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,37,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_MODEM_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,38,METHOD_BUFFERED,FILE_ANY_ACCESS)
+#define IOCTL_SERIAL_SET_FIFO_CONTROL CTL_CODE(FILE_DEVICE_SERIAL_PORT,39,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+
+typedef struct _SERIAL_BAUD_RATE {
+ ULONG BaudRate;
+ } SERIAL_BAUD_RATE,*PSERIAL_BAUD_RATE;
+
+typedef struct _SERIAL_LINE_CONTROL {
+ UCHAR StopBits;
+ UCHAR Parity;
+ UCHAR WordLength;
+ } SERIAL_LINE_CONTROL,*PSERIAL_LINE_CONTROL;
+
+typedef struct _SERIAL_TIMEOUTS {
+ ULONG ReadIntervalTimeout;
+ ULONG ReadTotalTimeoutMultiplier;
+ ULONG ReadTotalTimeoutConstant;
+ ULONG WriteTotalTimeoutMultiplier;
+ ULONG WriteTotalTimeoutConstant;
+ } SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS;
+
+#define STOP_BIT_1 0
+#define STOP_BITS_1_5 1
+#define STOP_BITS_2 2
+
+#define NO_PARITY 0
+#define ODD_PARITY 1
+#define EVEN_PARITY 2
+#define MARK_PARITY 3
+#define SPACE_PARITY 4
+
+#endif // #ifdef _KERNEL_MODE, #include <ntddser.h>
+
+//
+// DEFINE_GUID(GUID_DEVINTERFACE_MODEM, 0x2c7089aa, 0x2e0e, 0x11d1, 0xb1, 0x14, 0x00, 0xc0, 0x4f, 0xc2, 0xaa, 0xe4);
+//
+#include <ntddmodm.h>