summaryrefslogtreecommitdiff
path: root/SPB/SpbTestTool/exe
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /SPB/SpbTestTool/exe
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'SPB/SpbTestTool/exe')
-rw-r--r--SPB/SpbTestTool/exe/SpbTestTool.vcxproj204
-rw-r--r--SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters28
-rw-r--r--SPB/SpbTestTool/exe/command.cpp660
-rw-r--r--SPB/SpbTestTool/exe/command.h638
-rw-r--r--SPB/SpbTestTool/exe/internal.h99
-rw-r--r--SPB/SpbTestTool/exe/main.cpp633
-rw-r--r--SPB/SpbTestTool/exe/util.cpp250
7 files changed, 2512 insertions, 0 deletions
diff --git a/SPB/SpbTestTool/exe/SpbTestTool.vcxproj b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj
new file mode 100644
index 00000000..88f1e6a5
--- /dev/null
+++ b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj
@@ -0,0 +1,204 @@
+<?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>{D98724B9-FEB8-4D51-B807-1D83E324A9AD}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{418E967E-17B4-4EA7-9D97-735BA0A2EE70}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>SpbTestTool</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>SpbTestTool</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>SpbTestTool</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>SpbTestTool</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="command.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="util.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters
new file mode 100644
index 00000000..e2c07bad
--- /dev/null
+++ b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters
@@ -0,0 +1,28 @@
+<?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>{E51F9248-08FA-42B8-80B9-2B287C503100}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{CC896E5F-EEB8-4743-8F57-FAD8C296E752}</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>{CEA4D39C-0E96-45C5-97EF-3245169C1997}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="command.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/SPB/SpbTestTool/exe/command.cpp b/SPB/SpbTestTool/exe/command.cpp
new file mode 100644
index 00000000..fa559266
--- /dev/null
+++ b/SPB/SpbTestTool/exe/command.cpp
@@ -0,0 +1,660 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ command.cpp
+
+Abstract:
+
+ This module contains the class definitions for the various
+ SpbTestTool commands.
+
+Environment:
+
+ user-mode
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+
+long CCommand::s_Index = 1;
+
+VOID
+PrintCommands()
+{
+ printf("\n");
+ printf("Commands:\n");
+ printf(" open open handle to SPB controller\n");
+ printf(" close close handle to SPB controller\n");
+ printf(" lock lock the bus for exclusive access\n");
+ printf(" unlock unlock the bus\n");
+ printf(" lockconn lock the shared connection for exclusive access -\n");
+ printf(" this primitive is used to synchronize with op-region\n");
+ printf(" accesses by firmware\n");
+ printf(" unlockconn unlock the shared connection\n");
+ printf(" write {} write byte array to peripheral\n");
+ printf(" > write {01 02 03}\n");
+ printf(" read <numBytes> read <numBytes> from peripheral\n");
+ printf(" > read 5\n");
+ printf(" writeread {} <numBytes> atomically write byte array to peripheral\n");
+ printf(" and read <numBytes> back\n");
+ printf(" > writeread {01 02 03} 5\n");
+ printf(" fullduplex {} <numBytes> simultaneously write byte array to peripheral\n");
+ printf(" and read <numBytes> back\n");
+ printf(" > full duplex {01 02 03} 5\n");
+ printf(" signal inform the SpbTestTool driver that the\n");
+ printf(" interrupt has been handled\n");
+ printf(" help print command list\n");
+ printf("\n");
+}
+
+PCCommand
+CCommand::_ParseCommand(
+ _In_ __drv_when(return != nullptr, __drv_aliasesMem) list<string> *Parameters
+ )
+{
+ string tag;
+ string name;
+
+ PCCommand command = nullptr;
+
+ if (Parameters->front()[0] == L'@')
+ {
+ if (PopStringParameter(Parameters, &tag) == false)
+ {
+ printf("Error - could not pop tag\n");
+ return nullptr;
+ }
+ }
+
+ if (PopStringParameter(Parameters, &name) == false)
+ {
+ return nullptr;
+ }
+
+ if(_stricmp(name.c_str(), "open") == 0)
+ {
+ command = new COpenCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "close") == 0)
+ {
+ command = new CCloseCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "lock") == 0)
+ {
+ command = new CLockCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "unlock") == 0)
+ {
+ command = new CUnlockCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "lockconn") == 0)
+ {
+ command = new CLockConnectionCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "unlockconn") == 0)
+ {
+ command = new CUnlockConnectionCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "read") == 0)
+ {
+ command = new CReadCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "write") == 0)
+ {
+ command = new CWriteCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "writeread") == 0)
+ {
+ command = new CWriteReadCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "fullduplex") == 0)
+ {
+ command = new CFullDuplexCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "signal") == 0)
+ {
+ command = new CSignalInterruptCommand(Parameters, tag);
+ }
+ else if(_stricmp(name.c_str(), "help") == 0)
+ {
+ PrintCommands();
+ return nullptr;
+ }
+ else
+ {
+ printf("unrecognized command %s\n", name.c_str());
+ PrintCommands();
+ return nullptr;
+ }
+
+ if (command->Parse() == false)
+ {
+ command->DetachParameter(); //avoid double deletion
+ delete command;
+ return nullptr;
+ }
+
+ return command;
+}
+
+bool
+COpenCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Open peripheral target
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_OPEN,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+COpenCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Peripheral target opened\n");
+ }
+}
+
+bool
+CCloseCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Close peripheral target
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_CLOSE,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CCloseCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Peripheral target closed\n");
+ }
+}
+
+bool
+CLockCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Lock controller for peripheral target
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_LOCK,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CLockCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Controller locked\n");
+ }
+}
+
+bool
+CUnlockCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Unlock controller
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_UNLOCK,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CUnlockCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Controller unlocked\n");
+ }
+}
+
+bool
+CLockConnectionCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Lock connection for peripheral target
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_LOCK_CONNECTION,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CLockConnectionCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Peripheral target locked\n");
+ }
+}
+
+bool
+CUnlockConnectionCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Unlock connection
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_UNLOCK_CONNECTION,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CUnlockConnectionCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Peripheral target unlocked\n");
+ }
+}
+
+bool
+CReadCommand::Execute(
+ VOID
+ )
+{
+ ULONG bytesRead;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((ReadFile(File,
+ Buffer,
+ Length,
+ &bytesRead,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesRead);
+ }
+
+ return true;
+}
+
+void
+CReadCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", Status);
+ }
+ else
+ {
+ printf("%u bytes read\n", Information);
+ PrintBytes(Information, Buffer);
+ }
+}
+
+bool
+CWriteCommand::Execute(
+ VOID
+ )
+{
+ ULONG bytesWritten;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((WriteFile(File,
+ Buffer,
+ Length,
+ &bytesWritten,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesWritten);
+ }
+
+ return true;
+}
+
+
+void
+CWriteCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", Status);
+ }
+ else
+ {
+ printf("%u bytes written\n", Information);
+ }
+}
+
+bool
+CWriteReadCommand::Execute(
+ VOID
+ )
+{
+ ULONG bytesTransferred;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(File,
+ IOCTL_SPBTESTTOOL_WRITEREAD,
+ WriteBuffer,
+ WriteLength,
+ Buffer,
+ ReadLength,
+ &bytesTransferred,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesTransferred);
+ }
+
+ return true;
+}
+
+void
+CWriteReadCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("%u bytes returned\n", Information);
+ PrintBytes(Information, Buffer);
+ }
+}
+
+bool
+CFullDuplexCommand::Execute(
+ VOID
+ )
+{
+ ULONG bytesTransferred;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(File,
+ IOCTL_SPBTESTTOOL_FULL_DUPLEX,
+ WriteBuffer,
+ WriteLength,
+ Buffer,
+ ReadLength,
+ &bytesTransferred,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesTransferred);
+ }
+
+ return true;
+}
+
+void
+CFullDuplexCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("%u bytes returned\n", Information);
+ PrintBytes(Information, Buffer);
+ }
+}
+
+bool
+CSignalInterruptCommand::Execute(
+ VOID
+ )
+{
+ //
+ // Signal interrupt
+ //
+
+ ULONG bytesReturned;
+
+ if (File == nullptr)
+ {
+ return false;
+ }
+
+ if ((DeviceIoControl(
+ File,
+ IOCTL_SPBTESTTOOL_SIGNAL_INTERRUPT,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ &bytesReturned,
+ &Overlapped) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ FakeCompletion(GetLastError(), bytesReturned);
+ }
+
+ return true;
+}
+
+void
+CSignalInterruptCommand::Complete(
+ _In_ DWORD Status,
+ _In_ DWORD /* Information */
+ )
+{
+ if (Status != NO_ERROR)
+ {
+ printf("Error %u\n", GetLastError());
+ }
+ else
+ {
+ printf("Interrupt signalled\n");
+ }
+}
diff --git a/SPB/SpbTestTool/exe/command.h b/SPB/SpbTestTool/exe/command.h
new file mode 100644
index 00000000..5e2633bd
--- /dev/null
+++ b/SPB/SpbTestTool/exe/command.h
@@ -0,0 +1,638 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ command.h
+
+Abstract:
+
+ This module contains the class declarations for the various
+ SpbTestTool commands.
+
+Environment:
+
+ user-mode
+
+Revision History:
+
+--*/
+
+typedef struct CCommand CCommand, *PCCommand;
+
+pair<ULONG, PBYTE>
+ParseBuffer(
+ _In_ list<string> *Parameters,
+ _In_ list<string>::iterator Start
+ );
+
+VOID
+PrintCommands();
+
+struct CCommand
+{
+public:
+
+ long Index;
+ string Type;
+ list<string> *Parameters;
+
+ //
+ // File handle this command is being run against (if any).
+ //
+
+ HANDLE File;
+
+ //
+ // Overlapped structure for this command to use.
+ //
+
+ OVERLAPPED Overlapped;
+
+ //
+ // Handle to the thread for this command (if run asynchronously)
+ // The thread is signalled when the command is complete.
+ //
+
+ HANDLE Thread;
+
+ //
+ // Common parameters.
+ //
+
+ string Address;
+ PBYTE Buffer;
+
+ static long s_Index;
+
+ CCommand(
+ _In_ string Type,
+ _In_ __drv_aliasesMem list<string> *Tokens
+ ) : Type(Type),
+ Thread(nullptr),
+ Parameters(Tokens),
+ Address(""),
+ Buffer(nullptr),
+ File(nullptr)
+ {
+ ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
+ Index = s_Index;
+ s_Index += 1;
+ return;
+ }
+
+ virtual
+ ~CCommand(
+ void
+ )
+ {
+ delete[] Buffer;
+ delete Parameters;
+ }
+
+ virtual
+ bool
+ Parse(
+ void
+ )
+ {
+ File = g_Peripheral;
+ return true;
+ }
+
+ void
+ DetachParameter(
+ void
+ )
+ {
+ Parameters = nullptr;
+ }
+
+
+ typedef
+ void
+ (FN_PARSE)(
+ _In_ list<string>::const_iterator &Iterator
+ );
+
+public:
+
+ static
+ PCCommand
+ _ParseCommand(
+ _In_ __drv_when(return != nullptr, __drv_aliasesMem) list<string> *Tokens
+ );
+
+public:
+
+ VOID
+ FakeCompletion(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+ {
+ Overlapped.Internal = Status == NO_ERROR ? Status : HRESULT_FROM_WIN32(Status);
+ Overlapped.InternalHigh = Information;
+ SetEvent(Overlapped.hEvent);
+ }
+
+ virtual
+ bool
+ Execute(
+ VOID
+ ) = 0;
+
+ virtual
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ )
+ {
+ printf("%s completed with status %u, information %u\n",
+ Type.c_str(),
+ Status,
+ Information);
+ }
+
+ virtual
+ bool
+ Cancel(
+ VOID
+ )
+ {
+ if (File != nullptr)
+ {
+ return CancelIoEx(File, &Overlapped) ? true : false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+};
+
+class COpenCommand : public CCommand
+{
+private:
+
+public:
+ COpenCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("open", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CCloseCommand : public CCommand
+{
+private:
+
+public:
+ CCloseCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("close", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CLockCommand : public CCommand
+{
+private:
+
+public:
+ CLockCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("lock", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CUnlockCommand : public CCommand
+{
+private:
+
+public:
+ CUnlockCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("unlock", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CLockConnectionCommand : public CCommand
+{
+private:
+
+public:
+ CLockConnectionCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("lockconn", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CUnlockConnectionCommand : public CCommand
+{
+private:
+
+public:
+ CUnlockConnectionCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("unlockconn", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CReadCommand : public CCommand
+{
+private:
+ ULONG Length;
+
+public:
+
+ CReadCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("read", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Parse(
+ void
+ )
+ {
+ if (CCommand::Parse() == false)
+ {
+ return false;
+ }
+
+ if (PopNumberParameter(Parameters, 10, &Length) == false)
+ {
+ printf("Length required\n");
+ return false;
+ }
+
+ if (Length > 0)
+ {
+ Buffer = new BYTE[Length];
+ ZeroMemory(Buffer, Length);
+ }
+ else
+ {
+ Buffer = nullptr;
+ }
+
+ return true;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+
+class CWriteCommand : public CCommand
+{
+private:
+ ULONG Length;
+
+public:
+
+ CWriteCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("write", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Parse(
+ VOID
+ )
+ {
+ if (CCommand::Parse() == false)
+ {
+ return false;
+ }
+
+ pair<ULONG, PBYTE> buf;
+
+ if (PopBufferParameter(Parameters, &buf) == false)
+ {
+ printf("Buffer required\n");
+ return false;
+ }
+
+ Length = buf.first;
+ Buffer = buf.second;
+
+ return true;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CWriteReadCommand : public CCommand
+{
+private:
+ ULONG WriteLength;
+ ULONG ReadLength;
+
+ PBYTE WriteBuffer;
+
+public:
+
+ CWriteReadCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("writeread", Parameters)
+ {
+ WriteBuffer = NULL;
+ return;
+ }
+
+ ~CWriteReadCommand(
+ void
+ )
+ {
+ delete[] WriteBuffer;
+ }
+
+ bool
+ Parse(
+ void
+ )
+ {
+ if (CCommand::Parse() == false)
+ {
+ return false;
+ }
+
+ pair<ULONG, PBYTE> buf;
+
+ if (PopBufferParameter(Parameters, &buf) == false)
+ {
+ printf("Buffer required\n");
+ return false;
+ }
+
+ WriteLength = buf.first;
+ WriteBuffer = buf.second;
+
+ if (PopNumberParameter(Parameters, 10, &ReadLength) == false)
+ {
+ printf("Length required\n");
+ return false;
+ }
+
+ if (ReadLength > 0)
+ {
+ Buffer = new BYTE[ReadLength];
+ ZeroMemory(Buffer, ReadLength);
+ }
+ else
+ {
+ Buffer = nullptr;
+ }
+
+ return true;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CFullDuplexCommand : public CCommand
+{
+private:
+ ULONG WriteLength;
+ ULONG ReadLength;
+
+ PBYTE WriteBuffer;
+
+public:
+
+ CFullDuplexCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("fullduplex", Parameters)
+ {
+ WriteBuffer = NULL;
+ return;
+ }
+
+ ~CFullDuplexCommand(
+ void
+ )
+ {
+ delete[] WriteBuffer;
+ }
+
+ bool
+ Parse(
+ void
+ )
+ {
+ if (CCommand::Parse() == false)
+ {
+ return false;
+ }
+
+ pair<ULONG, PBYTE> buf;
+
+ if (PopBufferParameter(Parameters, &buf) == false)
+ {
+ printf("Buffer required\n");
+ return false;
+ }
+
+ WriteLength = buf.first;
+ WriteBuffer = buf.second;
+
+ if (PopNumberParameter(Parameters, 10, &ReadLength) == false)
+ {
+ printf("Length required\n");
+ return false;
+ }
+
+ if (ReadLength > 0)
+ {
+ Buffer = new BYTE[ReadLength];
+ ZeroMemory(Buffer, ReadLength);
+ }
+ else
+ {
+ Buffer = nullptr;
+ }
+
+ return true;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CSignalInterruptCommand : public CCommand
+{
+private:
+
+public:
+ CSignalInterruptCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("signal", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
+
+class CWaitOnInterruptCommand : public CCommand
+{
+private:
+
+public:
+ CWaitOnInterruptCommand(
+ _In_ __drv_aliasesMem list<string> *Parameters,
+ _In_opt_ string Tag
+ ) : CCommand("waitoninterrupt", Parameters)
+ {
+ return;
+ }
+
+ bool
+ Execute(
+ VOID
+ );
+
+ void
+ Complete(
+ _In_ DWORD Status,
+ _In_ DWORD Information
+ );
+};
diff --git a/SPB/SpbTestTool/exe/internal.h b/SPB/SpbTestTool/exe/internal.h
new file mode 100644
index 00000000..268186c0
--- /dev/null
+++ b/SPB/SpbTestTool/exe/internal.h
@@ -0,0 +1,99 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ internal.h
+
+Abstract:
+
+ This module contains the internal type definitations and
+ helper function declarations for the SpbTestTool app.
+
+Environment:
+
+ user-mode
+
+Revision History:
+
+--*/
+
+#include <string>
+#include <map>
+#include <list>
+#include <map>
+#include <functional>
+
+#include <iomanip>
+
+#include <cstdlib>
+
+#include <stdexcept>
+
+#include <math.h>
+
+#include <wchar.h>
+#include <windows.h>
+#include <winioctl.h>
+#include <specstrings.h>
+
+#include "spbtestioctl.h"
+
+using namespace std;
+
+//
+// Global Variables
+//
+
+extern HANDLE g_Peripheral;
+
+typedef pair<ULONG, PBYTE> BUFPAIR;
+typedef list<BUFPAIR> BUFLIST;
+
+VOID
+PrintBytes(
+ _In_ ULONG BufferCb,
+ _In_reads_bytes_(BufferCb) BYTE Buffer[]
+ );
+
+_Success_(return)
+bool
+PopStringParameter(
+ _Inout_ list<string> *Parameters,
+ _Out_ string *Value,
+ _Out_opt_ bool *Present = nullptr
+ );
+
+typedef pair<ULONG,ULONG> bounds;
+
+_Success_(return)
+bool
+PopNumberParameter(
+ _Inout_ list<string> *Parameters,
+ _In_ ULONG Radix,
+ _Out_ ULONG *Value,
+ _In_opt_ pair<ULONG,ULONG> Bounds = bounds(0,0),
+ _Out_opt_ bool *Present = nullptr
+ );
+
+_Success_(return)
+bool
+ParseNumber(
+ _In_ const string &String,
+ _In_ ULONG Radix,
+ _Out_ ULONG *Value,
+ _In_opt_ bounds Bounds = bounds(0,0)
+ );
+
+_Success_(return)
+bool
+PopBufferParameter(
+ _Inout_ list<string> *Parameters,
+ _Out_ pair<ULONG, PBYTE> *Value
+ );
+
+
+#define countof(x) (sizeof(x) / sizeof(x[0]))
+
+#include "command.h"
diff --git a/SPB/SpbTestTool/exe/main.cpp b/SPB/SpbTestTool/exe/main.cpp
new file mode 100644
index 00000000..ce9e994a
--- /dev/null
+++ b/SPB/SpbTestTool/exe/main.cpp
@@ -0,0 +1,633 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ main.cpp
+
+Abstract:
+
+ This module contains the main entry point for the SpbTestTool
+ app. It facilitates accepting input, building commands, and
+ printing output.
+
+Environment:
+
+ user-mode
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+
+DWORD WINAPI InterruptNotificationThread(
+ _In_ LPVOID pvData
+ );
+
+bool
+ReadCommandFromStream(
+ _In_ FILE* InputStream,
+ _Inout_ list<string> *Tokens
+ );
+
+VOID
+PrintUsage(
+ _In_ PCSTR exeName
+ );
+
+DWORD
+RunCommand(
+ _In_ PCCommand Command
+ );
+
+HANDLE g_Peripheral = nullptr;
+HANDLE g_Event = nullptr;
+HANDLE g_InterruptNotificationThread = nullptr;
+PCCommand g_CurrentCommand = nullptr;
+bool g_WaitOnInterrupt = true;
+
+BOOL
+WINAPI
+OnControlKey(
+ _In_ DWORD ControlType
+ );
+
+void
+__cdecl
+main(
+ _In_ ULONG ArgumentsCe,
+ _In_reads_(ArgumentsCe) PCSTR Arguments[]
+ )
+{
+ FILE* inputStream = stdin;
+ bool prompt = true;
+
+ PCSTR peripheralPath = nullptr;
+ PCSTR inputPath = nullptr;
+
+ //
+ // Parse the command line arguments.
+ //
+
+ ULONG arg = 1;
+
+ while (arg < ArgumentsCe)
+ {
+ if ((Arguments[arg][0] != '/') &&
+ (Arguments[arg][0] != '-'))
+ {
+ PrintUsage(Arguments[0]);
+ goto exit;
+ }
+ else
+ {
+ if (tolower(Arguments[arg][1]) == 'p')
+ {
+ arg++;
+ if (arg == ArgumentsCe)
+ {
+ PrintUsage(Arguments[0]);
+ goto exit;
+ }
+ peripheralPath = Arguments[arg];
+ }
+ else if (tolower(Arguments[arg][1]) == 'i')
+ {
+ arg++;
+ if (arg == ArgumentsCe)
+ {
+ PrintUsage(Arguments[0]);
+ goto exit;
+ }
+ inputPath = Arguments[arg];
+ }
+ else
+ {
+ PrintUsage(Arguments[0]);
+ goto exit;
+ }
+ }
+
+ arg++;
+ }
+
+ //
+ // Open the input file if specified
+ //
+
+ if (inputPath != nullptr)
+ {
+ errno_t error;
+
+ printf("Opening %s as command input file\n", inputPath);
+ error = fopen_s(&inputStream, inputPath, "r");
+
+ if (error != 0)
+ {
+ printf("Error opening input file %s - %d\n", inputPath, error);
+ goto exit;
+ }
+
+ if (inputStream == nullptr)
+ {
+ printf("Error opening input file %s - %d\n", inputPath, error);
+ goto exit;
+ }
+
+ prompt = false;
+ }
+
+ //
+ // Open peripheral driver
+ //
+
+ if (peripheralPath == nullptr)
+ {
+ g_Peripheral = CreateFileW(
+ SPBTESTTOOL_USERMODE_PATH,
+ (GENERIC_READ | GENERIC_WRITE),
+ 0,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ nullptr);
+ }
+ else
+ {
+ printf("Opening %s as peripheral driver path \n", peripheralPath);
+ g_Peripheral = CreateFileA(
+ peripheralPath,
+ (GENERIC_READ | GENERIC_WRITE),
+ 0,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ nullptr);
+ }
+
+ if (g_Peripheral == INVALID_HANDLE_VALUE)
+ {
+ printf("Error opening peripheral driver - %u\n", GetLastError());
+ goto exit;
+ }
+
+ setvbuf(inputStream, nullptr, _IONBF, 0);
+ setvbuf(stdout, nullptr, _IONBF, 0);
+ setvbuf(stderr, nullptr, _IONBF, 0);
+
+ //
+ // Setup a control-C handler.
+ //
+
+ if (SetConsoleCtrlHandler(OnControlKey, true) == FALSE)
+ {
+ printf("Error setting ctrl-C handler - %u\n", GetLastError());
+ goto exit;
+ }
+
+ //
+ // Setup an overlapped structure to use with each I/O.
+ //
+
+ g_Event = CreateEvent(nullptr, true, false, nullptr);
+
+ if (g_Event == nullptr)
+ {
+ printf("error creating I/O event - %u\n", GetLastError());
+ goto exit;
+ }
+
+ //
+ // Create interrupt notification thread.
+ //
+
+ g_InterruptNotificationThread = CreateThread(
+ nullptr,
+ 0,
+ &InterruptNotificationThread,
+ nullptr,
+ 0,
+ nullptr);
+
+ if (g_InterruptNotificationThread == nullptr)
+ {
+ printf("error creating interrupt notification thread - %u\n", GetLastError());
+ goto exit;
+ }
+
+ //
+ // Loop reading commands off the command line and parsing them.
+ // EOF causes an exit.
+ //
+
+ do
+ {
+ list<string> *tokens = new list<string>();
+ PCCommand command;
+
+ if (prompt)
+ {
+ printf("> ");
+ fflush(stdout);
+ }
+
+ if (ReadCommandFromStream(inputStream, tokens) == false)
+ {
+ delete tokens;
+ break;
+ }
+
+ if (tokens->empty())
+ {
+ delete tokens;
+ continue;
+ }
+
+ command = CCommand::_ParseCommand(tokens);
+
+ if (command == nullptr)
+ {
+ delete tokens;
+ continue;
+ }
+
+ g_CurrentCommand = command;
+
+ RunCommand(command);
+
+ g_CurrentCommand = nullptr;
+
+ //
+ // A reference to the tokens list is saved by
+ // the command and will be freed when the command
+ // is deleted.
+ //
+
+ delete command;
+
+ }
+ while (feof(inputStream) == 0);
+
+exit:
+
+ if (prompt == false)
+ {
+ fclose(inputStream);
+ }
+
+ if (g_InterruptNotificationThread != nullptr)
+ {
+ WaitForSingleObject(g_InterruptNotificationThread, INFINITE);
+ CloseHandle(g_InterruptNotificationThread);
+ }
+
+ CloseHandle(g_Peripheral);
+
+ if (g_Event != nullptr)
+ {
+ CloseHandle(g_Event);
+ }
+
+ return;
+}
+
+DWORD WINAPI InterruptNotificationThread(
+ _In_ LPVOID pvData
+ )
+{
+ DWORD status;
+ DWORD bytesReturned;
+ OVERLAPPED ov = {0};
+
+ UNREFERENCED_PARAMETER(pvData);
+
+ ov.hEvent = CreateEvent(nullptr, false, false, nullptr);
+
+ if (ov.hEvent == nullptr)
+ {
+ printf("error creating overlapped event for interrupt thread - %u\n", GetLastError());
+ goto exit;
+ }
+
+ while (g_WaitOnInterrupt == true)
+ {
+ if ((DeviceIoControl(
+ g_Peripheral,
+ IOCTL_SPBTESTTOOL_WAIT_ON_INTERRUPT,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ &ov) == TRUE) ||
+ (GetLastError() != ERROR_IO_PENDING))
+ {
+ printf("failed to pend WaitOnInterrupt IOCTL- %u\n", GetLastError());
+ goto exit;
+ }
+
+ status = WaitForSingleObject(ov.hEvent, INFINITE);
+
+ switch (status)
+ {
+ // DeviceIoControl completed.
+ case WAIT_OBJECT_0:
+
+ if (!GetOverlappedResult(g_Peripheral, &ov, &bytesReturned, FALSE))
+ {
+ printf("GetOverlappedResult failed with status: %u\n\n", GetLastError());
+ }
+ else
+ {
+ printf("\n\n");
+ printf(" ** Interrupt detected. Please acknowledge or disable **\n");
+ printf(" *** and type 'signal' to inform the SpbTestTool driver ***\n");
+ printf(" ** that the interrupt has been handled. **\n");
+ printf("\n");
+ }
+ break;
+
+ default:
+ // Error in the WaitForSingleObject; abort.
+ // This indicates a problem with the OVERLAPPED
+ // structure's event handle.
+ printf("WaitOnInterrupt unexpected return %u\n\n", status);
+ break;
+ }
+ }
+
+exit:
+
+ return 0;
+}
+
+VOID
+PrintUsage(
+ _In_ PCSTR exeName
+ )
+{
+ printf("Usage: %s [/p <driver_path>] [/i <script_name>]\n",
+ exeName);
+}
+
+DWORD
+RunCommand(
+ _In_ PCCommand Command
+ )
+{
+
+ DWORD status;
+ DWORD bytesTransferred;
+
+ Command->Overlapped.hEvent = g_Event;
+
+ if (Command->Execute() == true)
+ {
+ if (GetOverlappedResult(Command->File,
+ &(Command->Overlapped),
+ &bytesTransferred,
+ true) == FALSE)
+ {
+ status = GetLastError();
+ }
+ else
+ {
+ status = NO_ERROR;
+ }
+
+ Command->Complete(status, bytesTransferred);
+ }
+ else
+ {
+ status = GetLastError();
+ }
+
+ return status;
+}
+
+
+bool
+ReadLine(
+ _In_ FILE* InputStream,
+ _In_ ULONG BufferCch,
+ _Out_writes_(BufferCch) CHAR Buffer[]
+ )
+{
+ ULONG i;
+
+ for(i = 0; i < BufferCch - 1; i += 1)
+ {
+ if (fread(&(Buffer[i]), sizeof(CHAR), 1, InputStream) == 0)
+ {
+ return false;
+ }
+
+ fputc(Buffer[i], stdout);
+
+ if (Buffer[i] == '\n')
+ {
+ Buffer[i] = '\0';
+ return true;
+ }
+ else if (Buffer[i] == '\b')
+ {
+ Buffer[i] = '\0';
+ i -= 2;
+ }
+ }
+
+ return false;
+}
+
+bool
+ReadCommandFromStream(
+ _In_ FILE* InputStream,
+ _Inout_ list<string> *Tokens
+ )
+{
+ CHAR buffer[255];
+
+ if (ReadLine(InputStream,
+ sizeof(buffer) - 1,
+ buffer) == false)
+ {
+ return false;
+ }
+
+ string currentLine(buffer);
+ string token;
+
+ list<string> tokens;
+
+ Tokens->clear();
+
+ string::size_type i;
+ long start;
+
+ for(i = 0, start = -1;
+ i < currentLine.length() + 1;
+ i += 1)
+ {
+ wchar_t c;
+
+ if (i < currentLine.length())
+ {
+ c = currentLine[i];
+ }
+ else
+ {
+ c = L'\0';
+ }
+
+ if (iswspace(c) || (c == L'\0'))
+ {
+ if (start == -1)
+ {
+ //
+ // not tracking a token - whitespace is skipped.
+ //
+ }
+ else
+ {
+ //
+ // tracking a token - whitespace or NUL terminates it.
+ // if the last character was a } then split the token.
+ //
+
+ if (currentLine[i-1] == '}')
+ {
+ token.assign(currentLine, start, i - start - 1);
+ Tokens->insert(Tokens->end(), token);
+ Tokens->insert(Tokens->end(), string("}"));
+ }
+ else
+ {
+ token.assign(currentLine, start, i - start);
+ Tokens->insert(Tokens->end(), token);
+ }
+
+ start = -1;
+ }
+ }
+ else if (start == -1)
+ {
+ //
+ // first character of a token. If it's { then split the token.
+ //
+
+ if (currentLine[i] == '{')
+ {
+ Tokens->insert(Tokens->end(), string("{"));
+ }
+ else if (currentLine[i] == '}')
+ {
+ Tokens->insert(Tokens->end(), string("}"));
+ }
+ else
+ {
+ start = (long) i;
+ }
+ }
+ else
+ {
+ //
+ // tracking a token - non whitespace is included.
+ //
+ }
+ }
+
+ return true;
+}
+
+VOID
+PrintBytes(
+ _In_ ULONG BufferCb,
+ _In_reads_bytes_(BufferCb) BYTE Buffer[]
+ )
+{
+ ULONG index = 0;
+
+ for(index = 0; index < BufferCb; index += 16)
+ {
+ printf(" ");
+ for(ULONG i = index; i < (index + 16); i += 1)
+ {
+ if (i < BufferCb)
+ {
+ if ((i != index) && (i % 8 == 0))
+ {
+ printf("- ");
+ }
+
+ printf("%02x ", Buffer[i]);
+ }
+ else
+ {
+ if ((i != index) && (i % 8 == 0))
+ {
+ printf(" ");
+ }
+ printf(" ");
+ }
+ }
+
+ printf(" : ");
+
+ for(ULONG i = index; i < (index + 16); i += 1)
+ {
+ if (i < BufferCb)
+ {
+ if ((i != index) && (i % 8 == 0))
+ {
+ printf(" ");
+ }
+
+ if (isprint(Buffer[i]))
+ {
+ printf("%c", Buffer[i]);
+ }
+ else
+ {
+ printf(".");
+ }
+ }
+ else
+ {
+ printf(" ");
+ }
+ }
+
+ printf("\n");
+ }
+}
+
+BOOL
+WINAPI
+OnControlKey(
+ _In_ DWORD ControlType
+ )
+{
+ if (ControlType == CTRL_C_EVENT)
+ {
+ //
+ // If there's a current command then attempt to cancel it.
+ //
+
+ if (g_CurrentCommand != nullptr)
+ {
+ g_CurrentCommand->Cancel();
+ return TRUE;
+ }
+
+ //
+ // Stop the interrupt notification thread
+ //
+
+ g_WaitOnInterrupt = false;
+ CancelIo(g_Peripheral);
+ }
+
+ return FALSE;
+}
diff --git a/SPB/SpbTestTool/exe/util.cpp b/SPB/SpbTestTool/exe/util.cpp
new file mode 100644
index 00000000..fe6067c9
--- /dev/null
+++ b/SPB/SpbTestTool/exe/util.cpp
@@ -0,0 +1,250 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ util.cpp
+
+Abstract:
+
+ This module contains the internal helper function definitions
+ for the SpbTestTool app.
+
+Environment:
+
+ user-mode
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+
+_Success_(return)
+bool
+PopStringParameter(
+ _Inout_ list<string> *Parameters,
+ _Out_ string *Value,
+ _Out_opt_ bool *Present
+ )
+{
+ if (Parameters->empty())
+ {
+ if (Present != nullptr)
+ {
+ *Present = false;
+ *Value = string("");
+ return true;
+ }
+ else
+ {
+ printf("Missing required parameter\n");
+ return false;
+ }
+ }
+
+ if (Present != nullptr)
+ {
+ *Present = true;
+ }
+
+ *Value = Parameters->front();
+ Parameters->pop_front();
+ return true;
+}
+
+_Success_(return)
+bool
+ParseNumber(
+ _In_ const string &String,
+ _In_ ULONG Radix,
+ _Out_ ULONG *Value,
+ _In_opt_ bounds Bounds
+ )
+{
+ PSTR end;
+
+#pragma prefast(suppress:__WARNING_MISSING_ZERO_TERMINATION2 ,"zero-termination is checked below")
+ *Value = strtoul(String.c_str(), &end, Radix);
+
+ //
+ // Make sure the entire string parsed.
+ //
+
+ if (*end != '\0')
+ {
+ printf("Value %s is not a number\n", String.c_str());
+ return false;
+ }
+
+ //
+ // See if we should do a bounds check.
+ //
+
+ if ((Bounds.first != 0) || (Bounds.second != 0))
+ {
+ if ((*Value < Bounds.first) ||
+ (*Value > Bounds.second))
+ {
+ printf("Value %s is out of bounds\n", String.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+_Success_(return)
+bool
+PopNumberParameter(
+ _Inout_ list<string> *Parameters,
+ _In_ ULONG Radix,
+ _Out_ ULONG *Value,
+ _In_opt_ bounds Bounds,
+ _Out_opt_ bool *Present
+ )
+{
+ string s;
+
+ bool found = PopStringParameter(Parameters, &s, Present);
+
+ if ((Present != nullptr) && (*Present == false))
+ {
+ *Value = Bounds.first;
+ return true;
+ }
+ else if (found == false)
+ {
+ return false;
+ }
+
+ return ParseNumber(s, Radix, Value, Bounds);
+}
+
+_Success_(return)
+bool
+PopBufferParameter(
+ _Inout_ list<string> *Parameters,
+ _Out_ pair<ULONG, PBYTE> *Value
+ )
+{
+ ULONG length = 0;
+ PBYTE buffer = nullptr;
+
+ //
+ // Check for an explict length
+ //
+
+ if (Parameters->front() != "{")
+ {
+ if (PopNumberParameter(Parameters, 10, &length) == false)
+ {
+ printf("Length expected\n");
+ return false;
+ }
+
+ //
+ // Consume any leading {
+ //
+
+ if ((Parameters->empty() == false) &&
+ (Parameters->front() == "{"))
+ {
+ Parameters->pop_front();
+ }
+ }
+ else
+ {
+ string tmp;
+ if (PopStringParameter(Parameters, &tmp) == false)
+ {
+ return false;
+ }
+ else if (tmp != "{")
+ {
+ printf("output buffer must start with {\n");
+ return false;
+ }
+
+ //
+ // Count values until the trailing } - assume one byte per value
+ //
+
+ list<string>::iterator i;
+
+ for(i = Parameters->begin();
+ ((i != Parameters->end()) && (*i != "}"));
+ i++)
+ {
+ length += 1;
+ }
+
+ if (*i != "}")
+ {
+ printf("output buffer must end with }\n");
+ return false;
+ }
+ }
+
+ if (length != 0)
+ {
+ ULONG b = 0;
+ bool bufferEnd = false;
+
+ //
+ // Allocate the buffer.
+ //
+
+ buffer = new BYTE[length];
+
+ for(b = 0; b < length; b += 1)
+ {
+ ULONG value = 0;
+
+ if (bufferEnd == false)
+ {
+ string nextElement;
+
+ PopStringParameter(Parameters, &nextElement);
+
+ if (nextElement == "}")
+ {
+ value = 0;
+ bufferEnd = true;
+ }
+ else if (ParseNumber(nextElement, 16, &value, bounds(0, 0xff)) == false)
+ {
+ printf("invalid byte value %s\n", nextElement.c_str());
+ delete [] buffer;
+ return false;
+ }
+ }
+
+ buffer[b] = (BYTE) value;
+ }
+
+ if (bufferEnd == false)
+ {
+ string end;
+
+ if (PopStringParameter(Parameters, &end) == false)
+ {
+ printf("unclosed buffer\n");
+ delete [] buffer;
+ return false;
+ }
+ else if (end != "}")
+ {
+ printf("buffer has too many initializers\n");
+ delete [] buffer;
+ return false;
+ }
+ }
+ }
+
+ Value->first = length;
+ Value->second = buffer;
+
+ return true;
+}