diff options
| author | Dave Wilson <[email protected]> | 2015-04-29 09:48:49 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-04-29 10:47:29 -0700 |
| commit | d40232638faaab19de557e70a3ee938da7a35295 (patch) | |
| tree | 14e61c973745949af186b7940e3a53d25322f5de /serial/VirtualSerial2 | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'serial/VirtualSerial2')
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, + ¤tCharacter, + 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> |
