summaryrefslogtreecommitdiff
path: root/SPB/SpbTestTool/sys
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/sys
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'SPB/SpbTestTool/sys')
-rw-r--r--SPB/SpbTestTool/sys/SpbTestTool.vcxproj197
-rw-r--r--SPB/SpbTestTool/sys/SpbTestTool.vcxproj.Filters42
-rw-r--r--SPB/SpbTestTool/sys/device.cpp848
-rw-r--r--SPB/SpbTestTool/sys/device.h43
-rw-r--r--SPB/SpbTestTool/sys/driver.cpp414
-rw-r--r--SPB/SpbTestTool/sys/driver.h36
-rw-r--r--SPB/SpbTestTool/sys/internal.h144
-rw-r--r--SPB/SpbTestTool/sys/peripheral.cpp1683
-rw-r--r--SPB/SpbTestTool/sys/peripheral.h104
-rw-r--r--SPB/SpbTestTool/sys/resource.rc11
-rw-r--r--SPB/SpbTestTool/sys/spbtestioctl.h50
-rw-r--r--SPB/SpbTestTool/sys/spbtesttool.asl26
-rw-r--r--SPB/SpbTestTool/sys/spbtesttool.inxbin0 -> 4688 bytes
-rw-r--r--SPB/SpbTestTool/sys/trace.h54
14 files changed, 3652 insertions, 0 deletions
diff --git a/SPB/SpbTestTool/sys/SpbTestTool.vcxproj b/SPB/SpbTestTool/sys/SpbTestTool.vcxproj
new file mode 100644
index 00000000..48b8d23c
--- /dev/null
+++ b/SPB/SpbTestTool/sys/SpbTestTool.vcxproj
@@ -0,0 +1,197 @@
+<?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>{028ED946-EE58-43F7-834B-297119CE4720}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{775D4A74-74A0-4CBD-B20E-06D7EAEEAB7C}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="driver.cpp; device.cpp; peripheral.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppScanConfigurationData>trace.h</WppScanConfigurationData>
+ <WppTraceFunction>Trace(LEVEL,FLAGS,MSG,...)</WppTraceFunction>
+ </ClCompile>
+ <Inf Include=".\SpbTestTool.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\SpbTestTool.inf</CopyOutput>
+ </Inf>
+ <OtherWpp Include="resource.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppScanConfigurationData>trace.h</WppScanConfigurationData>
+ <WppTraceFunction>Trace(LEVEL,FLAGS,MSG,...)</WppTraceFunction>
+ </OtherWpp>
+ </ItemGroup>
+ <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>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc" />
+ </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/sys/SpbTestTool.vcxproj.Filters b/SPB/SpbTestTool/sys/SpbTestTool.vcxproj.Filters
new file mode 100644
index 00000000..5c06c882
--- /dev/null
+++ b/SPB/SpbTestTool/sys/SpbTestTool.vcxproj.Filters
@@ -0,0 +1,42 @@
+<?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>{758F79B8-0F82-4FC8-8C5B-0875A36D16C8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{BB2FE3BE-C3C8-4C98-A8FA-CE4AE906C0BC}</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>{B0A30E36-D110-468D-A945-84112CBE25B8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A2DE30AB-8982-454D-976D-E8F3EB8B4777}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="peripheral.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include=".\SpbTestTool.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/SPB/SpbTestTool/sys/device.cpp b/SPB/SpbTestTool/sys/device.cpp
new file mode 100644
index 00000000..28455aa6
--- /dev/null
+++ b/SPB/SpbTestTool/sys/device.cpp
@@ -0,0 +1,848 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ device.cpp
+
+Abstract:
+
+ This module contains WDF device initialization
+ functions for the peripheral driver.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+#include "peripheral.h"
+#include "device.h"
+
+#include "device.tmh"
+
+
+/////////////////////////////////////////////////
+//
+// WDF callbacks.
+//
+/////////////////////////////////////////////////
+
+NTSTATUS
+OnPrepareHardware(
+ _In_ WDFDEVICE FxDevice,
+ _In_ WDFCMRESLIST FxResourcesRaw,
+ _In_ WDFCMRESLIST FxResourcesTranslated
+ )
+/*++
+
+ Routine Description:
+
+ This routine caches the SPB resource connection ID.
+
+ Arguments:
+
+ FxDevice - a handle to the framework device object
+ FxResourcesRaw - list of translated hardware resources that
+ the PnP manager has assigned to the device
+ FxResourcesTranslated - list of raw hardware resources that
+ the PnP manager has assigned to the device
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice);
+ BOOLEAN fSpbResourceFound = FALSE;
+ BOOLEAN fInterruptResourceFound = FALSE;
+ ULONG interruptIndex = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(FxResourcesRaw);
+
+ //
+ // Parse the peripheral's resources.
+ //
+
+ ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated);
+
+ for(ULONG i = 0; i < resourceCount; i++)
+ {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
+ UCHAR Class;
+ UCHAR Type;
+
+ pDescriptor = WdfCmResourceListGetDescriptor(
+ FxResourcesTranslated, i);
+
+ switch (pDescriptor->Type)
+ {
+ case CmResourceTypeConnection:
+
+ //
+ // Look for I2C or SPI resource and save connection ID.
+ //
+
+ Class = pDescriptor->u.Connection.Class;
+ Type = pDescriptor->u.Connection.Type;
+
+ if ((Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL) &&
+ ((Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) ||
+ (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_SPI)))
+ {
+ if (fSpbResourceFound == FALSE)
+ {
+ pDevice->PeripheralId.LowPart =
+ pDescriptor->u.Connection.IdLowPart;
+ pDevice->PeripheralId.HighPart =
+ pDescriptor->u.Connection.IdHighPart;
+
+ fSpbResourceFound = TRUE;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_WDFLOADING,
+ "SPB resource found with ID=0x%llx",
+ pDevice->PeripheralId.QuadPart);
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_WDFLOADING,
+ "Duplicate SPB resource found with ID=0x%llx",
+ pDevice->PeripheralId.QuadPart);
+ }
+ }
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ if (fInterruptResourceFound == FALSE)
+ {
+ fInterruptResourceFound = TRUE;
+ interruptIndex = i;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_WDFLOADING,
+ "Interrupt resource found");
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_WDFLOADING,
+ "Duplicate interrupt resource found");
+ }
+
+ break;
+
+ default:
+
+ //
+ // Ignoring all other resource types.
+ //
+
+ break;
+ }
+ }
+
+ //
+ // An SPB resource is required.
+ //
+
+ if (fSpbResourceFound == FALSE)
+ {
+ status = STATUS_NOT_FOUND;
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "SPB resource not found - %!STATUS!",
+ status);
+ }
+
+ //
+ // Create the interrupt if an interrupt
+ // resource was found.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ if ((pDevice->ConnectInterrupt == TRUE) &&
+ (fInterruptResourceFound == TRUE))
+ {
+ WDF_INTERRUPT_CONFIG interruptConfig;
+ WDF_INTERRUPT_CONFIG_INIT(
+ &interruptConfig,
+ OnInterruptIsr,
+ NULL);
+
+ interruptConfig.PassiveHandling = TRUE;
+ interruptConfig.InterruptTranslated = WdfCmResourceListGetDescriptor(
+ FxResourcesTranslated,
+ interruptIndex);
+ interruptConfig.InterruptRaw = WdfCmResourceListGetDescriptor(
+ FxResourcesRaw,
+ interruptIndex);
+
+ status = WdfInterruptCreate(
+ pDevice->FxDevice,
+ &interruptConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pDevice->Interrupt);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "WdfInterruptCreate failed - %!STATUS!",
+ status);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ KeInitializeEvent(
+ &pDevice->IsrWaitEvent,
+ SynchronizationEvent,
+ FALSE);
+ }
+ }
+ }
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return status;
+}
+
+NTSTATUS
+OnReleaseHardware(
+ _In_ WDFDEVICE FxDevice,
+ _In_ WDFCMRESLIST FxResourcesTranslated
+ )
+/*++
+
+ Routine Description:
+
+ Arguments:
+
+ FxDevice - a handle to the framework device object
+ FxResourcesTranslated - list of raw hardware resources that
+ the PnP manager has assigned to the device
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(FxResourcesTranslated);
+
+ if (pDevice->Interrupt != nullptr)
+ {
+ WdfObjectDelete(pDevice->Interrupt);
+ }
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return status;
+}
+
+NTSTATUS
+OnD0Entry(
+ _In_ WDFDEVICE FxDevice,
+ _In_ WDF_POWER_DEVICE_STATE FxPreviousState
+ )
+/*++
+
+ Routine Description:
+
+ This routine allocates objects needed by the driver.
+
+ Arguments:
+
+ FxDevice - a handle to the framework device object
+ FxPreviousState - previous power state
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ UNREFERENCED_PARAMETER(FxPreviousState);
+
+ PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice);
+ NTSTATUS status;
+
+ //
+ // Create the SPB target.
+ //
+
+ WDF_OBJECT_ATTRIBUTES targetAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&targetAttributes);
+
+ status = WdfIoTargetCreate(
+ pDevice->FxDevice,
+ &targetAttributes,
+ &pDevice->SpbController);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Failed to create IO target - %!STATUS!",
+ status);
+ }
+
+ //
+ // InputMemory will be created when an SPB request is about to be
+ // sent. Indicate that it is not yet initialized.
+ //
+
+ pDevice->InputMemory = WDF_NO_HANDLE;
+
+ //
+ // Create the SPB request.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ WDF_OBJECT_ATTRIBUTES requestAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&requestAttributes, REQUEST_CONTEXT);
+
+ status = WdfRequestCreate(
+ &requestAttributes,
+ nullptr,
+ &pDevice->SpbRequest);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Failed to create IO request - %!STATUS!",
+ status);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ PREQUEST_CONTEXT pRequest = GetRequestContext(
+ pDevice->SpbRequest);
+
+ pRequest->FxDevice = pDevice->FxDevice;
+ pRequest->IsSpbSequenceRequest = FALSE;
+ pRequest->SequenceWriteLength = 0;
+ }
+ }
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return status;
+}
+
+NTSTATUS
+OnD0Exit(
+ _In_ WDFDEVICE FxDevice,
+ _In_ WDF_POWER_DEVICE_STATE FxPreviousState
+ )
+/*++
+
+ Routine Description:
+
+ This routine destroys objects needed by the driver.
+
+ Arguments:
+
+ FxDevice - a handle to the framework device object
+ FxPreviousState - previous power state
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ UNREFERENCED_PARAMETER(FxPreviousState);
+
+ PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice);
+
+ if (pDevice->SpbController != WDF_NO_HANDLE)
+ {
+ WdfObjectDelete(pDevice->SpbController);
+ pDevice->SpbController = WDF_NO_HANDLE;
+ }
+
+ if (pDevice->SpbRequest != WDF_NO_HANDLE)
+ {
+ WdfObjectDelete(pDevice->SpbRequest);
+ pDevice->SpbRequest = WDF_NO_HANDLE;
+ }
+
+ if (pDevice->InputMemory != WDF_NO_HANDLE)
+ {
+ WdfObjectDelete(pDevice->InputMemory);
+ pDevice->InputMemory = WDF_NO_HANDLE;
+ }
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+OnFileCleanup(
+ _In_ WDFFILEOBJECT FileObject
+ )
+/*++
+
+ Routine Description:
+
+ This routine is called before a device is stopped.
+
+ Arguments:
+
+ FileObject - a handle to the framework file object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+
+ device = WdfFileObjectGetDevice(FileObject);
+ pDevice = GetDeviceContext(device);
+
+ //
+ // The client app has closed the device handle,
+ // make sure the SPB target is closed.
+ //
+
+ SpbPeripheralClose(pDevice);
+
+ //
+ // Signal the ISR wait event just
+ // in case the callback is stalled.
+ //
+
+ if (pDevice->Interrupt != nullptr)
+ {
+ KeSetEvent(
+ &pDevice->IsrWaitEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+ }
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+}
+
+VOID
+OnTopLevelIoDefault(
+ _In_ WDFQUEUE FxQueue,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ Accepts all incoming requests and pends or forwards appropriately.
+
+ Arguments:
+
+ FxQueue - Handle to the framework queue object that is associated with the
+ I/O request.
+ FxRequest - Handle to a framework request object.
+
+ Return Value:
+
+ None.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxQueue);
+
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+ WDF_REQUEST_PARAMETERS params;
+ NTSTATUS status;
+
+ device = WdfIoQueueGetDevice(FxQueue);
+ pDevice = GetDeviceContext(device);
+
+ WDF_REQUEST_PARAMETERS_INIT(&params);
+
+ WdfRequestGetParameters(FxRequest, &params);
+
+ if ((params.Type == WdfRequestTypeDeviceControl) &&
+ (params.Parameters.DeviceIoControl.IoControlCode ==
+ IOCTL_SPBTESTTOOL_WAIT_ON_INTERRUPT))
+ {
+ SpbPeripheralWaitOnInterrupt(pDevice, FxRequest);
+ }
+ else
+ {
+ status = WdfRequestForwardToIoQueue(FxRequest, pDevice->SpbQueue);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to forward WDFREQUEST %p to SPB queue %p - %!STATUS!",
+ FxRequest,
+ pDevice->SpbQueue,
+ status);
+
+ WdfRequestComplete(FxRequest, status);
+ }
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+OnIoRead (
+ _In_ WDFQUEUE FxQueue,
+ _In_ WDFREQUEST FxRequest,
+ _In_ size_t Length
+ )
+/*++
+
+ Routine Description:
+
+ Performs read from the toaster device. This event is called when the
+ framework receives IRP_MJ_READ requests.
+
+ Arguments:
+
+ FxQueue - Handle to the framework queue object that is associated with the
+ I/O request.
+ FxRequest - Handle to a framework request object.
+ Length - Length of the data buffer associated with the request.
+ By default, the queue does not dispatch zero length read & write
+ requests to the driver and instead to complete such requests with
+ status success. So we will never get a zero length request.
+
+ Return Value:
+
+ None.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(Length);
+
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Read request %p received",
+ FxRequest);
+
+ device = WdfIoQueueGetDevice(FxQueue);
+ pDevice = GetDeviceContext(device);
+
+ //
+ // Send the read request.
+ //
+
+ SpbPeripheralRead(pDevice,FxRequest);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+OnIoWrite (
+ _In_ WDFQUEUE FxQueue,
+ _In_ WDFREQUEST FxRequest,
+ _In_ size_t Length
+ )
+/*++
+
+Routine Description:
+
+ Performs write to the toaster device. This event is called when the
+ framework receives IRP_MJ_WRITE requests.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+ Lenght - Length of the data buffer associated with the request.
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ None
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(Length);
+
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Write request %p received",
+ FxRequest);
+
+ device = WdfIoQueueGetDevice(FxQueue);
+ pDevice = GetDeviceContext(device);
+
+ //
+ // Send the write request.
+ //
+
+ SpbPeripheralWrite(pDevice,FxRequest);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+OnIoDeviceControl(
+ _In_ WDFQUEUE FxQueue,
+ _In_ WDFREQUEST FxRequest,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
+ requests from the system.
+
+Arguments:
+
+ FxQueue - Handle to the framework queue object that is associated
+ with the I/O request.
+ FxRequest - Handle to a framework request object.
+ OutputBufferLength - length of the request's output buffer,
+ if an output buffer is available.
+ InputBufferLength - length of the request's input buffer,
+ if an input buffer is available.
+ IoControlCode - the driver-defined or system-defined I/O control code
+ (IOCTL) that is associated with the request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+ BOOLEAN fSync = FALSE;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "DeviceIoControl request %p received with IOCTL=%lu",
+ FxRequest,
+ IoControlCode);
+
+ device = WdfIoQueueGetDevice(FxQueue);
+ pDevice = GetDeviceContext(device);
+
+ //
+ // Translate the test IOCTL into the appropriate
+ // SPB API method. Open and close are completed
+ // synchronously.
+ //
+
+ switch (IoControlCode)
+ {
+ case IOCTL_SPBTESTTOOL_OPEN:
+ fSync = TRUE;
+ status = SpbPeripheralOpen(pDevice);
+ break;
+
+ case IOCTL_SPBTESTTOOL_CLOSE:
+ fSync = TRUE;
+ status = SpbPeripheralClose(pDevice);
+ break;
+
+ case IOCTL_SPBTESTTOOL_LOCK:
+ SpbPeripheralLock(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_UNLOCK:
+ SpbPeripheralUnlock(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_LOCK_CONNECTION:
+ SpbPeripheralLockConnection(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_UNLOCK_CONNECTION:
+ SpbPeripheralUnlockConnection(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_WRITEREAD:
+ SpbPeripheralWriteRead(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_FULL_DUPLEX:
+ SpbPeripheralFullDuplex(pDevice, FxRequest);
+ break;
+
+ case IOCTL_SPBTESTTOOL_SIGNAL_INTERRUPT:
+ SpbPeripheralSignalInterrupt(pDevice, FxRequest);
+ break;
+
+ default:
+ fSync = TRUE;
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "Request %p received with unexpected IOCTL=%lu",
+ FxRequest,
+ IoControlCode);
+ }
+
+ //
+ // Complete the request if necessary.
+ //
+
+ if (fSync)
+ {
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Completing request %p with %!STATUS!",
+ FxRequest,
+ status);
+
+ WdfRequestComplete(FxRequest, status);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+BOOLEAN
+OnInterruptIsr(
+ _In_ WDFINTERRUPT FxInterrupt,
+ _In_ ULONG MessageID
+ )
+/*++
+
+ Routine Description:
+
+ This routine responds to interrupts generated by the H/W.
+ It then waits indefinitely for the user to signal that
+ the interrupt has been acknowledged, allowing the ISR to
+ return. This ISR is called at PASSIVE_LEVEL.
+
+ Arguments:
+
+ Interrupt - a handle to a framework interrupt object
+ MessageID - message number identifying the device's
+ hardware interrupt message (if using MSI)
+
+ Return Value:
+
+ TRUE if interrupt recognized.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ BOOLEAN fInterruptRecognized = TRUE;
+ BOOLEAN fNotificationSent;
+ WDFDEVICE device;
+ PDEVICE_CONTEXT pDevice;
+
+ UNREFERENCED_PARAMETER(MessageID);
+
+ device = WdfInterruptGetDevice(FxInterrupt);
+ pDevice = GetDeviceContext(device);
+
+ //
+ // Notify the app that an interrupt has occurred.
+ //
+
+ fNotificationSent = SpbPeripheralInterruptNotify(pDevice);
+
+ if (fNotificationSent)
+ {
+ //
+ // Stall in ISR until acknowledged by user.
+ //
+ // Note: In a 'real' driver, the ISR should directly
+ // acknowledge the interrupt and then queue
+ // a workitem to carry out any additional
+ // processing. The ISR should never call
+ // KeWaitForSingleObject as done below.
+ //
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Stalling in ISR until continue command received");
+
+ KeClearEvent(&pDevice->IsrWaitEvent);
+
+ KeWaitForSingleObject(
+ &pDevice->IsrWaitEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "Interrupt detected, but failed to send notification, ignoring");
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+
+ return fInterruptRecognized;
+}
diff --git a/SPB/SpbTestTool/sys/device.h b/SPB/SpbTestTool/sys/device.h
new file mode 100644
index 00000000..40ec9904
--- /dev/null
+++ b/SPB/SpbTestTool/sys/device.h
@@ -0,0 +1,43 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This module contains the function definitions for
+ the WDF device.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#ifndef _DEVICE_H_
+#define _DEVICE_H_
+
+//
+// WDF event callbacks.
+//
+
+EVT_WDF_DEVICE_PREPARE_HARDWARE OnPrepareHardware;
+EVT_WDF_DEVICE_RELEASE_HARDWARE OnReleaseHardware;
+EVT_WDF_DEVICE_D0_ENTRY OnD0Entry;
+EVT_WDF_DEVICE_D0_EXIT OnD0Exit;
+
+EVT_WDF_FILE_CLEANUP OnFileCleanup;
+
+EVT_WDF_IO_QUEUE_IO_DEFAULT OnTopLevelIoDefault;
+EVT_WDF_IO_QUEUE_IO_READ OnIoRead;
+EVT_WDF_IO_QUEUE_IO_WRITE OnIoWrite;
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OnIoDeviceControl;
+
+EVT_WDF_INTERRUPT_ISR OnInterruptIsr;
+
+#endif \ No newline at end of file
diff --git a/SPB/SpbTestTool/sys/driver.cpp b/SPB/SpbTestTool/sys/driver.cpp
new file mode 100644
index 00000000..253a8858
--- /dev/null
+++ b/SPB/SpbTestTool/sys/driver.cpp
@@ -0,0 +1,414 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ driver.cpp
+
+Abstract:
+
+ This module contains the WDF driver initialization
+ functions for the peripheral driver.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+#include "driver.h"
+#include "device.h"
+#include "ntstrsafe.h"
+
+#include "driver.tmh"
+
+NTSTATUS
+#pragma prefast(suppress:__WARNING_DRIVER_FUNCTION_TYPE, "thanks, i know this already")
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ WDF_DRIVER_CONFIG driverConfig;
+ WDF_OBJECT_ATTRIBUTES driverAttributes;
+
+ WDFDRIVER fxDriver;
+
+ NTSTATUS status;
+
+ WPP_INIT_TRACING(DriverObject, RegistryPath);
+
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ WDF_DRIVER_CONFIG_INIT(&driverConfig, OnDeviceAdd);
+ driverConfig.DriverPoolTag = SPBT_POOL_TAG;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&driverAttributes);
+ driverAttributes.EvtCleanupCallback = OnDriverCleanup;
+
+ status = WdfDriverCreate(
+ DriverObject,
+ RegistryPath,
+ &driverAttributes,
+ &driverConfig,
+ &fxDriver);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating WDF driver object - %!STATUS!",
+ status);
+
+ goto exit;
+ }
+
+ Trace(
+ TRACE_LEVEL_VERBOSE,
+ TRACE_FLAG_WDFLOADING,
+ "Created WDF driver object");
+
+exit:
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return status;
+}
+
+VOID
+OnDriverCleanup(
+ _In_ WDFOBJECT Object
+ )
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ UNREFERENCED_PARAMETER(Object);
+
+ WPP_CLEANUP(nullptr);
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+}
+
+NTSTATUS
+OnDeviceAdd(
+ _In_ WDFDRIVER FxDriver,
+ _Inout_ PWDFDEVICE_INIT FxDeviceInit
+ )
+/*++
+
+ Routine Description:
+
+ This routine creates the device object for an SPB
+ controller and the device's child objects.
+
+ Arguments:
+
+ FxDriver - the WDF driver object handle
+ FxDeviceInit - information about the PDO that we are loading on
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_WDFLOADING);
+
+ PDEVICE_CONTEXT pDevice;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(FxDriver);
+
+ //
+ // Setup PNP/Power callbacks.
+ //
+
+ {
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks;
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks);
+
+ pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware;
+ pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware;
+ pnpCallbacks.EvtDeviceD0Entry = OnD0Entry;
+ pnpCallbacks.EvtDeviceD0Exit = OnD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(FxDeviceInit, &pnpCallbacks);
+ }
+
+ //
+ // Prepare for file object handling.
+ //
+
+ {
+ WDF_FILEOBJECT_CONFIG fileObjectConfig;
+
+ WDF_FILEOBJECT_CONFIG_INIT(
+ &fileObjectConfig,
+ nullptr,
+ nullptr,
+ OnFileCleanup);
+
+ WDF_OBJECT_ATTRIBUTES fileObjectAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&fileObjectAttributes);
+
+ WdfDeviceInitSetFileObjectConfig(
+ FxDeviceInit,
+ &fileObjectConfig,
+ &fileObjectAttributes);
+ }
+
+ //
+ // Set request attributes.
+ //
+
+ {
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
+ &attributes,
+ REQUEST_CONTEXT);
+
+ WdfDeviceInitSetRequestAttributes(FxDeviceInit, &attributes);
+ }
+
+ //
+ // Create the device.
+ //
+
+ {
+ WDFDEVICE fxDevice;
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(
+ &FxDeviceInit,
+ &deviceAttributes,
+ &fxDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating WDFDEVICE - %!STATUS!",
+ status);
+
+ goto exit;
+ }
+
+ pDevice = GetDeviceContext(fxDevice);
+ NT_ASSERT(pDevice != nullptr);
+
+ pDevice->FxDevice = fxDevice;
+ }
+
+ //
+ // Ensure device is disable-able
+ //
+
+ {
+ WDF_DEVICE_STATE deviceState;
+ WDF_DEVICE_STATE_INIT(&deviceState);
+
+ deviceState.NotDisableable = WdfFalse;
+ WdfDeviceSetDeviceState(pDevice->FxDevice, &deviceState);
+ }
+
+ //
+ // Create queues to handle IO
+ //
+
+ {
+ WDF_IO_QUEUE_CONFIG queueConfig;
+ WDFQUEUE queue;
+
+ //
+ // Top-level queue
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel);
+
+ queueConfig.EvtIoDefault = OnTopLevelIoDefault;
+ queueConfig.PowerManaged = WdfFalse;
+
+ status = WdfIoQueueCreate(
+ pDevice->FxDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating top-level IO queue - %!STATUS!",
+ status);
+
+ goto exit;
+ }
+
+ //
+ // Sequential SPB queue
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &queueConfig,
+ WdfIoQueueDispatchSequential);
+
+ queueConfig.EvtIoRead = OnIoRead;
+ queueConfig.EvtIoWrite = OnIoWrite;
+ queueConfig.EvtIoDeviceControl = OnIoDeviceControl;
+ queueConfig.PowerManaged = WdfFalse;
+
+ status = WdfIoQueueCreate(
+ pDevice->FxDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pDevice->SpbQueue
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating SPB IO queue - %!STATUS!",
+ status);
+
+ goto exit;
+ }
+ }
+
+ //
+ // Create a symbolic link.
+ //
+
+ {
+ DECLARE_UNICODE_STRING_SIZE(symbolicLinkName, 128);
+
+ status = RtlUnicodeStringPrintf(
+ &symbolicLinkName, L"%ws",
+ SPBTESTTOOL_SYMBOLIC_NAME);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating symbolic link string for device "
+ "- %!STATUS!",
+ status);
+
+ goto exit;
+ }
+
+ status = WdfDeviceCreateSymbolicLink(
+ pDevice->FxDevice,
+ &symbolicLinkName);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_WDFLOADING,
+ "Error creating symbolic link for device "
+ "- %!STATUS!",
+ status);
+
+ goto exit;
+ }
+ }
+
+ //
+ // Retrieve registry settings.
+ //
+
+ {
+ WDFKEY key = NULL;
+ WDFKEY subkey = NULL;
+ ULONG connectInterrupt = 0;
+ NTSTATUS settingStatus;
+
+ DECLARE_CONST_UNICODE_STRING(subkeyName, L"Settings");
+ DECLARE_CONST_UNICODE_STRING(connectInterruptName, L"ConnectInterrupt");
+
+ settingStatus = WdfDeviceOpenRegistryKey(
+ pDevice->FxDevice,
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &key);
+
+ if (!NT_SUCCESS(settingStatus))
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_WDFLOADING,
+ "Error opening device registry key - %!STATUS!",
+ settingStatus);
+ }
+
+ if (NT_SUCCESS(settingStatus))
+ {
+ settingStatus = WdfRegistryOpenKey(
+ key,
+ &subkeyName,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &subkey);
+
+ if (!NT_SUCCESS(settingStatus))
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_WDFLOADING,
+ "Error opening registry subkey for 'Settings' - %!STATUS!",
+ settingStatus);
+ }
+ }
+
+ if (NT_SUCCESS(settingStatus))
+ {
+
+ settingStatus = WdfRegistryQueryULong(
+ subkey,
+ &connectInterruptName,
+ &connectInterrupt);
+
+ if (!NT_SUCCESS(settingStatus))
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_WDFLOADING,
+ "Error querying registry value for 'ConnectInterrupt' - %!STATUS!",
+ settingStatus);
+ }
+ }
+
+ if (key != NULL)
+ {
+ WdfRegistryClose(key);
+ }
+
+ if (subkey != NULL)
+ {
+ WdfRegistryClose(subkey);
+ }
+
+ pDevice->ConnectInterrupt = (connectInterrupt == 1);
+ }
+
+exit:
+
+ FuncExit(TRACE_FLAG_WDFLOADING);
+
+ return status;
+}
diff --git a/SPB/SpbTestTool/sys/driver.h b/SPB/SpbTestTool/sys/driver.h
new file mode 100644
index 00000000..1029377c
--- /dev/null
+++ b/SPB/SpbTestTool/sys/driver.h
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This module contains the function definitions for
+ the WDF driver.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#ifndef _DRIVER_H_
+#define _DRIVER_H_
+
+extern "C"
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT pDriverObject,
+ _In_ PUNICODE_STRING pRegistryPath
+ );
+
+EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd;
+EVT_WDF_OBJECT_CONTEXT_CLEANUP OnDriverCleanup;
+
+#endif
diff --git a/SPB/SpbTestTool/sys/internal.h b/SPB/SpbTestTool/sys/internal.h
new file mode 100644
index 00000000..7e40560b
--- /dev/null
+++ b/SPB/SpbTestTool/sys/internal.h
@@ -0,0 +1,144 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ internal.h
+
+Abstract:
+
+ This module contains the common internal type and function
+ definitions for the SPB peripheral driver.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#ifndef _INTERNAL_H_
+#define _INTERNAL_H_
+
+#pragma warning(push)
+#pragma warning(disable:4512)
+#pragma warning(disable:4480)
+
+#define SPBT_POOL_TAG ((ULONG) 'TBPS')
+
+/////////////////////////////////////////////////
+//
+// Common includes.
+//
+/////////////////////////////////////////////////
+
+#include <ntddk.h>
+#include <wdm.h>
+#include <wdf.h>
+#include <ntstrsafe.h>
+
+#include "spb.h"
+#include "spbtestioctl.h"
+
+#define RESHUB_USE_HELPER_ROUTINES
+#include "reshub.h"
+
+#include "trace.h"
+
+//
+// Forward Declarations
+//
+
+typedef struct _DEVICE_CONTEXT DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+typedef struct _REQUEST_CONTEXT REQUEST_CONTEXT, *PREQUEST_CONTEXT;
+
+struct _DEVICE_CONTEXT
+{
+ //
+ // Handle back to the WDFDEVICE
+ //
+
+ WDFDEVICE FxDevice;
+
+ //
+ // Handle to the sequential SPB queue
+ //
+
+ WDFQUEUE SpbQueue;
+
+ //
+ // Connection ID for SPB peripheral
+ //
+
+ LARGE_INTEGER PeripheralId;
+
+ //
+ // Interrupt object and wait event
+ //
+
+ WDFINTERRUPT Interrupt;
+ KEVENT IsrWaitEvent;
+
+ //
+ // Setting indicating whether the interrupt should be connected
+ //
+
+ BOOLEAN ConnectInterrupt;
+
+ //
+ // SPB controller target
+ //
+
+ WDFIOTARGET SpbController;
+
+ //
+ // SPB request object
+ //
+
+ WDFREQUEST SpbRequest;
+
+ //
+ // Input memory for request. Valid while request in progress.
+ //
+
+ WDFMEMORY InputMemory;
+
+ //
+ // Client request object
+ //
+
+ WDFREQUEST ClientRequest;
+
+ //
+ // WaitOnInterrupt request object
+ //
+
+ WDFREQUEST WaitOnInterruptRequest;
+};
+
+struct _REQUEST_CONTEXT
+{
+ //
+ // Associated framework device object
+ //
+
+ WDFDEVICE FxDevice;
+
+ //
+ // Variables to track write length for a sequence request.
+ // There are needed to complete the client request with
+ // correct bytesReturned value.
+ //
+
+ BOOLEAN IsSpbSequenceRequest;
+ ULONG_PTR SequenceWriteLength;
+};
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext);
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext);
+
+#pragma warning(pop)
+
+#endif // _INTERNAL_H_
diff --git a/SPB/SpbTestTool/sys/peripheral.cpp b/SPB/SpbTestTool/sys/peripheral.cpp
new file mode 100644
index 00000000..c6966ada
--- /dev/null
+++ b/SPB/SpbTestTool/sys/peripheral.cpp
@@ -0,0 +1,1683 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ peripheral.cpp
+
+Abstract:
+
+ This module contains the function for interaction
+ with the SPB API.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#include "internal.h"
+#include "peripheral.h"
+
+#include "peripheral.tmh"
+
+NTSTATUS
+SpbPeripheralOpen(
+ _In_ PDEVICE_CONTEXT pDevice
+ )
+/*++
+
+ Routine Description:
+
+ This routine opens a handle to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ WDF_IO_TARGET_OPEN_PARAMS openParams;
+ NTSTATUS status;
+
+ //
+ // Create the device path using the connection ID.
+ //
+
+ DECLARE_UNICODE_STRING_SIZE(DevicePath, RESOURCE_HUB_PATH_SIZE);
+
+ RESOURCE_HUB_CREATE_PATH_FROM_ID(
+ &DevicePath,
+ pDevice->PeripheralId.LowPart,
+ pDevice->PeripheralId.HighPart);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Opening handle to SPB target via %wZ",
+ &DevicePath);
+
+ //
+ // Open a handle to the SPB controller.
+ //
+
+ WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(
+ &openParams,
+ &DevicePath,
+ (GENERIC_READ | GENERIC_WRITE));
+
+ openParams.ShareAccess = 0;
+ openParams.CreateDisposition = FILE_OPEN;
+ openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ status = WdfIoTargetOpen(
+ pDevice->SpbController,
+ &openParams);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to open SPB target - %!STATUS!",
+ status);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+
+ return status;
+}
+
+NTSTATUS
+SpbPeripheralClose(
+ _In_ PDEVICE_CONTEXT pDevice
+ )
+/*++
+
+ Routine Description:
+
+ This routine closes a handle to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Closing handle to SPB target");
+
+ WdfIoTargetClose(pDevice->SpbController);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+SpbPeripheralLock(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends a lock command to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_LOCK_CONTROLLER",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for lock and send.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_LOCK_CONTROLLER,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_LOCK_CONTROLLER - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralUnlock(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends an unlock command to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_UNLOCK_CONTROLLER",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for unlock and send.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_UNLOCK_CONTROLLER,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_UNLOCK_CONTROLLER - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralLockConnection(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends a lock connection command to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_LOCK_CONNECTION",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for lock and send.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_LOCK_CONNECTION,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_LOCK_CONNECTION - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralUnlockConnection(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends an unlock connection command to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_UNLOCK_CONNECTION",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for unlock and send.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_UNLOCK_CONNECTION,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_UNLOCK_CONNECTION - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralRead(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine reads from the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ WDFMEMORY memory = nullptr;
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for read",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for read and send.
+ //
+
+ status = WdfRequestRetrieveOutputMemory(
+ FxRequest,
+ &memory);
+
+ if (NT_SUCCESS(status))
+ {
+ status = WdfIoTargetFormatRequestForRead(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ memory,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "read - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralWrite(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine writes to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ WDFMEMORY memory = nullptr;
+ NTSTATUS status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for write",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Initialize the SPB request for write and send.
+ //
+
+ status = WdfRequestRetrieveInputMemory(
+ FxRequest,
+ &memory);
+
+ if (NT_SUCCESS(status))
+ {
+ status = WdfIoTargetFormatRequestForWrite(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ memory,
+ nullptr,
+ nullptr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "write - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralWriteRead(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends a write-read sequence to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ PVOID pInputBuffer = nullptr;
+ PVOID pOutputBuffer = nullptr;
+ size_t inputBufferLength = 0;
+ size_t outputBufferLength = 0;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ PREQUEST_CONTEXT pRequest;
+ NTSTATUS status;
+
+ pRequest = GetRequestContext(pDevice->SpbRequest);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_EXECUTE_SEQUENCE",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Get input and output buffers.
+ //
+
+ status = WdfRequestRetrieveInputBuffer(
+ FxRequest,
+ 0,
+ &pInputBuffer,
+ &inputBufferLength);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to retrieve input buffer - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(
+ FxRequest,
+ 0,
+ &pOutputBuffer,
+ &outputBufferLength);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to retrieve output buffer - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ //
+ // Build SPB sequence.
+ //
+
+ const ULONG transfers = 2;
+
+ SPB_TRANSFER_LIST_AND_ENTRIES(transfers) seq;
+ SPB_TRANSFER_LIST_INIT(&(seq.List), transfers);
+
+ {
+ //
+ // PreFAST cannot figure out the SPB_TRANSFER_LIST_ENTRY
+ // "struct hack" size but using an index variable quiets
+ // the warning. This is a false positive from OACR.
+ //
+
+ ULONG index = 0;
+ seq.List.Transfers[index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionToDevice,
+ 0,
+ pInputBuffer,
+ (ULONG)inputBufferLength);
+
+ seq.List.Transfers[index + 1] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionFromDevice,
+ 0,
+ pOutputBuffer,
+ (ULONG)outputBufferLength);
+ }
+
+ //
+ // Create preallocated WDFMEMORY. The IOCTL is METHOD_BUFFERED,
+ // so the memory doesn't have to persist until the request is
+ // completed.
+ //
+
+ NT_ASSERT(pDevice->InputMemory == WDF_NO_HANDLE);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+
+ status = WdfMemoryCreatePreallocated(
+ &attributes,
+ (PVOID)&seq,
+ sizeof(seq),
+ &pDevice->InputMemory);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to create WDFMEMORY - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Built write-read sequence %p with byte length=%lu",
+ &seq,
+ (ULONG)(inputBufferLength + outputBufferLength));
+
+ //
+ // Send sequence IOCTL.
+ //
+
+ //
+ // Mark SPB request as sequence and save length.
+ // These will be used in the completion callback
+ // to complete the client request with the correct
+ // number of bytes
+ //
+
+ pRequest->IsSpbSequenceRequest = TRUE;
+ pRequest->SequenceWriteLength = (ULONG_PTR)inputBufferLength;
+
+ //
+ // Format and send the SPB sequence request.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_EXECUTE_SEQUENCE,
+ pDevice->InputMemory,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to format request - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_EXECUTE_SEQUENCE - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ goto Done;
+ }
+
+Done:
+
+ if (!NT_SUCCESS(status))
+ {
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralFullDuplex(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends a full duplex transfer to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ FxRequest - the framework request object
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxRequest);
+
+ PVOID pInputBuffer = nullptr;
+ PVOID pOutputBuffer = nullptr;
+ size_t inputBufferLength = 0;
+ size_t outputBufferLength = 0;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ PREQUEST_CONTEXT pRequest;
+ NTSTATUS status;
+
+ pRequest = GetRequestContext(pDevice->SpbRequest);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Formatting SPB request %p for IOCTL_SPB_FULL_DUPLEX",
+ pDevice->SpbRequest);
+
+ //
+ // Save the client request.
+ //
+
+ pDevice->ClientRequest = FxRequest;
+
+ //
+ // Get input and output buffers.
+ //
+
+ status = WdfRequestRetrieveInputBuffer(
+ FxRequest,
+ 0,
+ &pInputBuffer,
+ &inputBufferLength);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to retrieve input buffer - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(
+ FxRequest,
+ 0,
+ &pOutputBuffer,
+ &outputBufferLength);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to retrieve output buffer - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ //
+ // Build full duplex transfer using SPB transfer list.
+ //
+
+ const ULONG transfers = 2;
+
+ SPB_TRANSFER_LIST_AND_ENTRIES(transfers) seq;
+ SPB_TRANSFER_LIST_INIT(&(seq.List), transfers);
+
+ {
+ //
+ // PreFAST cannot figure out the SPB_TRANSFER_LIST_ENTRY
+ // "struct hack" size but using an index variable quiets
+ // the warning. This is a false positive from OACR.
+ //
+
+ ULONG index = 0;
+ seq.List.Transfers[index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionToDevice,
+ 0,
+ pInputBuffer,
+ (ULONG)inputBufferLength);
+
+ seq.List.Transfers[index + 1] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE(
+ SpbTransferDirectionFromDevice,
+ 0,
+ pOutputBuffer,
+ (ULONG)outputBufferLength);
+ }
+
+ //
+ // Create preallocated WDFMEMORY. The IOCTL is METHOD_BUFFERED,
+ // so the memory doesn't have to persist until the request is
+ // completed.
+ //
+
+ NT_ASSERT(pDevice->InputMemory == WDF_NO_HANDLE);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+
+ status = WdfMemoryCreatePreallocated(
+ &attributes,
+ (PVOID)&seq,
+ sizeof(seq),
+ &pDevice->InputMemory);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to create WDFMEMORY - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Built full duplex transfer %p with byte length=%lu",
+ &seq,
+ (ULONG)(inputBufferLength + outputBufferLength));
+
+ //
+ // Send full duplex IOCTL.
+ //
+
+ //
+ // Mark SPB request as full duplex (sequence format)
+ // and save length. These will be used in the completion
+ // callback to complete the client request with the correct
+ // number of bytes
+ //
+
+ pRequest->IsSpbSequenceRequest = TRUE;
+ pRequest->SequenceWriteLength = (ULONG_PTR)inputBufferLength;
+
+ //
+ // Format and send the full duplex request.
+ //
+
+ status = WdfIoTargetFormatRequestForIoctl(
+ pDevice->SpbController,
+ pDevice->SpbRequest,
+ IOCTL_SPB_FULL_DUPLEX,
+ pDevice->InputMemory,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to format request - %!STATUS!",
+ status);
+
+ goto Done;
+ }
+
+ status = SpbPeripheralSendRequest(
+ pDevice,
+ pDevice->SpbRequest,
+ FxRequest);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p for "
+ "IOCTL_SPB_FULL_DUPLEX - %!STATUS!",
+ pDevice->SpbRequest,
+ status);
+
+ goto Done;
+ }
+
+Done:
+
+ if (!NT_SUCCESS(status))
+ {
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ 0);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralSignalInterrupt(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+Routine Description:
+
+ This routine signals the interrupt service routine
+ to continue.
+
+Arguments:
+
+ pDevice - the device context
+ FxRequest - the framework request object
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (pDevice->Interrupt != nullptr)
+ {
+ //
+ // Signal ISR to continue.
+ //
+
+ KeSetEvent(
+ &pDevice->IsrWaitEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Setting ISR wait event");
+ }
+ else
+ {
+ status = STATUS_NOT_FOUND;
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "No interrupt object found, ignoring - %!STATUS!",
+ status);
+ }
+
+ WdfRequestComplete(FxRequest, status);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralWaitOnInterrupt(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+Routine Description:
+
+ This routine pends the WaitOnInterrupt request.
+
+Arguments:
+
+ pDevice - the device context
+ FxRequest - the framework request object
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ PREQUEST_CONTEXT pRequest = GetRequestContext(FxRequest);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (pDevice->WaitOnInterruptRequest == nullptr)
+ {
+ //
+ // Mark request cancellable.
+ //
+
+ pRequest->FxDevice = pDevice->FxDevice;
+
+ status = WdfRequestMarkCancelableEx(
+ FxRequest,
+ SpbPeripheralOnWaitOnInterruptCancel);
+
+ if (!NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to mark WaitOnInterrupt request %p cancellable - %!STATUS!",
+ FxRequest,
+ status);
+ }
+
+ //
+ // Pend the WaitOnInterrupt request.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "WaitOnInterrupt request %p pended",
+ FxRequest);
+
+ pDevice->WaitOnInterruptRequest = FxRequest;
+ }
+ }
+ else
+ {
+ status = STATUS_INVALID_DEVICE_STATE;
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "Cannont pend multiple WaitOnInterrupt requests, ignoring - %!STATUS!",
+ status);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ WdfRequestComplete(FxRequest, status);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralOnWaitOnInterruptCancel(
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+Routine Description:
+
+ This event is called when the WaitOnInterrupt request is cancelled.
+
+Arguments:
+
+ FxRequest - the framework request object
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ PREQUEST_CONTEXT pRequest;
+ PDEVICE_CONTEXT pDevice;
+
+ pRequest = GetRequestContext(FxRequest);
+ pDevice = GetDeviceContext(pRequest->FxDevice);
+
+ //
+ // Complete the request as cancelled
+ //
+
+ if (FxRequest == pDevice->WaitOnInterruptRequest)
+ {
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "WaitOnInterrupt request %p cancelled",
+ FxRequest);
+
+ pDevice->WaitOnInterruptRequest = nullptr;
+ WdfRequestComplete(FxRequest, STATUS_CANCELLED);
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "Cancel for WDFREQUEST %p without WaitOnInterrupt request pended,"
+ "will complete as cancelled anyway",
+ FxRequest);
+
+ WdfRequestComplete(FxRequest, STATUS_CANCELLED);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+BOOLEAN
+SpbPeripheralInterruptNotify(
+ _In_ PDEVICE_CONTEXT pDevice
+ )
+/*++
+Routine Description:
+
+ This routine completes the pending WaitOnInterrupt request.
+
+Arguments:
+
+ pDevice - the device context
+
+Return Value:
+
+ TRUE if notification sent, false otherwise.
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ WDFREQUEST request;
+ BOOLEAN fNotificationSent = FALSE;
+ NTSTATUS status;
+
+ if (pDevice->WaitOnInterruptRequest != nullptr)
+ {
+ //
+ // Complete the WaitOnInterrupt request.
+ //
+
+ request = pDevice->WaitOnInterruptRequest;
+ pDevice->WaitOnInterruptRequest = nullptr;
+
+ status = WdfRequestUnmarkCancelable(request);
+
+ if (NT_SUCCESS(status))
+ {
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Interrupt detected, WaitOnInterrupt request %p completed",
+ pDevice->WaitOnInterruptRequest);
+
+ WdfRequestComplete(request, STATUS_SUCCESS);
+ fNotificationSent = TRUE;
+ }
+ else if (status == STATUS_CANCELLED)
+ {
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Interrupt detected with WaitOnInterrupt request %p "
+ "already completed - %!STATUS!",
+ pDevice->WaitOnInterruptRequest,
+ status);
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Interrupt detected but failed to unmark WaitOnInterrupt "
+ "request %p as cancellable - %!STATUS!",
+ pDevice->WaitOnInterruptRequest,
+ status);
+ }
+ }
+ else
+ {
+ Trace(
+ TRACE_LEVEL_WARNING,
+ TRACE_FLAG_SPBAPI,
+ "Interrupt detected without a pended WaitOnInterrupt request");
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+
+ return fNotificationSent;
+}
+
+NTSTATUS
+SpbPeripheralSendRequest(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST SpbRequest,
+ _In_ WDFREQUEST ClientRequest
+ )
+/*++
+
+ Routine Description:
+
+ This routine sends a write-read sequence to the SPB controller.
+
+ Arguments:
+
+ pDevice - a pointer to the device context
+ SpbRequest - the SPB request object
+ ClientRequest - the client request object
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ PREQUEST_CONTEXT pRequest = GetRequestContext(ClientRequest);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Saving client request %p, and "
+ "sending SPB request %p",
+ ClientRequest,
+ SpbRequest);
+
+ //
+ // Init client request context.
+ //
+
+ pRequest->FxDevice = pDevice->FxDevice;
+ pRequest->IsSpbSequenceRequest = FALSE;
+ pRequest->SequenceWriteLength = 0;
+
+ //
+ // Mark the client request as cancellable.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ status = WdfRequestMarkCancelableEx(
+ ClientRequest,
+ SpbPeripheralOnCancel);
+ }
+
+ //
+ // Send the SPB request.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ WdfRequestSetCompletionRoutine(
+ SpbRequest,
+ SpbPeripheralOnCompletion,
+ GetRequestContext(SpbRequest));
+
+ BOOLEAN fSent = WdfRequestSend(
+ SpbRequest,
+ pDevice->SpbController,
+ WDF_NO_SEND_OPTIONS);
+
+ if (!fSent)
+ {
+ status = WdfRequestGetStatus(SpbRequest);
+
+ Trace(
+ TRACE_LEVEL_ERROR,
+ TRACE_FLAG_SPBAPI,
+ "Failed to send SPB request %p - %!STATUS!",
+ SpbRequest,
+ status);
+
+ NTSTATUS cancelStatus;
+ cancelStatus = WdfRequestUnmarkCancelable(ClientRequest);
+
+ if (!NT_SUCCESS(cancelStatus))
+ {
+ NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if request has already been cancelled",
+ cancelStatus == STATUS_CANCELLED);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Client request %p has already been cancelled - "
+ "%!STATUS!",
+ ClientRequest,
+ cancelStatus);
+ }
+ }
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+
+ return status;
+}
+
+VOID
+SpbPeripheralOnCompletion(
+ _In_ WDFREQUEST FxRequest,
+ _In_ WDFIOTARGET FxTarget,
+ _In_ PWDF_REQUEST_COMPLETION_PARAMS Params,
+ _In_ WDFCONTEXT Context
+ )
+/*++
+
+ Routine Description:
+
+ This routine is called when a request completes.
+
+ Arguments:
+
+ FxRequest - the framework request object
+ FxTarget - the framework IO target object
+ Params - a pointer to the request completion parameters
+ Context - the request context
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ UNREFERENCED_PARAMETER(FxTarget);
+ UNREFERENCED_PARAMETER(Context);
+
+ PREQUEST_CONTEXT pRequest;
+ PDEVICE_CONTEXT pDevice;
+ NTSTATUS status;
+ NTSTATUS cancelStatus;
+ ULONG_PTR bytesCompleted;
+
+ pRequest = GetRequestContext(FxRequest);
+ pDevice = GetDeviceContext(pRequest->FxDevice);
+
+ status = Params->IoStatus.Status;
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Completion callback received for SPB request %p with %!STATUS!",
+ FxRequest,
+ status);
+
+ //
+ // Unmark the client request as cancellable
+ //
+
+ cancelStatus = WdfRequestUnmarkCancelable(pDevice->ClientRequest);
+
+ if (!NT_SUCCESS(cancelStatus))
+ {
+ NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if request has already been cancelled",
+ cancelStatus == STATUS_CANCELLED);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Client request %p has already been cancelled - %!STATUS!",
+ pDevice->ClientRequest,
+ cancelStatus);
+ }
+
+ //
+ // Complete the request pair
+ //
+
+ if (pRequest->IsSpbSequenceRequest == TRUE)
+ {
+ //
+ // The client DeviceIoControl should only be
+ // completed with bytesReturned and not total
+ // bytes transferred. Here we infer the number
+ // of bytes read by substracting the write
+ // length from the total.
+ //
+
+ bytesCompleted =
+ Params->IoStatus.Information < pRequest->SequenceWriteLength ?
+ 0 : Params->IoStatus.Information - pRequest->SequenceWriteLength;
+ }
+ else
+ {
+ bytesCompleted = Params->IoStatus.Information;
+ }
+
+ SpbPeripheralCompleteRequestPair(
+ pDevice,
+ status,
+ bytesCompleted);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralOnCancel(
+ _In_ WDFREQUEST FxRequest
+ )
+/*++
+Routine Description:
+
+ This event is called when the client request is cancelled.
+
+Arguments:
+
+ FxRequest - the framework request object
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ PREQUEST_CONTEXT pRequest;
+ PDEVICE_CONTEXT pDevice;
+
+ pRequest = GetRequestContext(FxRequest);
+ pDevice = GetDeviceContext(pRequest->FxDevice);
+
+ //
+ // Attempt to cancel the SPB request
+ //
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Cancel received for client request %p, "
+ "attempting to cancel SPB request %p",
+ FxRequest,
+ pDevice->SpbRequest);
+
+ WdfRequestCancelSentRequest(pDevice->SpbRequest);
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
+
+VOID
+SpbPeripheralCompleteRequestPair(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ NTSTATUS status,
+ _In_ ULONG_PTR bytesCompleted
+ )
+/*++
+Routine Description:
+
+ This routine marks the SpbRequest as reuse
+ and completes the client request.
+
+Arguments:
+
+ pDevice - the device context
+ status - the client completion status
+ bytesCompleted - the number of bytes completed
+ for the client request
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ FuncEntry(TRACE_FLAG_SPBAPI);
+
+ PREQUEST_CONTEXT pRequest;
+ pRequest = GetRequestContext(pDevice->SpbRequest);
+
+ Trace(
+ TRACE_LEVEL_INFORMATION,
+ TRACE_FLAG_SPBAPI,
+ "Marking SPB request %p for reuse, and completing "
+ "client request %p with %!STATUS! and bytes=%lu",
+ pDevice->SpbRequest,
+ pDevice->ClientRequest,
+ status,
+ (ULONG)bytesCompleted);
+
+ //
+ // Mark the SPB request as reuse
+ //
+
+ pRequest->IsSpbSequenceRequest = FALSE;
+ pRequest->SequenceWriteLength = 0;
+
+ WDF_REQUEST_REUSE_PARAMS params;
+ WDF_REQUEST_REUSE_PARAMS_INIT(
+ &params,
+ WDF_REQUEST_REUSE_NO_FLAGS,
+ STATUS_SUCCESS);
+
+ WdfRequestReuse(pDevice->SpbRequest, &params);
+
+ if (pDevice->InputMemory != WDF_NO_HANDLE)
+ {
+ WdfObjectDelete(pDevice->InputMemory);
+ pDevice->InputMemory = WDF_NO_HANDLE;
+ }
+
+ //
+ // Complete the client request
+ //
+
+ if (pDevice->ClientRequest != nullptr)
+ {
+ WDFREQUEST clientRequest = pDevice->ClientRequest;
+ pDevice->ClientRequest = nullptr;
+
+ //
+ // In order to satisfy SDV, assume clientRequest
+ // is equal to pDevice->ClientRequest. This suppresses
+ // a warning in the driver's cancellation path.
+ //
+ // Typically when WdfRequestUnmarkCancelable returns
+ // STATUS_CANCELLED a driver does not go on to complete
+ // the request in that context. This sample, however,
+ // driver has handled this condition appropriately by
+ // not completing the cancelled request in its
+ // EvtRequestCancel callback. Developers should be
+ // cautious when copying code from this sample, paying
+ // close attention to the cancellation logic.
+ //
+ _Analysis_assume_(clientRequest == pDevice->ClientRequest);
+
+ WdfRequestCompleteWithInformation(
+ clientRequest,
+ status,
+ bytesCompleted);
+ }
+
+ FuncExit(TRACE_FLAG_SPBAPI);
+}
diff --git a/SPB/SpbTestTool/sys/peripheral.h b/SPB/SpbTestTool/sys/peripheral.h
new file mode 100644
index 00000000..fc1fc806
--- /dev/null
+++ b/SPB/SpbTestTool/sys/peripheral.h
@@ -0,0 +1,104 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ peripheral.h
+
+Abstract:
+
+ This module contains the function definitions for
+ interaction with the SPB API.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#ifndef _PERIPHERAL_H_
+#define _PERIPHERAL_H_
+
+EVT_WDF_REQUEST_COMPLETION_ROUTINE SpbPeripheralOnCompletion;
+EVT_WDF_REQUEST_CANCEL SpbPeripheralOnCancel;
+
+EVT_WDF_REQUEST_CANCEL SpbPeripheralOnWaitOnInterruptCancel;
+
+NTSTATUS
+SpbPeripheralOpen(
+ _In_ PDEVICE_CONTEXT pDevice);
+
+NTSTATUS
+SpbPeripheralClose(
+ _In_ PDEVICE_CONTEXT pDevice);
+
+VOID
+SpbPeripheralLock(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralUnlock(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralLockConnection(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralUnlockConnection(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralRead(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralWrite(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralWriteRead(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralFullDuplex(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralSignalInterrupt(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+VOID
+SpbPeripheralWaitOnInterrupt(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST FxRequest);
+
+BOOLEAN
+SpbPeripheralInterruptNotify(
+ _In_ PDEVICE_CONTEXT pDevice);
+
+NTSTATUS
+SpbPeripheralSendRequest(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ WDFREQUEST SpbRequest,
+ _In_ WDFREQUEST ClientRequest);
+
+VOID
+SpbPeripheralCompleteRequestPair(
+ _In_ PDEVICE_CONTEXT pDevice,
+ _In_ NTSTATUS status,
+ _In_ ULONG_PTR bytesCompleted);
+
+#endif // _PERIPHERAL_H_
diff --git a/SPB/SpbTestTool/sys/resource.rc b/SPB/SpbTestTool/sys/resource.rc
new file mode 100644
index 00000000..24dd5368
--- /dev/null
+++ b/SPB/SpbTestTool/sys/resource.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "SPB Test Tool Peripheral Driver"
+#define VER_INTERNALNAME_STR "SpbTestTool.sys"
+#define VER_ORIGINALFILENAME_STR "SpbTestTool.sys"
+
+#include "common.ver"
diff --git a/SPB/SpbTestTool/sys/spbtestioctl.h b/SPB/SpbTestTool/sys/spbtestioctl.h
new file mode 100644
index 00000000..5a0f7b7e
--- /dev/null
+++ b/SPB/SpbTestTool/sys/spbtestioctl.h
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ spbtestioctl.h
+
+Abstract:
+
+ This module contains the public device path names and
+ IOCTL definitions for the SpbTestTool.
+
+Environment:
+
+Revision History:
+
+--*/
+
+#ifndef _SPBTESTIOCTL_H_
+#define _SPBTESTIOCTL_H_
+
+//
+// Device path names
+//
+
+#define SPBTESTTOOL_NAME L"SPBTESTTOOL"
+
+#define SPBTESTTOOL_SYMBOLIC_NAME L"\\DosDevices\\" SPBTESTTOOL_NAME
+#define SPBTESTTOOL_USERMODE_PATH L"\\\\.\\" SPBTESTTOOL_NAME
+#define SPBTESTTOOL_USERMODE_PATH_SIZE sizeof(SPBTESTTOOL_USERMODE_PATH)
+
+//
+// Priavte SpbTestTool IOCTLs
+//
+
+#define FILE_DEVICE_SPB_PERIPHERAL 0x400
+
+#define IOCTL_SPBTESTTOOL_OPEN CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x700, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_CLOSE CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x701, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_LOCK CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x702, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_UNLOCK CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x703, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_WRITEREAD CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x704, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_LOCK_CONNECTION CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x705, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_UNLOCK_CONNECTION CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x706, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_SIGNAL_INTERRUPT CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x707, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_WAIT_ON_INTERRUPT CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x708, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SPBTESTTOOL_FULL_DUPLEX CTL_CODE(FILE_DEVICE_SPB_PERIPHERAL, 0x709, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif _SPBTESTIOCTL_H_ \ No newline at end of file
diff --git a/SPB/SpbTestTool/sys/spbtesttool.asl b/SPB/SpbTestTool/sys/spbtesttool.asl
new file mode 100644
index 00000000..fcf3c9ac
--- /dev/null
+++ b/SPB/SpbTestTool/sys/spbtesttool.asl
@@ -0,0 +1,26 @@
+//
+// Test peripheral device node
+//
+Device(SPBT)
+{
+ Name(_HID, "SpbTestTool")
+ Name(_UID, 1)
+ Method(_CRS, 0x0, NotSerialized)
+ {
+ Name (RBUF, ResourceTemplate ()
+ {
+ //
+ // Sample I2C and GPIO resources. Modify to match your
+ // platform's underlying controllers and connections.
+ // \_SB.I2C and \_SB.GPIO are paths to predefined I2C
+ // and GPIO controller instances.
+ //
+ // Note: SpbTestTool does not require a GPIO resource.
+ // Remove as necessary.
+ //
+ I2CSerialBus(0x1D, ControllerInitiated, 400000, AddressingMode7Bit, "\\_SB.I2C", , )
+ GpioInt(Level, ActiveHigh, Exclusive, PullDown, 0, "\\_SB.GPIO") {1}
+ })
+ Return(RBUF)
+ }
+} \ No newline at end of file
diff --git a/SPB/SpbTestTool/sys/spbtesttool.inx b/SPB/SpbTestTool/sys/spbtesttool.inx
new file mode 100644
index 00000000..ae1a4fe4
--- /dev/null
+++ b/SPB/SpbTestTool/sys/spbtesttool.inx
Binary files differ
diff --git a/SPB/SpbTestTool/sys/trace.h b/SPB/SpbTestTool/sys/trace.h
new file mode 100644
index 00000000..00601dc8
--- /dev/null
+++ b/SPB/SpbTestTool/sys/trace.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ trace.h
+
+Abstract:
+
+ This module contains the trace definitions for the SPB
+ peripheral driver.
+
+Environment:
+
+ kernel-mode only
+
+Revision History:
+
+--*/
+
+#ifndef _TRACE_H_
+#define _TRACE_H_
+
+extern "C"
+{
+//
+// Tracing Definitions:
+//
+// Control GUID:
+// {73e3b785-f5fb-423e-94a9-56627fea9053}
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ SpbTestToolTraceGuid, \
+ (73e3b785,f5fb,423e,94a9,56627fea9053), \
+ WPP_DEFINE_BIT(TRACE_FLAG_WDFLOADING) \
+ WPP_DEFINE_BIT(TRACE_FLAG_SPBAPI) \
+ WPP_DEFINE_BIT(TRACE_FLAG_OTHER) \
+ )
+}
+
+#define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags)
+#define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level)
+
+// begin_wpp config
+// FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS);
+// FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS);
+// USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> entry");
+// USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <--");
+// end_wpp
+
+#endif _TRACE_H_