Remove VirtualSerial2 directory and all its contents

Co-authored-by: ekinnee <1707617+ekinnee@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-08-06 21:58:05 +00:00
parent 1881bfb8cc
commit bcbafbf8b3
20 changed files with 0 additions and 2988 deletions

View file

@ -1,187 +0,0 @@
<?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>{65A037CB-9245-442A-A791-5CFC34E97BF7}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<SampleGuid>{D3E77C62-C6F0-4210-824E-1875C7B48EC5}</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" />
<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="*.inx" />
<FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
</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>

View file

@ -1,40 +0,0 @@
<?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>{75562F82-D2DC-4C96-8D1E-01C195D61A2C}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
<UniqueIdentifier>{0748F304-5FE6-4C01-B27A-3CD7B1A268B7}</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>{87F14B94-F7A4-42E8-9931-8ADDA3989EBD}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
<UniqueIdentifier>{30F678DB-C12C-461E-8128-CE409AAC9C42}</UniqueIdentifier>
</Filter>
</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>

View file

@ -1,17 +0,0 @@
//---------------------------------------------------------------------------
// 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"

View file

@ -1,17 +0,0 @@
//---------------------------------------------------------------------------
// 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"

View file

@ -1,187 +0,0 @@
<?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>{CD78D78F-B132-4E6F-A11F-B62185A6152A}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<SampleGuid>{3E00ED06-5DB5-444F-8FFA-D098A0218DF2}</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" />
<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="*.inx" />
<FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
</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>

View file

@ -1,40 +0,0 @@
<?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>{5A926099-4361-4BDC-BF0F-D98AD6F55C3A}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
<UniqueIdentifier>{9C5FC831-BCE8-4E84-8BED-0B1182AA7358}</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>{43B83C13-0033-4A5E-A0DB-F0BA1B304FB0}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
<UniqueIdentifier>{83A3125A-7FA1-4416-B24A-FA9C1EECAAF0}</UniqueIdentifier>
</Filter>
</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>

View file

@ -1,64 +0,0 @@
---
page_type: sample
urlFragment: virtual-serial-driver-sample-v2
description: "Demonstrates UMDF version 2 serial drivers and includes a simple virtual serial driver (ComPort) and a controller-less modem driver (FakeModem)."
languages:
- cpp
products:
- windows
- windows-wdk
---
# Virtual serial driver sample (V2)
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 the [Serial Controller Driver Design Guide](https://docs.microsoft.com/windows-hardware/drivers/serports/).
## Code tour
### comsup.cpp and 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 and 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 and driver.h
- Definition and implementation of the device callback class (CMyDriver) for the sample. This includes events on the framework device object.
### queue.cpp and 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.

View file

@ -1,46 +0,0 @@

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", "{F7F21610-DDE7-4709-9C48-68A0ABD1FF65}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FakeModem", "FakeModem", "{704FA9C6-88FA-4381-8FA5-3407E62FAF20}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VirtualSerial2um", "ComPort\VirtualSerial2um.vcxproj", "{65A037CB-9245-442A-A791-5CFC34E97BF7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem2um", "FakeModem\fakemodem2um.vcxproj", "{CD78D78F-B132-4E6F-A11F-B62185A6152A}"
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
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Debug|Win32.ActiveCfg = Debug|Win32
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Debug|Win32.Build.0 = Debug|Win32
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Release|Win32.ActiveCfg = Release|Win32
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Release|Win32.Build.0 = Release|Win32
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Debug|x64.ActiveCfg = Debug|x64
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Debug|x64.Build.0 = Debug|x64
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Release|x64.ActiveCfg = Release|x64
{65A037CB-9245-442A-A791-5CFC34E97BF7}.Release|x64.Build.0 = Release|x64
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Debug|Win32.ActiveCfg = Debug|Win32
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Debug|Win32.Build.0 = Debug|Win32
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Release|Win32.ActiveCfg = Release|Win32
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Release|Win32.Build.0 = Release|Win32
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Debug|x64.ActiveCfg = Debug|x64
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Debug|x64.Build.0 = Debug|x64
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Release|x64.ActiveCfg = Release|x64
{CD78D78F-B132-4E6F-A11F-B62185A6152A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{65A037CB-9245-442A-A791-5CFC34E97BF7} = {F7F21610-DDE7-4709-9C48-68A0ABD1FF65}
{CD78D78F-B132-4E6F-A11F-B62185A6152A} = {704FA9C6-88FA-4381-8FA5-3407E62FAF20}
EndGlobalSection
EndGlobal

View file

@ -1,449 +0,0 @@
/*++
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,
NonPagedPoolNx,
&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;
}

View file

@ -1,122 +0,0 @@
/*++
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
);

View file

@ -1,72 +0,0 @@
/*++
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;
}

View file

@ -1,30 +0,0 @@
/*++
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;

View file

@ -1,58 +0,0 @@
/*++
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

View file

@ -1,963 +0,0 @@
/*++
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;
}

View file

@ -1,113 +0,0 @@
/*++
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
);

View file

@ -1,338 +0,0 @@
/*++
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;
}

View file

@ -1,117 +0,0 @@
/*++
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
);

View file

@ -1,128 +0,0 @@
/*++
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>