summaryrefslogtreecommitdiff
path: root/audio/simpleaudiosample/Source/Main
diff options
context:
space:
mode:
authorjudzmura <[email protected]>2021-03-01 13:12:34 -0800
committerGitHub <[email protected]>2021-03-01 13:12:34 -0800
commit9a2e9aecb9135e782c434e617f57bfbdf9d8f2fd (patch)
treec67dd7a72a15a8d72c7bb6c6e19c1086d5e15f08 /audio/simpleaudiosample/Source/Main
parent6c41d837b87a0b70fe5dcee78baeba4ef28c45ad (diff)
Add SimpleAudioSample driver. (#577)
* Add SimpleAudioSample driver. * Fixed outdated copyrights and updated readme. * Added Filters as a dependency for Main and defined FileDigestAlgorithm as SHA256.
Diffstat (limited to 'audio/simpleaudiosample/Source/Main')
-rw-r--r--audio/simpleaudiosample/Source/Main/Main.vcxproj478
-rw-r--r--audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters44
-rw-r--r--audio/simpleaudiosample/Source/Main/NewDelete.cpp141
-rw-r--r--audio/simpleaudiosample/Source/Main/SimpleAudioSample.inxbin0 -> 15164 bytes
-rw-r--r--audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc28
-rw-r--r--audio/simpleaudiosample/Source/Main/adapter.cpp844
-rw-r--r--audio/simpleaudiosample/Source/Main/basetopo.cpp688
-rw-r--r--audio/simpleaudiosample/Source/Main/common.cpp2772
-rw-r--r--audio/simpleaudiosample/Source/Main/mintopo.cpp557
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavert.cpp1683
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavert.h302
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavertstream.cpp1644
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavertstream.h248
13 files changed, 9429 insertions, 0 deletions
diff --git a/audio/simpleaudiosample/Source/Main/Main.vcxproj b/audio/simpleaudiosample/Source/Main/Main.vcxproj
new file mode 100644
index 00000000..fabab156
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/Main.vcxproj
@@ -0,0 +1,478 @@
+<?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|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</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>{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <SupportsPackaging>false</SupportsPackaging>
+ <RequiresPackageProject>true</RequiresPackageProject>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2A9A946E-F017-4E0D-BF75-AD81E7E97D64}</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 Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <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 Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <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 Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <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 Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <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" />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>SimpleAudioSample</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <!--
+ Use one of the following pre-processor defines to select the right power management:
+ - _USE_IPortClsRuntimePower
+ - _USE_SingleComponentMultiFxStates
+ Note that the single-component/multi-state feature requires also a registry
+ value set via the INF. The name of the registry value is SingleComponentMultiFxStates.
+ see INF file for more info.
+ -->
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="adapter.cpp" />
+ <ClCompile Include="basetopo.cpp" />
+ <ClCompile Include="common.cpp" />
+ <ClCompile Include="mintopo.cpp" />
+ <ClCompile Include="minwavert.cpp" />
+ <ClCompile Include="minwavertstream.cpp" />
+ <ClCompile Include="newdelete.cpp" />
+ <ResourceCompile Include="SimpleAudioSample.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inx)" Include="*.inx" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters b/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters
new file mode 100644
index 00000000..0669f019
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters
@@ -0,0 +1,44 @@
+<?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>{7FE326AE-6214-4FE0-A27B-F229A098BDBC}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{64C16D2B-849C-4264-A615-18A8E8AC9505}</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>{46FAF4E8-F18C-4797-9CFA-2F3473BCB316}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{EE8F0A00-C1F0-4CB4-80E3-5FCC378E0BF4}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="SimpleAudioSample.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="*.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project>
diff --git a/audio/simpleaudiosample/Source/Main/NewDelete.cpp b/audio/simpleaudiosample/Source/Main/NewDelete.cpp
new file mode 100644
index 00000000..8ef3797d
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/NewDelete.cpp
@@ -0,0 +1,141 @@
+/*****************************************************************************
+* NewDelete.cpp - CPP placement new and delete operators implementation
+*****************************************************************************
+* Copyright (c) Microsoft Corporation All Rights Reserved
+*
+* Module Name:
+*
+* NewDelete.cpp
+*
+* Abstract:
+*
+* Definition of placement new and delete operators.
+*
+*/
+
+#ifdef _NEW_DELETE_OPERATORS_
+#ifdef __cplusplus
+extern "C" {
+#include <wdm.h>
+}
+#else
+#include <wdm.h>
+#endif
+
+#include "newDelete.h"
+#include "definitions.h"
+
+#pragma code_seg()
+/*****************************************************************************
+* Functions
+*/
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified allocation tag.
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags,
+ ULONG tag
+)
+{
+ PVOID result = ExAllocatePool2(poolFlags, iSize, tag);
+
+ return result;
+}
+
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified allocation tag.
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags
+)
+{
+ PVOID result = ExAllocatePool2(poolFlags, iSize, SIMPLEAUDIOSAMPLE_POOLTAG);
+
+ return result;
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Delete with tag function.
+*/
+void __cdecl operator delete
+(
+ PVOID pVoid,
+ ULONG tag
+)
+{
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, tag);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Delete function.
+*/
+void __cdecl operator delete
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+)
+{
+ UNREFERENCED_PARAMETER(cbSize);
+
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+)
+{
+ UNREFERENCED_PARAMETER(cbSize);
+
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid
+)
+{
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+#endif//_NEW_DELETE_OPERATORS_
diff --git a/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx
new file mode 100644
index 00000000..a63bb0ba
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx
Binary files differ
diff --git a/audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc
new file mode 100644
index 00000000..7fbb4893
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ SimpleAudioSample.rc
+
+Abstract:
+
+--*/
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SOUND
+#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Simple Audio Sample Driver"
+#define VER_INTERNALNAME_STR "SimpleAudioSample.sys"
+#define VER_ORIGINALFILENAME_STR "SimpleAudioSample.sys"
+
+#define VER_LEGALCOPYRIGHT_YEARS "2013"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Microsoft Corp." VER_LEGALCOPYRIGHT_YEARS
+
+#include "common.ver"
+
+
diff --git a/audio/simpleaudiosample/Source/Main/adapter.cpp b/audio/simpleaudiosample/Source/Main/adapter.cpp
new file mode 100644
index 00000000..105f7fde
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/adapter.cpp
@@ -0,0 +1,844 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ adapter.cpp
+
+Abstract:
+
+ Setup and miniport installation. No resources are used by simple audio sample.
+ This sample is to demonstrate how to develop a full featured audio miniport driver.
+--*/
+
+#pragma warning (disable : 4127)
+
+//
+// All the GUIDS for all the miniports end up in this object.
+//
+#define PUT_GUIDS_HERE
+
+#include "definitions.h"
+#include "endpoints.h"
+#include "minipairs.h"
+
+typedef void (*fnPcDriverUnload) (PDRIVER_OBJECT);
+fnPcDriverUnload gPCDriverUnloadRoutine = NULL;
+extern "C" DRIVER_UNLOAD DriverUnload;
+
+//-----------------------------------------------------------------------------
+// Referenced forward.
+//-----------------------------------------------------------------------------
+
+DRIVER_ADD_DEVICE AddDevice;
+
+NTSTATUS
+StartDevice
+(
+ _In_ PDEVICE_OBJECT,
+ _In_ PIRP,
+ _In_ PRESOURCELIST
+);
+
+_Dispatch_type_(IRP_MJ_PNP)
+DRIVER_DISPATCH PnpHandler;
+
+//
+// Rendering streams are saved to a file by default. Use the registry value
+// DoNotCreateDataFiles (DWORD) > 0 to override this default.
+//
+DWORD g_DoNotCreateDataFiles = 0; // default is off.
+DWORD g_DisableToneGenerator = 0; // default is to generate tones.
+UNICODE_STRING g_RegistryPath; // This is used to store the registry settings path for the driver
+
+//-----------------------------------------------------------------------------
+// Functions
+//-----------------------------------------------------------------------------
+
+#pragma code_seg("PAGE")
+void ReleaseRegistryStringBuffer()
+{
+ if (g_RegistryPath.Buffer != NULL)
+ {
+ ExFreePool(g_RegistryPath.Buffer);
+ g_RegistryPath.Buffer = NULL;
+ g_RegistryPath.Length = 0;
+ g_RegistryPath.MaximumLength = 0;
+ }
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+extern "C"
+void DriverUnload
+(
+ _In_ PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ Our driver unload routine. This just frees the WDF driver object.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+Environment:
+
+ PASSIVE_LEVEL
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF(D_TERSE, ("[DriverUnload]"));
+
+ ReleaseRegistryStringBuffer();
+
+ if (DriverObject == NULL)
+ {
+ goto Done;
+ }
+
+ //
+ // Invoke first the port unload.
+ //
+ if (gPCDriverUnloadRoutine != NULL)
+ {
+ gPCDriverUnloadRoutine(DriverObject);
+ }
+
+ //
+ // Unload WDF driver object.
+ //
+ if (WdfGetDriver() != NULL)
+ {
+ WdfDriverMiniportUnload(WdfGetDriver());
+ }
+Done:
+ return;
+}
+
+//=============================================================================
+#pragma code_seg("INIT")
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+CopyRegistrySettingsPath(
+ _In_ PUNICODE_STRING RegistryPath
+)
+/*++
+
+Routine Description:
+
+Copies the following registry path to a global variable.
+
+\REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters
+
+Arguments:
+
+RegistryPath - Registry path passed to DriverEntry
+
+Returns:
+
+NTSTATUS - SUCCESS if able to configure the framework
+
+--*/
+
+{
+ // Initializing the unicode string, so that if it is not allocated it will not be deallocated too.
+ RtlInitUnicodeString(&g_RegistryPath, NULL);
+
+ g_RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
+
+ g_RegistryPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, g_RegistryPath.MaximumLength, MINADAPTER_POOLTAG);
+
+ if (g_RegistryPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&g_RegistryPath, RegistryPath->Buffer);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("INIT")
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+GetRegistrySettings(
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Initialize Driver Framework settings from the driver
+ specific registry settings under
+
+ \REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters
+
+Arguments:
+
+ RegistryPath - Registry path passed to DriverEntry
+
+Returns:
+
+ NTSTATUS - SUCCESS if able to configure the framework
+
+--*/
+
+{
+ NTSTATUS ntStatus;
+ UNICODE_STRING parametersPath;
+ RTL_QUERY_REGISTRY_TABLE paramTable[] = {
+ // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"DoNotCreateDataFiles", &g_DoNotCreateDataFiles, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &g_DoNotCreateDataFiles, sizeof(ULONG)},
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"DisableToneGenerator", &g_DisableToneGenerator, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &g_DisableToneGenerator, sizeof(ULONG)},
+ { NULL, 0, NULL, NULL, 0, NULL, 0}
+ };
+
+ DPF(D_TERSE, ("[GetRegistrySettings]"));
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString(&parametersPath, NULL);
+
+ parametersPath.MaximumLength =
+ RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(WCHAR);
+
+ parametersPath.Buffer = (PWCH) ExAllocatePool2(POOL_FLAG_PAGED, parametersPath.MaximumLength, MINADAPTER_POOLTAG);
+ if (parametersPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&parametersPath, RegistryPath->Buffer);
+ RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
+
+ ntStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ &paramTable[0],
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RtlQueryRegistryValues failed, using default values, 0x%x", ntStatus));
+ //
+ // Don't return error because we will operate with default values.
+ //
+ }
+
+ //
+ // Dump settings.
+ //
+ DPF(D_VERBOSE, ("DoNotCreateDataFiles: %u", g_DoNotCreateDataFiles));
+ DPF(D_VERBOSE, ("DisableToneGenerator: %u", g_DisableToneGenerator));
+
+ //
+ // Cleanup.
+ //
+ ExFreePool(parametersPath.Buffer);
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg("INIT")
+extern "C" DRIVER_INITIALIZE DriverEntry;
+extern "C" NTSTATUS
+DriverEntry
+(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPathName
+)
+{
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+ All audio adapter drivers can use this code without change.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path,
+ to driver-specific key in the registry.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+ NTSTATUS ntStatus;
+ WDF_DRIVER_CONFIG config;
+
+ DPF(D_TERSE, ("[DriverEntry]"));
+
+ // Copy registry Path name in a global variable to be used by modules inside driver.
+ // !! NOTE !! Inside this function we are initializing the registrypath, so we MUST NOT add any failing calls
+ // before the following call.
+ ntStatus = CopyRegistrySettingsPath(RegistryPathName);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Registry path copy error 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Get registry configuration.
+ //
+ ntStatus = GetRegistrySettings(RegistryPathName);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Registry Configuration error 0x%x", ntStatus)),
+ Done);
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+ //
+ // Set WdfDriverInitNoDispatchOverride flag to tell the framework
+ // not to provide dispatch routines for the driver. In other words,
+ // the framework must not intercept IRPs that the I/O manager has
+ // directed to the driver. In this case, they will be handled by Audio
+ // port driver.
+ //
+ config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
+ config.DriverPoolTag = MINADAPTER_POOLTAG;
+
+ ntStatus = WdfDriverCreate(DriverObject,
+ RegistryPathName,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ WDF_NO_HANDLE);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("WdfDriverCreate failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Tell the class driver to initialize the driver.
+ //
+ ntStatus = PcInitializeAdapterDriver(DriverObject,
+ RegistryPathName,
+ (PDRIVER_ADD_DEVICE)AddDevice);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("PcInitializeAdapterDriver failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // To intercept stop/remove/surprise-remove.
+ //
+ DriverObject->MajorFunction[IRP_MJ_PNP] = PnpHandler;
+
+ //
+ // Hook the port class unload function
+ //
+ gPCDriverUnloadRoutine = DriverObject->DriverUnload;
+ DriverObject->DriverUnload = DriverUnload;
+
+ //
+ // All done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ if (WdfGetDriver() != NULL)
+ {
+ WdfDriverMiniportUnload(WdfGetDriver());
+ }
+
+ ReleaseRegistryStringBuffer();
+ }
+
+ return ntStatus;
+} // DriverEntry
+
+#pragma code_seg()
+// disable prefast warning 28152 because
+// DO_DEVICE_INITIALIZING is cleared in PcAddAdapterDevice
+#pragma warning(disable:28152)
+#pragma code_seg("PAGE")
+//=============================================================================
+NTSTATUS AddDevice
+(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PDEVICE_OBJECT PhysicalDeviceObject
+)
+/*++
+
+Routine Description:
+
+ The Plug & Play subsystem is handing us a brand new PDO, for which we
+ (by means of INF registration) have been asked to provide a driver.
+
+ We need to determine if we need to be in the driver stack for the device.
+ Create a function device object to attach to the stack
+ Initialize that device object
+ Return status success.
+
+ All audio adapter drivers can use this code without change.
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+ PhysicalDeviceObject - pointer to a device object created by the
+ underlying bus driver.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+ ULONG maxObjects;
+
+ DPF(D_TERSE, ("[AddDevice]"));
+
+ maxObjects = g_MaxMiniports;
+
+ // Tell the class driver to add the device.
+ //
+ ntStatus =
+ PcAddAdapterDevice
+ (
+ DriverObject,
+ PhysicalDeviceObject,
+ PCPFNSTARTDEVICE(StartDevice),
+ maxObjects,
+ 0
+ );
+
+ return ntStatus;
+} // AddDevice
+
+#pragma code_seg()
+NTSTATUS
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PowerControlCallback
+(
+ _In_ LPCGUID PowerControlCode,
+ _In_opt_ PVOID InBuffer,
+ _In_ SIZE_T InBufferSize,
+ _Out_writes_bytes_to_(OutBufferSize, *BytesReturned) PVOID OutBuffer,
+ _In_ SIZE_T OutBufferSize,
+ _Out_opt_ PSIZE_T BytesReturned,
+ _In_opt_ PVOID Context
+)
+{
+ UNREFERENCED_PARAMETER(PowerControlCode);
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferSize);
+ UNREFERENCED_PARAMETER(OutBuffer);
+ UNREFERENCED_PARAMETER(OutBufferSize);
+ UNREFERENCED_PARAMETER(BytesReturned);
+ UNREFERENCED_PARAMETER(Context);
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallEndpointRenderFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon,
+ _In_ PENDPOINT_MINIPAIR _pAeMiniports
+ )
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopology = NULL;
+ PUNKNOWN unknownWave = NULL;
+ PPORTCLSETWHELPER pPortClsEtwHelper = NULL;
+#ifdef _USE_IPortClsRuntimePower
+ PPORTCLSRUNTIMEPOWER pPortClsRuntimePower = NULL;
+#endif // _USE_IPortClsRuntimePower
+ PPORTCLSStreamResourceManager pPortClsResMgr = NULL;
+ PPORTCLSStreamResourceManager2 pPortClsResMgr2 = NULL;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_pDeviceObject);
+
+ ntStatus = _pAdapterCommon->InstallEndpointFilters(
+ _pIrp,
+ _pAeMiniports,
+ NULL,
+ &unknownTopology,
+ &unknownWave,
+ NULL, NULL);
+
+ if (unknownWave) // IID_IPortClsEtwHelper and IID_IPortClsRuntimePower interfaces are only exposed on the WaveRT port.
+ {
+ ntStatus = unknownWave->QueryInterface (IID_IPortClsEtwHelper, (PVOID *)&pPortClsEtwHelper);
+ if (NT_SUCCESS(ntStatus))
+ {
+ _pAdapterCommon->SetEtwHelper(pPortClsEtwHelper);
+ ASSERT(pPortClsEtwHelper != NULL);
+ pPortClsEtwHelper->Release();
+ }
+
+#ifdef _USE_IPortClsRuntimePower
+ // Let's get the runtime power interface on PortCls.
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsRuntimePower, (PVOID *)&pPortClsRuntimePower);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // This interface would typically be stashed away for later use. Instead,
+ // let's just send an empty control with GUID_NULL.
+ NTSTATUS ntStatusTest =
+ pPortClsRuntimePower->SendPowerControl
+ (
+ _pDeviceObject,
+ &GUID_NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ if (NT_SUCCESS(ntStatusTest) || STATUS_NOT_IMPLEMENTED == ntStatusTest || STATUS_NOT_SUPPORTED == ntStatusTest)
+ {
+ ntStatus = pPortClsRuntimePower->RegisterPowerControlCallback(_pDeviceObject, &PowerControlCallback, NULL);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = pPortClsRuntimePower->UnregisterPowerControlCallback(_pDeviceObject);
+ }
+ }
+ else
+ {
+ ntStatus = ntStatusTest;
+ }
+
+ pPortClsRuntimePower->Release();
+ }
+#endif // _USE_IPortClsRuntimePower
+
+ //
+ // Test: add and remove current thread as streaming audio resource.
+ // In a real driver you should only add interrupts and driver-owned threads
+ // (i.e., do NOT add the current thread as streaming resource).
+ //
+ // testing IPortClsStreamResourceManager:
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsStreamResourceManager, (PVOID *)&pPortClsResMgr);
+ if (NT_SUCCESS(ntStatus))
+ {
+ PCSTREAMRESOURCE_DESCRIPTOR res;
+ PCSTREAMRESOURCE hRes = NULL;
+ PDEVICE_OBJECT pdo = NULL;
+
+ PcGetPhysicalDeviceObject(_pDeviceObject, &pdo);
+ PCSTREAMRESOURCE_DESCRIPTOR_INIT(&res);
+ res.Pdo = pdo;
+ res.Type = ePcStreamResourceThread;
+ res.Resource.Thread = PsGetCurrentThread();
+
+ NTSTATUS ntStatusTest = pPortClsResMgr->AddStreamResource(NULL, &res, &hRes);
+ if (NT_SUCCESS(ntStatusTest))
+ {
+ pPortClsResMgr->RemoveStreamResource(hRes);
+ hRes = NULL;
+ }
+
+ pPortClsResMgr->Release();
+ pPortClsResMgr = NULL;
+ }
+
+ // testing IPortClsStreamResourceManager2:
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsStreamResourceManager2, (PVOID *)&pPortClsResMgr2);
+ if (NT_SUCCESS(ntStatus))
+ {
+ PCSTREAMRESOURCE_DESCRIPTOR res;
+ PCSTREAMRESOURCE hRes = NULL;
+ PDEVICE_OBJECT pdo = NULL;
+
+ PcGetPhysicalDeviceObject(_pDeviceObject, &pdo);
+ PCSTREAMRESOURCE_DESCRIPTOR_INIT(&res);
+ res.Pdo = pdo;
+ res.Type = ePcStreamResourceThread;
+ res.Resource.Thread = PsGetCurrentThread();
+
+ NTSTATUS ntStatusTest = pPortClsResMgr2->AddStreamResource2(pdo, NULL, &res, &hRes);
+ if (NT_SUCCESS(ntStatusTest))
+ {
+ pPortClsResMgr2->RemoveStreamResource(hRes);
+ hRes = NULL;
+ }
+
+ pPortClsResMgr2->Release();
+ pPortClsResMgr2 = NULL;
+ }
+ }
+
+ SAFE_RELEASE(unknownTopology);
+ SAFE_RELEASE(unknownWave);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallAllRenderFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon
+ )
+{
+ NTSTATUS ntStatus;
+ PENDPOINT_MINIPAIR* ppAeMiniports = g_RenderEndpoints;
+
+ PAGED_CODE();
+
+ for(ULONG i = 0; i < g_cRenderEndpoints; ++i, ++ppAeMiniports)
+ {
+ ntStatus = InstallEndpointRenderFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+Exit:
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallEndpointCaptureFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon,
+ _In_ PENDPOINT_MINIPAIR _pAeMiniports
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_pDeviceObject);
+
+ ntStatus = _pAdapterCommon->InstallEndpointFilters(
+ _pIrp,
+ _pAeMiniports,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallAllCaptureFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon
+)
+{
+ NTSTATUS ntStatus;
+ PENDPOINT_MINIPAIR* ppAeMiniports = g_CaptureEndpoints;
+
+ PAGED_CODE();
+
+ for (ULONG i = 0; i < g_cCaptureEndpoints; ++i, ++ppAeMiniports)
+ {
+ ntStatus = InstallEndpointCaptureFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+Exit:
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+StartDevice
+(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _In_ PRESOURCELIST ResourceList
+)
+{
+/*++
+
+Routine Description:
+
+ This function is called by the operating system when the device is
+ started.
+ It is responsible for starting the miniports. This code is specific to
+ the adapter because it calls out miniports for functions that are specific
+ to the adapter.
+
+Arguments:
+
+ DeviceObject - pointer to the driver object
+
+ Irp - pointer to the irp
+
+ ResourceList - pointer to the resource list assigned by PnP manager
+
+Return Value:
+
+ NT status code.
+
+--*/
+ UNREFERENCED_PARAMETER(ResourceList);
+
+ PAGED_CODE();
+
+ ASSERT(DeviceObject);
+ ASSERT(Irp);
+ ASSERT(ResourceList);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ PADAPTERCOMMON pAdapterCommon = NULL;
+ PUNKNOWN pUnknownCommon = NULL;
+ PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension);
+
+ DPF_ENTER(("[StartDevice]"));
+
+ //
+ // create a new adapter common object
+ //
+ ntStatus = NewAdapterCommon(
+ &pUnknownCommon,
+ IID_IAdapterCommon,
+ NULL,
+ POOL_FLAG_NON_PAGED
+ );
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ ntStatus = pUnknownCommon->QueryInterface( IID_IAdapterCommon,(PVOID *) &pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ ntStatus = pAdapterCommon->Init(DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // register with PortCls for power-management services
+ ntStatus = PcRegisterAdapterPowerManagement( PUNKNOWN(pAdapterCommon), DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // Install wave+topology filters for render devices
+ //
+ ntStatus = InstallAllRenderFilters(DeviceObject, Irp, pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // Install wave+topology filters for capture devices
+ //
+ ntStatus = InstallAllCaptureFilters(DeviceObject, Irp, pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+Exit:
+
+ //
+ // Stash the adapter common object in the device extension so
+ // we can access it for cleanup on stop/removal.
+ //
+ if (pAdapterCommon)
+ {
+ ASSERT(pExtension != NULL);
+ pExtension->m_pCommon = pAdapterCommon;
+ }
+
+ //
+ // Release the adapter IUnknown interface.
+ //
+ SAFE_RELEASE(pUnknownCommon);
+
+ return ntStatus;
+} // StartDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PnpHandler
+(
+ _In_ DEVICE_OBJECT *_DeviceObject,
+ _Inout_ IRP *_Irp
+)
+/*++
+
+Routine Description:
+
+ Handles PnP IRPs
+
+Arguments:
+
+ _DeviceObject - Functional Device object pointer.
+
+ _Irp - The Irp being passed
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ IO_STACK_LOCATION *stack;
+ PortClassDeviceContext *ext;
+
+ // Documented https://msdn.microsoft.com/en-us/library/windows/hardware/ff544039(v=vs.85).aspx
+ // This method will be called in IRQL PASSIVE_LEVEL
+#pragma warning(suppress: 28118)
+ PAGED_CODE();
+
+ ASSERT(_DeviceObject);
+ ASSERT(_Irp);
+
+ //
+ // Check for the REMOVE_DEVICE irp. If we're being unloaded,
+ // uninstantiate our devices and release the adapter common
+ // object.
+ //
+ stack = IoGetCurrentIrpStackLocation(_Irp);
+
+ switch (stack->MinorFunction)
+ {
+ case IRP_MN_REMOVE_DEVICE:
+ case IRP_MN_SURPRISE_REMOVAL:
+ case IRP_MN_STOP_DEVICE:
+ ext = static_cast<PortClassDeviceContext*>(_DeviceObject->DeviceExtension);
+
+ if (ext->m_pCommon != NULL)
+ {
+ ext->m_pCommon->Cleanup();
+
+ ext->m_pCommon->Release();
+ ext->m_pCommon = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ntStatus = PcDispatchIrp(_DeviceObject, _Irp);
+
+ return ntStatus;
+}
+
+#pragma code_seg()
+
diff --git a/audio/simpleaudiosample/Source/Main/basetopo.cpp b/audio/simpleaudiosample/Source/Main/basetopo.cpp
new file mode 100644
index 00000000..b29a9bb1
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/basetopo.cpp
@@ -0,0 +1,688 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ basetopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport. This the base class for
+ all simple audio sample drivers
+--*/
+
+//4127: conditional expression is constant
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include "basetopo.h"
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportTopologySimpleAudioSample::CMiniportTopologySimpleAudioSample
+(
+ _In_ PCFILTER_DESCRIPTOR *FilterDesc,
+ _In_ USHORT DeviceMaxChannels
+)
+/*++
+
+Routine Description:
+
+ Topology miniport constructor
+
+Arguments:
+
+ FilterDesc -
+
+ DeviceMaxChannels -
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ m_AdapterCommon = NULL;
+
+ ASSERT(FilterDesc != NULL);
+ m_FilterDescriptor = FilterDesc;
+ m_PortEvents = NULL;
+
+ ASSERT(DeviceMaxChannels > 0);
+ m_DeviceMaxChannels = DeviceMaxChannels;
+} // CMiniportTopologySimpleAudioSample
+
+CMiniportTopologySimpleAudioSample::~CMiniportTopologySimpleAudioSample
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Topology miniport destructor
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ SAFE_RELEASE(m_AdapterCommon);
+ SAFE_RELEASE(m_PortEvents);
+} // ~CMiniportTopologySimpleAudioSample
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat OPTIONAL,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest
+ quality intersection of two data ranges. Topology miniport does nothing.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
+ submitted by client in the data range intersection property
+ request
+
+ MyDataRange - Pin's data range to be compared with client's data range
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned
+
+ ResultantFormatLength - Actual length of the resultant format that is placed
+ at ResultantFormat. This should be less than or equal
+ to OutputBufferLength
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PinId);
+ UNREFERENCED_PARAMETER(ClientDataRange);
+ UNREFERENCED_PARAMETER(MyDataRange);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(ResultantFormat);
+ UNREFERENCED_PARAMETER(ResultantFormatLength);
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ return (STATUS_NOT_IMPLEMENTED);
+} // DataRangeIntersection
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure. This is the placeholder for the FromNode or ToNode fields in
+ connections which describe connections to the filter's pins
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ *OutFilterDescriptor = m_FilterDescriptor;
+
+ return (STATUS_SUCCESS);
+} // GetDescription
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::Init
+(
+ _In_ PUNKNOWN UnknownAdapter_,
+ _In_ PPORTTOPOLOGY Port_
+)
+/*++
+
+Routine Description:
+
+ Initializes the topology miniport.
+
+Arguments:
+
+ UnknownAdapter -
+
+ Port_ - Pointer to topology port
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter_);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMiniportTopologySimpleAudioSample::Init]"));
+
+ NTSTATUS ntStatus;
+
+ ntStatus =
+ UnknownAdapter_->QueryInterface(
+ IID_IAdapterCommon,
+ (PVOID *) &m_AdapterCommon);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Get the port event interface.
+ //
+ ntStatus = Port_->QueryInterface(
+ IID_IPortEvents,
+ (PVOID *)&m_PortEvents);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_AdapterCommon->MixerReset();
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ // clean up AdapterCommon
+ SAFE_RELEASE(m_AdapterCommon);
+ SAFE_RELEASE(m_PortEvents);
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerGeneric
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles all properties for this miniport.
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ switch (PropertyRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_AUDIO_VOLUMELEVEL:
+ ntStatus = PropertyHandler_Volume(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_MUTE:
+ ntStatus = PropertyHandler_Mute(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_PEAKMETER2:
+ ntStatus = PropertyHandler_PeakMeter2(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_CPU_RESOURCES:
+ ntStatus = PropertyHandler_CpuResources(PropertyRequest);
+ break;
+
+ case KSPROPERTY_AUDIO_MUX_SOURCE:
+ ntStatus = PropertyHandlerMuxSource(PropertyRequest);
+ break;
+
+ case KSPROPERTY_AUDIO_DEV_SPECIFIC:
+ ntStatus = PropertyHandlerDevSpecific(PropertyRequest);
+ break;
+
+ default:
+ DPF(D_TERSE, ("[PropertyHandlerGeneric: Invalid Device Request]"));
+ }
+
+ return ntStatus;
+} // PropertyHandlerGeneric
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerMuxSource
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ PropertyHandler for KSPROPERTY_AUDIO_MUX_SOURCE.
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Validate node
+ // This property is only valid for WAVEIN_MUX node.
+ //
+ // TODO if (WAVEIN_MUX == PropertyRequest->Node)
+ {
+ if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ PULONG pulMuxValue = PULONG(PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *pulMuxValue = m_AdapterCommon->MixerMuxRead();
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->MixerMuxWrite(*pulMuxValue);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_ALL,
+ VT_I4
+ );
+ }
+ }
+ else
+ {
+ DPF(D_TERSE, ("[PropertyHandlerMuxSource - Invalid parameter]"));
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerMuxSource
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerDevSpecific(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Property handler for KSPROPERTY_AUDIO_DEV_SPECIFIC
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus=STATUS_SUCCESS;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ if( DEV_SPECIFIC_VT_BOOL == PropertyRequest->Node )
+ {
+ ntStatus = PropertyHandler_BasicSupport(PropertyRequest,KSPROPERTY_TYPE_ALL,VT_BOOL);
+ }
+ else
+ {
+ ULONG ExpectedSize = sizeof( KSPROPERTY_DESCRIPTION ) +
+ sizeof( KSPROPERTY_MEMBERSHEADER ) +
+ sizeof( KSPROPERTY_BOUNDS_LONG );
+ DWORD ulPropTypeSetId;
+
+ if( DEV_SPECIFIC_VT_I4 == PropertyRequest->Node )
+ {
+ ulPropTypeSetId = VT_I4;
+ }
+ else if ( DEV_SPECIFIC_VT_UI4 == PropertyRequest->Node )
+ {
+ ulPropTypeSetId = VT_UI4;
+ }
+ else
+ {
+ ulPropTypeSetId = VT_ILLEGAL;
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if( NT_SUCCESS(ntStatus))
+ {
+ if ( !PropertyRequest->ValueSize )
+ {
+ PropertyRequest->ValueSize = ExpectedSize;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
+ {
+ // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
+ //
+ PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL;
+ PropDesc->DescriptionSize = ExpectedSize;
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = ulPropTypeSetId;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 0;
+ PropDesc->Reserved = 0;
+
+ if ( PropertyRequest->ValueSize >= ExpectedSize )
+ {
+ // Extra information to return
+ PropDesc->MembersListCount = 1;
+
+ PKSPROPERTY_MEMBERSHEADER MembersHeader = ( PKSPROPERTY_MEMBERSHEADER )( PropDesc + 1);
+ MembersHeader->MembersFlags = KSPROPERTY_MEMBER_RANGES;
+ MembersHeader->MembersCount = 1;
+ MembersHeader->MembersSize = sizeof( KSPROPERTY_BOUNDS_LONG );
+ MembersHeader->Flags = 0;
+
+ PKSPROPERTY_BOUNDS_LONG PeakMeterBounds = (PKSPROPERTY_BOUNDS_LONG)( MembersHeader + 1);
+ if(VT_I4 == ulPropTypeSetId )
+ {
+ PeakMeterBounds->SignedMinimum = 0;
+ PeakMeterBounds->SignedMaximum = 0x7fffffff;
+ }
+ else
+ {
+ PeakMeterBounds->UnsignedMinimum = 0;
+ PeakMeterBounds->UnsignedMaximum = 0xffffffff;
+ }
+
+ // set the return value size
+ PropertyRequest->ValueSize = ExpectedSize;
+ }
+ else
+ {
+ // No extra information to return.
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ //
+ *(PULONG(PropertyRequest->Value)) = KSPROPERTY_TYPE_ALL;
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+ }
+ else
+ {
+ // switch on node id
+ switch( PropertyRequest->Node )
+ {
+ case DEV_SPECIFIC_VT_BOOL:
+ {
+ PBOOL pbDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(BOOL), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ pbDevSpecific = PBOOL (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *pbDevSpecific = m_AdapterCommon->bDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(BOOL);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->bDevSpecificWrite(*pbDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ case DEV_SPECIFIC_VT_I4:
+ {
+ INT* piDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(int), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ piDevSpecific = PINT (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *piDevSpecific = m_AdapterCommon->iDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(int);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->iDevSpecificWrite(*piDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ case DEV_SPECIFIC_VT_UI4:
+ {
+ UINT* puiDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(UINT), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ puiDevSpecific = PUINT (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *puiDevSpecific = m_AdapterCommon->uiDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(UINT);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->uiDevSpecificWrite(*puiDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ default:
+ ntStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+
+ if( !NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus));
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerDevSpecific
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID
+CMiniportTopologySimpleAudioSample::AddEventToEventList
+(
+ _In_ PKSEVENT_ENTRY EventEntry
+)
+/*++
+
+Routine Description:
+
+ The AddEventToEventList method adds an event to the port driver's event list
+
+Arguments:
+
+ EventEntry -
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CMiniportTopology::AddEventToEventList]"));
+
+ ASSERT(m_PortEvents != NULL);
+
+ m_PortEvents->AddEventToEventList(EventEntry);
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID
+CMiniportTopologySimpleAudioSample::GenerateEventList
+(
+ _In_opt_ GUID *Set,
+ _In_ ULONG EventId,
+ _In_ BOOL PinEvent,
+ _In_ ULONG PinId,
+ _In_ BOOL NodeEvent,
+ _In_ ULONG NodeId
+)
+/*++
+
+Routine Description:
+
+ The GenerateEventList method notifies clients through the port driver's list
+ of event entries that a particular event has occurred.
+
+Arguments:
+
+ Set -
+
+ EventId -
+
+ PinEvent -
+
+ PinId -
+
+ NodeEvent -
+
+ NodeId -
+
+--*/
+{
+ DPF_ENTER(("[CMiniportTopologySimpleAudioSample::GenerateEventList]"));
+
+ ASSERT(m_PortEvents != NULL);
+
+ m_PortEvents->GenerateEventList(
+ Set,
+ EventId,
+ PinEvent,
+ PinId,
+ NodeEvent,
+ NodeId);
+}
+
+#pragma code_seg()
diff --git a/audio/simpleaudiosample/Source/Main/common.cpp b/audio/simpleaudiosample/Source/Main/common.cpp
new file mode 100644
index 00000000..8843d3a4
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/common.cpp
@@ -0,0 +1,2772 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ common.cpp
+
+Abstract:
+
+ Implementation of the AdapterCommon class.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include <initguid.h>
+#include "definitions.h"
+#include "hw.h"
+#include "savedata.h"
+#include "endpoints.h"
+
+//-----------------------------------------------------------------------------
+// CSaveData statics
+//-----------------------------------------------------------------------------
+
+PSAVEWORKER_PARAM CSaveData::m_pWorkItems = NULL;
+PDEVICE_OBJECT CSaveData::m_pDeviceObject = NULL;
+//=============================================================================
+// Classes
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// CAdapterCommon
+//
+class CAdapterCommon :
+ public IAdapterCommon,
+ public IAdapterPowerManagement,
+ public CUnknown
+{
+ private:
+ PSERVICEGROUP m_pServiceGroupWave;
+ PDEVICE_OBJECT m_pDeviceObject;
+ PDEVICE_OBJECT m_pPhysicalDeviceObject;
+ WDFDEVICE m_WdfDevice; // Wdf device.
+ DEVICE_POWER_STATE m_PowerState;
+
+ PCSimpleAudioSampleHW m_pHW; // Virtual Simple Audio Sample HW object
+ PPORTCLSETWHELPER m_pPortClsEtwHelper;
+
+ static LONG m_AdapterInstances; // # of adapter objects.
+
+ DWORD m_dwIdleRequests;
+
+ public:
+ //=====================================================================
+ // Default CUnknown
+ DECLARE_STD_UNKNOWN();
+ DEFINE_STD_CONSTRUCTOR(CAdapterCommon);
+ ~CAdapterCommon();
+
+ //=====================================================================
+ // Default IAdapterPowerManagement
+ IMP_IAdapterPowerManagement;
+
+ //=====================================================================
+ // IAdapterCommon methods
+
+ STDMETHODIMP_(NTSTATUS) Init
+ (
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+ STDMETHODIMP_(PDEVICE_OBJECT) GetDeviceObject(void);
+
+ STDMETHODIMP_(PDEVICE_OBJECT) GetPhysicalDeviceObject(void);
+
+ STDMETHODIMP_(WDFDEVICE) GetWdfDevice(void);
+
+ STDMETHODIMP_(void) SetWaveServiceGroup
+ (
+ _In_ PSERVICEGROUP ServiceGroup
+ );
+
+ STDMETHODIMP_(BOOL) bDevSpecificRead();
+
+ STDMETHODIMP_(void) bDevSpecificWrite
+ (
+ _In_ BOOL bDevSpecific
+ );
+ STDMETHODIMP_(INT) iDevSpecificRead();
+
+ STDMETHODIMP_(void) iDevSpecificWrite
+ (
+ _In_ INT iDevSpecific
+ );
+ STDMETHODIMP_(UINT) uiDevSpecificRead();
+
+ STDMETHODIMP_(void) uiDevSpecificWrite
+ (
+ _In_ UINT uiDevSpecific
+ );
+
+ STDMETHODIMP_(BOOL) MixerMuteRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(void) MixerMuteWrite
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ BOOL Value
+ );
+
+ STDMETHODIMP_(ULONG) MixerMuxRead(void);
+
+ STDMETHODIMP_(void) MixerMuxWrite
+ (
+ _In_ ULONG Index
+ );
+
+ STDMETHODIMP_(void) MixerReset(void);
+
+ STDMETHODIMP_(LONG) MixerVolumeRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(void) MixerVolumeWrite
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ LONG Value
+ );
+
+ STDMETHODIMP_(LONG) MixerPeakMeterRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(NTSTATUS) WriteEtwEvent
+ (
+ _In_ EPcMiniportEngineEvent miniportEventType,
+ _In_ ULONGLONG ullData1,
+ _In_ ULONGLONG ullData2,
+ _In_ ULONGLONG ullData3,
+ _In_ ULONGLONG ullData4
+ );
+
+ STDMETHODIMP_(VOID) SetEtwHelper
+ (
+ PPORTCLSETWHELPER _pPortClsEtwHelper
+ );
+
+ STDMETHODIMP_(NTSTATUS) InstallSubdevice
+ (
+ _In_opt_ PIRP Irp,
+ _In_ PWSTR Name,
+ _In_opt_ PWSTR TemplateName,
+ _In_ REFGUID PortClassId,
+ _In_ REFGUID MiniportClassId,
+ _In_opt_ PFNCREATEMINIPORT MiniportCreate,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY * pProperties,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PRESOURCELIST ResourceList,
+ _In_ REFGUID PortInterfaceId,
+ _Out_opt_ PUNKNOWN * OutPortInterface,
+ _Out_opt_ PUNKNOWN * OutPortUnknown,
+ _Out_opt_ PUNKNOWN * OutMiniportUnknown
+ );
+
+ STDMETHODIMP_(NTSTATUS) UnregisterSubdevice
+ (
+ _In_opt_ PUNKNOWN UnknownPort
+ );
+
+ STDMETHODIMP_(NTSTATUS) ConnectTopologies
+ (
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHODIMP_(NTSTATUS) DisconnectTopologies
+ (
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHODIMP_(NTSTATUS) InstallEndpointFilters
+ (
+ _In_opt_ PIRP Irp,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext,
+ _Out_opt_ PUNKNOWN * UnknownTopology,
+ _Out_opt_ PUNKNOWN * UnknownWave,
+ _Out_opt_ PUNKNOWN * UnknownMiniportTopology,
+ _Out_opt_ PUNKNOWN * UnknownMiniportWave
+ );
+
+ STDMETHODIMP_(NTSTATUS) RemoveEndpointFilters
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PUNKNOWN UnknownTopology,
+ _In_opt_ PUNKNOWN UnknownWave
+ );
+
+ STDMETHODIMP_(NTSTATUS) GetFilters
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _Out_opt_ PUNKNOWN *UnknownTopologyPort,
+ _Out_opt_ PUNKNOWN *UnknownTopologyMiniport,
+ _Out_opt_ PUNKNOWN *UnknownWavePort,
+ _Out_opt_ PUNKNOWN *UnknownWaveMiniport
+ );
+
+ STDMETHODIMP_(NTSTATUS) SetIdlePowerManagement
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_ BOOL bEnabled
+ );
+
+ STDMETHODIMP_(VOID) Cleanup();
+
+ //=====================================================================
+ // friends
+ friend NTSTATUS NewAdapterCommon
+ (
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags
+ );
+
+ private:
+
+ LIST_ENTRY m_SubdeviceCache;
+
+ NTSTATUS GetCachedSubdevice
+ (
+ _In_ PWSTR Name,
+ _Out_opt_ PUNKNOWN *OutUnknownPort,
+ _Out_opt_ PUNKNOWN *OutUnknownMiniport
+ );
+
+ NTSTATUS CacheSubdevice
+ (
+ _In_ PWSTR Name,
+ _In_ PUNKNOWN UnknownPort,
+ _In_ PUNKNOWN UnknownMiniport
+ );
+
+ NTSTATUS RemoveCachedSubdevice
+ (
+ _In_ PWSTR Name
+ );
+
+ VOID EmptySubdeviceCache();
+
+ NTSTATUS CreateAudioInterfaceWithProperties
+ (
+ _In_ PCWSTR ReferenceString,
+ _In_opt_ PCWSTR TemplateReferenceString,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties,
+ _Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
+ );
+
+ NTSTATUS MigrateDeviceInterfaceTemplateParameters
+ (
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_opt_ PCWSTR TemplateReferenceString
+ );
+};
+
+typedef struct _MINIPAIR_UNKNOWN
+{
+ LIST_ENTRY ListEntry;
+ WCHAR Name[MAX_PATH];
+ PUNKNOWN PortInterface;
+ PUNKNOWN MiniportInterface;
+ PADAPTERPOWERMANAGEMENT PowerInterface;
+} MINIPAIR_UNKNOWN;
+
+#define MAX_DEVICE_REG_KEY_LENGTH 0x100
+
+//
+// Used to implement the singleton pattern.
+//
+LONG CAdapterCommon::m_AdapterInstances = 0;
+
+
+
+//-----------------------------------------------------------------------------
+// Functions
+//-----------------------------------------------------------------------------
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple
+(
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties
+)
+{
+ NTSTATUS ntStatus;
+
+ PAGED_CODE();
+
+ if (pProperties)
+ {
+ for (ULONG i = 0; i < cPropertyCount; i++)
+ {
+ ntStatus = IoSetDeviceInterfacePropertyData(
+ SymbolicLinkName,
+ pProperties[i].PropertyKey,
+ LOCALE_NEUTRAL,
+ PLUGPLAY_PROPERTY_PERSISTENT,
+ pProperties[i].Type,
+ pProperties[i].BufferSize,
+ pProperties[i].Buffer);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+NewAdapterCommon
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags
+)
+/*++
+
+Routine Description:
+
+ Creates a new CAdapterCommon
+
+Arguments:
+
+ Unknown -
+
+ UnknownOuter -
+
+ PoolType
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+
+ NTSTATUS ntStatus;
+
+ //
+ // This sample supports only one instance of this object.
+ // (b/c of CSaveData's static members and Bluetooth HFP logic).
+ //
+ if (InterlockedCompareExchange(&CAdapterCommon::m_AdapterInstances, 1, 0) != 0)
+ {
+ ntStatus = STATUS_DEVICE_BUSY;
+ DPF(D_ERROR, ("NewAdapterCommon failed, only one instance is allowed"));
+ goto Done;
+ }
+
+ //
+ // Allocate an adapter object.
+ //
+ CAdapterCommon *p = new(PoolFlags, MINADAPTER_POOLTAG) CAdapterCommon(UnknownOuter);
+ if (p == NULL)
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ DPF(D_ERROR, ("NewAdapterCommon failed, 0x%x", ntStatus));
+ goto Done;
+ }
+
+ //
+ // Success.
+ //
+ *Unknown = PUNKNOWN((PADAPTERCOMMON)(p));
+ (*Unknown)->AddRef();
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ return ntStatus;
+} // NewAdapterCommon
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CAdapterCommon::~CAdapterCommon
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for CAdapterCommon.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::~CAdapterCommon]"));
+
+ if (m_pHW)
+ {
+ delete m_pHW;
+ m_pHW = NULL;
+ }
+
+ CSaveData::DestroyWorkItems();
+ SAFE_RELEASE(m_pPortClsEtwHelper);
+ SAFE_RELEASE(m_pServiceGroupWave);
+
+ if (m_WdfDevice)
+ {
+ WdfObjectDelete(m_WdfDevice);
+ m_WdfDevice = NULL;
+ }
+
+ InterlockedDecrement(&CAdapterCommon::m_AdapterInstances);
+ ASSERT(CAdapterCommon::m_AdapterInstances == 0);
+} // ~CAdapterCommon
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(PDEVICE_OBJECT)
+CAdapterCommon::GetDeviceObject
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the deviceobject
+
+Arguments:
+
+Return Value:
+
+ PDEVICE_OBJECT
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_pDeviceObject;
+} // GetDeviceObject
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(PDEVICE_OBJECT)
+CAdapterCommon::GetPhysicalDeviceObject
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the PDO.
+
+Arguments:
+
+Return Value:
+
+ PDEVICE_OBJECT
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_pPhysicalDeviceObject;
+} // GetPhysicalDeviceObject
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(WDFDEVICE)
+CAdapterCommon::GetWdfDevice
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the associated WDF miniport device. Note that this is NOT an audio
+ miniport. The WDF miniport device is the WDF device associated with the
+ adapter.
+
+Arguments:
+
+Return Value:
+
+ WDFDEVICE
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_WdfDevice;
+} // GetWdfDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::Init
+(
+ _In_ PDEVICE_OBJECT DeviceObject
+)
+/*++
+
+Routine Description:
+
+ Initialize adapter common object.
+
+Arguments:
+
+ DeviceObject - pointer to the device object
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::Init]"));
+
+ ASSERT(DeviceObject);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_pServiceGroupWave = NULL;
+ m_pDeviceObject = DeviceObject;
+ m_pPhysicalDeviceObject = NULL;
+ m_WdfDevice = NULL;
+ m_PowerState = PowerDeviceD0;
+ m_pHW = NULL;
+ m_pPortClsEtwHelper = NULL;
+
+ InitializeListHead(&m_SubdeviceCache);
+
+ //
+ // Get the PDO.
+ //
+ ntStatus = PcGetPhysicalDeviceObject(DeviceObject, &m_pPhysicalDeviceObject);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("PcGetPhysicalDeviceObject failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Create a WDF miniport to represent the adapter. Note that WDF miniports
+ // are NOT audio miniports. An audio adapter is associated with a single WDF
+ // miniport. This driver uses WDF to simplify the handling of the Bluetooth
+ // SCO HFP Bypass interface.
+ //
+ ntStatus = WdfDeviceMiniportCreate( WdfGetDriver(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ DeviceObject, // FDO
+ NULL, // Next device.
+ NULL, // PDO
+ &m_WdfDevice);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("WdfDeviceMiniportCreate failed, 0x%x", ntStatus)),
+ Done);
+
+ // Initialize HW.
+ //
+ m_pHW = new (POOL_FLAG_NON_PAGED, SIMPLEAUDIOSAMPLE_POOLTAG) CSimpleAudioSampleHW;
+ if (!m_pHW)
+ {
+ DPF(D_TERSE, ("Insufficient memory for Simple Audio Sample HW"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ IF_FAILED_JUMP(ntStatus, Done);
+
+ m_pHW->MixerReset();
+
+ //
+ // Initialize SaveData class.
+ //
+ CSaveData::SetDeviceObject(DeviceObject); //device object is needed by CSaveData
+ ntStatus = CSaveData::InitializeWorkItems(DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Done);
+Done:
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::MixerReset
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Reset mixer registers from registry.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ if (m_pHW)
+ {
+ m_pHW->MixerReset();
+ }
+} // MixerReset
+
+//=============================================================================
+/* Here are the definitions of the standard miniport events.
+
+Event type : eMINIPORT_IHV_DEFINED
+Parameter 1 : Defined and used by IHVs
+Parameter 2 : Defined and used by IHVs
+Parameter 3 : Defined and used by IHVs
+Parameter 4 :Defined and used by IHVs
+
+Event type: eMINIPORT_BUFFER_COMPLETE
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Data length completed
+Parameter 4:0
+
+Event type: eMINIPORT_PIN_STATE
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Pin State 0->KS_STOP, 1->KS_ACQUIRE, 2->KS_PAUSE, 3->KS_RUN
+Parameter 4:0
+
+Event type: eMINIPORT_GET_STREAM_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: 0
+Parameter 4:0
+
+
+Event type: eMINIPORT_SET_WAVERT_BUFFER_WRITE_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: the arget WaveRtBufferWritePosition received from portcls
+Parameter 4:0
+
+Event type: eMINIPORT_GET_PRESENTATION_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Presentation position
+Parameter 4:0
+
+Event type: eMINIPORT_PROGRAM_DMA
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Starting WaveRt buffer offset
+Parameter 4: Data length
+
+Event type: eMINIPORT_GLITCH_REPORT
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: major glitch code: 1:WaveRT buffer is underrun,
+ 2:decoder errors,
+ 3:receive the same wavert buffer two in a row in event driven mode
+Parameter 4: minor code for the glitch cause
+
+Event type: eMINIPORT_LAST_BUFFER_RENDERED
+Parameter 1: Current linear buffer position
+Parameter 2: the very last WaveRtBufferWritePosition that the driver received
+Parameter 3: 0
+Parameter 4: 0
+
+*/
+#pragma code_seg()
+STDMETHODIMP
+CAdapterCommon::WriteEtwEvent
+(
+ _In_ EPcMiniportEngineEvent miniportEventType,
+ _In_ ULONGLONG ullData1,
+ _In_ ULONGLONG ullData2,
+ _In_ ULONGLONG ullData3,
+ _In_ ULONGLONG ullData4
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (m_pPortClsEtwHelper)
+ {
+ ntStatus = m_pPortClsEtwHelper->MiniportWriteEtwEvent( miniportEventType, ullData1, ullData2, ullData3, ullData4) ;
+ }
+ return ntStatus;
+} // WriteEtwEvent
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::SetEtwHelper
+(
+ PPORTCLSETWHELPER _pPortClsEtwHelper
+)
+{
+ PAGED_CODE();
+
+ SAFE_RELEASE(m_pPortClsEtwHelper);
+
+ m_pPortClsEtwHelper = _pPortClsEtwHelper;
+
+ if (m_pPortClsEtwHelper)
+ {
+ m_pPortClsEtwHelper->AddRef();
+ }
+} // SetEtwHelper
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP
+CAdapterCommon::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface routine for AdapterCommon
+
+Arguments:
+
+ Interface -
+
+ Object -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PADAPTERCOMMON(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IAdapterCommon))
+ {
+ *Object = PVOID(PADAPTERCOMMON(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement))
+ {
+ *Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::SetWaveServiceGroup
+(
+ _In_ PSERVICEGROUP ServiceGroup
+)
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::SetWaveServiceGroup]"));
+
+ SAFE_RELEASE(m_pServiceGroupWave);
+
+ m_pServiceGroupWave = ServiceGroup;
+
+ if (m_pServiceGroupWave)
+ {
+ m_pServiceGroupWave->AddRef();
+ }
+} // SetWaveServiceGroup
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(BOOL)
+CAdapterCommon::bDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ BOOL - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->bGetDevSpecific();
+ }
+
+ return FALSE;
+} // bDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::bDevSpecificWrite
+(
+ _In_ BOOL bDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ bDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->bSetDevSpecific(bDevSpecific);
+ }
+} // DevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(INT)
+CAdapterCommon::iDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ INT - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->iGetDevSpecific();
+ }
+
+ return 0;
+} // iDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::iDevSpecificWrite
+(
+ _In_ INT iDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ iDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->iSetDevSpecific(iDevSpecific);
+ }
+} // iDevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(UINT)
+CAdapterCommon::uiDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ UINT - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->uiGetDevSpecific();
+ }
+
+ return 0;
+} // uiDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::uiDevSpecificWrite
+(
+ _In_ UINT uiDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ uiDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->uiSetDevSpecific(uiDevSpecific);
+ }
+} // uiDevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(BOOL)
+CAdapterCommon::MixerMuteRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+Return Value:
+
+ BOOL - mixer mute setting for this node
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerMute(Index, Channel);
+ }
+
+ return 0;
+} // MixerMuteRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerMuteWrite
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ BOOL Value
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerMute(Index, Channel, Value);
+ }
+} // MixerMuteWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(ULONG)
+CAdapterCommon::MixerMuxRead()
+/*++
+
+Routine Description:
+
+ Return the mux selection
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerMux();
+ }
+
+ return 0;
+} // MixerMuxRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerMuxWrite
+(
+ _In_ ULONG Index
+)
+/*++
+
+Routine Description:
+
+ Store the new mux selection
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerMux(Index);
+ }
+} // MixerMuxWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(LONG)
+CAdapterCommon::MixerVolumeRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Return the value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel = which channel
+
+Return Value:
+
+ Byte - mixer volume settings for this line
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerVolume(Index, Channel);
+ }
+
+ return 0;
+} // MixerVolumeRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerVolumeWrite
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ LONG Value
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel - which channel
+
+ Value - new volume level
+
+Return Value:
+
+ void
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerVolume(Index, Channel, Value);
+ }
+} // MixerVolumeWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(LONG)
+CAdapterCommon::MixerPeakMeterRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Return the value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel = which channel
+
+Return Value:
+
+ Byte - mixer sample peak meter settings for this line
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerPeakMeter(Index, Channel);
+ }
+
+ return 0;
+} // MixerVolumeRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::PowerChangeState
+(
+ _In_ POWER_STATE NewState
+)
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ NewState - The requested, new power state for the device.
+
+Return Value:
+
+ void
+
+Note:
+ From MSDN:
+
+ To assist the driver, PortCls will pause any active audio streams prior to calling
+ this method to place the device in a sleep state. After calling this method, PortCls
+ will unpause active audio streams, to wake the device up. Miniports can opt for
+ additional notification by utilizing the IPowerNotify interface.
+
+ The miniport driver must perform the requested change to the device's power state
+ before it returns from the PowerChangeState call. If the miniport driver needs to
+ save or restore any device state before a power-state change, the miniport driver
+ should support the IPowerNotify interface, which allows it to receive advance warning
+ of any such change. Before returning from a successful PowerChangeState call, the
+ miniport driver should cache the new power state.
+
+ While the miniport driver is in one of the sleep states (any state other than
+ PowerDeviceD0), it must avoid writing to the hardware. The miniport driver must cache
+ any hardware accesses that need to be deferred until the device powers up again. If
+ the power state is changing from one of the sleep states to PowerDeviceD0, the
+ miniport driver should perform any deferred hardware accesses after it has powered up
+ the device. If the power state is changing from PowerDeviceD0 to a sleep state, the
+ miniport driver can perform any necessary hardware accesses during the PowerChangeState
+ call before it powers down the device.
+
+ While powered down, a miniport driver is never asked to create a miniport driver object
+ or stream object. PortCls always places the device in the PowerDeviceD0 state before
+ calling the miniport driver's NewStream method.
+
+--*/
+{
+ DPF_ENTER(("[CAdapterCommon::PowerChangeState]"));
+
+ // Notify all registered miniports of a power state change
+ PLIST_ENTRY le = NULL;
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (pRecord->PowerInterface)
+ {
+ pRecord->PowerInterface->PowerChangeState(NewState);
+ }
+ }
+
+ // is this actually a state change??
+ //
+ if (NewState.DeviceState != m_PowerState)
+ {
+ // switch on new state
+ //
+ switch (NewState.DeviceState)
+ {
+ case PowerDeviceD0:
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3:
+ m_PowerState = NewState.DeviceState;
+
+ DPF
+ (
+ D_VERBOSE,
+ ("Entering D%u", ULONG(m_PowerState) - ULONG(PowerDeviceD0))
+ );
+
+ break;
+
+ default:
+
+ DPF(D_VERBOSE, ("Unknown Device Power State"));
+ break;
+ }
+ }
+} // PowerStateChange
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::QueryDeviceCapabilities
+(
+ _Inout_updates_bytes_(sizeof(DEVICE_CAPABILITIES)) PDEVICE_CAPABILITIES PowerDeviceCaps
+)
+/*++
+
+Routine Description:
+
+ Called at startup to get the caps for the device. This structure provides
+ the system with the mappings between system power state and device power
+ state. This typically will not need modification by the driver.
+
+Arguments:
+
+ PowerDeviceCaps - The device's capabilities.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PowerDeviceCaps);
+
+ DPF_ENTER(("[CAdapterCommon::QueryDeviceCapabilities]"));
+
+ return (STATUS_SUCCESS);
+} // QueryDeviceCapabilities
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::QueryPowerChangeState
+(
+ _In_ POWER_STATE NewStateQuery
+)
+/*++
+
+Routine Description:
+
+ Query to see if the device can change to this power state
+
+Arguments:
+
+ NewStateQuery - The requested, new power state for the device
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DPF_ENTER(("[CAdapterCommon::QueryPowerChangeState]"));
+
+ // query each miniport for it's power state, we're finished if even one indicates
+ // it cannot go to this power state.
+ PLIST_ENTRY le = NULL;
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && NT_SUCCESS(status); le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (pRecord->PowerInterface)
+ {
+ status = pRecord->PowerInterface->QueryPowerChangeState(NewStateQuery);
+ }
+ }
+
+ return status;
+} // QueryPowerChangeState
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::CreateAudioInterfaceWithProperties
+(
+ _In_ PCWSTR ReferenceString,
+ _In_opt_ PCWSTR TemplateReferenceString,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties,
+ _Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
+)
+/*++
+
+Routine Description:
+
+Create the audio interface (in disabled mode).
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::CreateAudioInterfaceWithProperties]"));
+
+ NTSTATUS ntStatus;
+ UNICODE_STRING referenceString;
+
+ RtlInitUnicodeString(&referenceString, ReferenceString);
+
+ //
+ // Reset output value.
+ //
+ RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
+
+ //
+ // Register an audio interface if not already present.
+ //
+ ntStatus = IoRegisterDeviceInterface(
+ GetPhysicalDeviceObject(),
+ &KSCATEGORY_AUDIO,
+ &referenceString,
+ AudioSymbolicLinkName);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: IoRegisterDeviceInterface(KSCATEGORY_AUDIO): failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Migrate optional device interface parameters from the template if it exists
+ // This is done first, so that any additional parameters in pProperties will override the defaults.
+ //
+ if (NULL != TemplateReferenceString)
+ {
+ ntStatus = MigrateDeviceInterfaceTemplateParameters(AudioSymbolicLinkName, TemplateReferenceString);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("MigrateDeviceInterfaceTempalteParameters: MigrateDeviceInterfaceTemplateParameters(...): failed, 0x%x", ntStatus)),
+ Done);
+ }
+
+ //
+ // Set properties on the interface
+ //
+ ntStatus = SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple(AudioSymbolicLinkName, cPropertyCount, pProperties);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple(...): failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // All done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ if (!NT_SUCCESS(ntStatus))
+ {
+ RtlFreeUnicodeString(AudioSymbolicLinkName);
+ RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
+ }
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::InstallSubdevice
+(
+ _In_opt_ PIRP Irp,
+ _In_ PWSTR Name,
+ _In_opt_ PWSTR TemplateName,
+ _In_ REFGUID PortClassId,
+ _In_ REFGUID MiniportClassId,
+ _In_opt_ PFNCREATEMINIPORT MiniportCreate,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY * pProperties,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PRESOURCELIST ResourceList,
+ _In_ REFGUID PortInterfaceId,
+ _Out_opt_ PUNKNOWN * OutPortInterface,
+ _Out_opt_ PUNKNOWN * OutPortUnknown,
+ _Out_opt_ PUNKNOWN * OutMiniportUnknown
+)
+{
+/*++
+
+Routine Description:
+
+ This function creates and registers a subdevice consisting of a port
+ driver, a minport driver and a set of resources bound together. It will
+ also optionally place a pointer to an interface on the port driver in a
+ specified location before initializing the port driver. This is done so
+ that a common ISR can have access to the port driver during
+ initialization, when the ISR might fire.
+
+Arguments:
+
+ Irp - pointer to the irp object.
+
+ Name - name of the miniport. Passes to PcRegisterSubDevice
+
+ PortClassId - port class id. Passed to PcNewPort.
+
+ MiniportClassId - miniport class id. Passed to PcNewMiniport.
+
+ MiniportCreate - pointer to a miniport creation function. If NULL,
+ PcNewMiniport is used.
+
+ DeviceContext - deviceType specific.
+
+ MiniportPair - endpoint configuration info.
+
+ ResourceList - pointer to the resource list.
+
+ PortInterfaceId - GUID that represents the port interface.
+
+ OutPortInterface - pointer to store the port interface
+
+ OutPortUnknown - pointer to store the unknown port interface.
+
+ OutMiniportUnknown - pointer to store the unknown miniport interface
+
+Return Value:
+
+ NT status code.
+
+--*/
+ PAGED_CODE();
+ DPF_ENTER(("[InstallSubDevice %S]", Name));
+
+ ASSERT(Name != NULL);
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus;
+ PPORT port = NULL;
+ PUNKNOWN miniport = NULL;
+ PADAPTERCOMMON adapterCommon = NULL;
+ UNICODE_STRING symbolicLink = { 0 };
+
+ adapterCommon = PADAPTERCOMMON(this);
+
+ ntStatus = CreateAudioInterfaceWithProperties(Name, TemplateName, cPropertyCount, pProperties, &symbolicLink);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Currently have no use for the symbolic link
+ RtlFreeUnicodeString(&symbolicLink);
+
+ // Create the port driver object
+ //
+ ntStatus = PcNewPort(&port, PortClassId);
+ }
+
+ // Create the miniport object
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (MiniportCreate)
+ {
+ ntStatus =
+ MiniportCreate
+ (
+ &miniport,
+ MiniportClassId,
+ NULL,
+ POOL_FLAG_NON_PAGED,
+ adapterCommon,
+ DeviceContext,
+ MiniportPair
+ );
+ }
+ else
+ {
+ ntStatus =
+ PcNewMiniport
+ (
+ (PMINIPORT *) &miniport,
+ MiniportClassId
+ );
+ }
+ }
+
+ // Init the port driver and miniport in one go.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+#pragma warning(push)
+ // IPort::Init's annotation on ResourceList requires it to be non-NULL. However,
+ // for dynamic devices, we may no longer have the resource list and this should
+ // still succeed.
+ //
+#pragma warning(disable:6387)
+ ntStatus =
+ port->Init
+ (
+ m_pDeviceObject,
+ Irp,
+ miniport,
+ adapterCommon,
+ ResourceList
+ );
+#pragma warning (pop)
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Register the subdevice (port/miniport combination).
+ //
+ ntStatus =
+ PcRegisterSubdevice
+ (
+ m_pDeviceObject,
+ Name,
+ port
+ );
+ }
+ }
+
+ // Deposit the port interfaces if it's needed.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (OutPortUnknown)
+ {
+ ntStatus =
+ port->QueryInterface
+ (
+ IID_IUnknown,
+ (PVOID *)OutPortUnknown
+ );
+ }
+
+ if (OutPortInterface)
+ {
+ ntStatus =
+ port->QueryInterface
+ (
+ PortInterfaceId,
+ (PVOID *) OutPortInterface
+ );
+ }
+
+ if (OutMiniportUnknown)
+ {
+ ntStatus =
+ miniport->QueryInterface
+ (
+ IID_IUnknown,
+ (PVOID *)OutMiniportUnknown
+ );
+ }
+
+ }
+
+ if (port)
+ {
+ port->Release();
+ }
+
+ if (miniport)
+ {
+ miniport->Release();
+ }
+
+ return ntStatus;
+} // InstallSubDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::UnregisterSubdevice
+(
+ _In_opt_ PUNKNOWN UnknownPort
+)
+/*++
+
+Routine Description:
+
+ Unregisters and releases the specified subdevice.
+
+Arguments:
+
+ UnknownPort - Wave or topology port interface.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::UnregisterSubdevice]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNREGISTERSUBDEVICE unregisterSubdevice = NULL;
+
+ if (NULL == UnknownPort)
+ {
+ return ntStatus;
+ }
+
+ //
+ // Get the IUnregisterSubdevice interface.
+ //
+ ntStatus = UnknownPort->QueryInterface(
+ IID_IUnregisterSubdevice,
+ (PVOID *)&unregisterSubdevice);
+
+ //
+ // Unregister the port object.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = unregisterSubdevice->UnregisterSubdevice(
+ m_pDeviceObject,
+ UnknownPort);
+
+ //
+ // Release the IUnregisterSubdevice interface.
+ //
+ unregisterSubdevice->Release();
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::ConnectTopologies
+(
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+)
+/*++
+
+Routine Description:
+
+ Connects the bridge pins between the wave and mixer topologies.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::ConnectTopologies]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ //
+ // register wave <=> topology connections
+ // This will connect bridge pins of wave and topology
+ // miniports.
+ //
+ for (ULONG i = 0; i < PhysicalConnectionCount && NT_SUCCESS(ntStatus); i++)
+ {
+
+ switch(PhysicalConnections[i].eType)
+ {
+ case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
+ ntStatus =
+ PcRegisterPhysicalConnection
+ (
+ m_pDeviceObject,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology,
+ UnknownWave,
+ PhysicalConnections[i].ulWave
+ );
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("ConnectTopologies: PcRegisterPhysicalConnection(render) failed, 0x%x", ntStatus));
+ }
+ break;
+ case CONNECTIONTYPE_WAVE_OUTPUT:
+ ntStatus =
+ PcRegisterPhysicalConnection
+ (
+ m_pDeviceObject,
+ UnknownWave,
+ PhysicalConnections[i].ulWave,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology
+ );
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("ConnectTopologies: PcRegisterPhysicalConnection(capture) failed, 0x%x", ntStatus));
+ }
+ break;
+ }
+ }
+
+ //
+ // Cleanup in case of error.
+ //
+ if (!NT_SUCCESS(ntStatus))
+ {
+ // disconnect all connections on error, ignore error code because not all
+ // connections may have been made
+ DisconnectTopologies(UnknownTopology, UnknownWave, PhysicalConnections, PhysicalConnectionCount);
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::DisconnectTopologies
+(
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+)
+/*++
+
+Routine Description:
+
+ Disconnects the bridge pins between the wave and mixer topologies.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::DisconnectTopologies]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ NTSTATUS ntStatus2 = STATUS_SUCCESS;
+ PUNREGISTERPHYSICALCONNECTION unregisterPhysicalConnection = NULL;
+
+ //
+ // Get the IUnregisterPhysicalConnection interface
+ //
+ ntStatus = UnknownTopology->QueryInterface(
+ IID_IUnregisterPhysicalConnection,
+ (PVOID *)&unregisterPhysicalConnection);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ for (ULONG i = 0; i < PhysicalConnectionCount; i++)
+ {
+ switch(PhysicalConnections[i].eType)
+ {
+ case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
+ ntStatus =
+ unregisterPhysicalConnection->UnregisterPhysicalConnection(
+ m_pDeviceObject,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology,
+ UnknownWave,
+ PhysicalConnections[i].ulWave
+ );
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("DisconnectTopologies: UnregisterPhysicalConnection(render) failed, 0x%x", ntStatus));
+ }
+ break;
+ case CONNECTIONTYPE_WAVE_OUTPUT:
+ ntStatus =
+ unregisterPhysicalConnection->UnregisterPhysicalConnection(
+ m_pDeviceObject,
+ UnknownWave,
+ PhysicalConnections[i].ulWave,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology
+ );
+ if (!NT_SUCCESS(ntStatus2))
+ {
+ DPF(D_TERSE, ("DisconnectTopologies: UnregisterPhysicalConnection(capture) failed, 0x%x", ntStatus2));
+ }
+ break;
+ }
+
+ // cache and return the first error encountered, as it's likely the most relevent
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ntStatus2;
+ }
+ }
+ }
+
+ //
+ // Release the IUnregisterPhysicalConnection interface.
+ //
+ SAFE_RELEASE(unregisterPhysicalConnection);
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::GetCachedSubdevice
+(
+ _In_ PWSTR Name,
+ _Out_opt_ PUNKNOWN *OutUnknownPort,
+ _Out_opt_ PUNKNOWN *OutUnknownMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::GetCachedSubdevice]"));
+
+ // search list, return interface to device if found, fail if not found
+ PLIST_ENTRY le = NULL;
+ BOOL bFound = FALSE;
+
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bFound; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (0 == wcscmp(Name, pRecord->Name))
+ {
+ if (OutUnknownPort)
+ {
+ *OutUnknownPort = pRecord->PortInterface;
+ (*OutUnknownPort)->AddRef();
+ }
+
+ if (OutUnknownMiniport)
+ {
+ *OutUnknownMiniport = pRecord->MiniportInterface;
+ (*OutUnknownMiniport)->AddRef();
+ }
+
+ bFound = TRUE;
+ }
+ }
+
+ return bFound?STATUS_SUCCESS:STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::CacheSubdevice
+(
+ _In_ PWSTR Name,
+ _In_ PUNKNOWN UnknownPort,
+ _In_ PUNKNOWN UnknownMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::CacheSubdevice]"));
+
+ // add the item with this name/interface to the list
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ MINIPAIR_UNKNOWN *pNewSubdevice = NULL;
+
+ pNewSubdevice = new(POOL_FLAG_NON_PAGED, MINADAPTER_POOLTAG) MINIPAIR_UNKNOWN;
+
+ if (!pNewSubdevice)
+ {
+ DPF(D_TERSE, ("Insufficient memory to cache subdevice"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ memset(pNewSubdevice, 0, sizeof(MINIPAIR_UNKNOWN));
+
+ ntStatus = RtlStringCchCopyW(pNewSubdevice->Name, SIZEOF_ARRAY(pNewSubdevice->Name), Name);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ pNewSubdevice->PortInterface = UnknownPort;
+ pNewSubdevice->PortInterface->AddRef();
+
+ pNewSubdevice->MiniportInterface = UnknownMiniport;
+ pNewSubdevice->MiniportInterface->AddRef();
+
+ // cache the IAdapterPowerManagement interface (if available) from the filter. Some endpoints,
+ // like FM and cellular, have their own power requirements that we must track. If this fails,
+ // it just means this filter doesn't do power management.
+ UnknownMiniport->QueryInterface(IID_IAdapterPowerManagement, (PVOID *)&(pNewSubdevice->PowerInterface));
+
+ InsertTailList(&m_SubdeviceCache, &pNewSubdevice->ListEntry);
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ if (pNewSubdevice)
+ {
+ delete pNewSubdevice;
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::RemoveCachedSubdevice
+(
+ _In_ PWSTR Name
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::RemoveCachedSubdevice]"));
+
+ // search list, remove the entry from the list
+
+ PLIST_ENTRY le = NULL;
+ BOOL bRemoved = FALSE;
+
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bRemoved; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (0 == wcscmp(Name, pRecord->Name))
+ {
+ SAFE_RELEASE(pRecord->PortInterface);
+ SAFE_RELEASE(pRecord->MiniportInterface);
+ SAFE_RELEASE(pRecord->PowerInterface);
+ memset(pRecord->Name, 0, sizeof(pRecord->Name));
+ RemoveEntryList(le);
+ bRemoved = TRUE;
+ delete pRecord;
+ break;
+ }
+ }
+
+ return bRemoved?STATUS_SUCCESS:STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+#pragma code_seg("PAGE")
+VOID
+CAdapterCommon::EmptySubdeviceCache()
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::EmptySubdeviceCache]"));
+
+ while (!IsListEmpty(&m_SubdeviceCache))
+ {
+ PLIST_ENTRY le = RemoveHeadList(&m_SubdeviceCache);
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ SAFE_RELEASE(pRecord->PortInterface);
+ SAFE_RELEASE(pRecord->MiniportInterface);
+ SAFE_RELEASE(pRecord->PowerInterface);
+ memset(pRecord->Name, 0, sizeof(pRecord->Name));
+
+ delete pRecord;
+ }
+}
+
+#pragma code_seg("PAGE")
+VOID
+CAdapterCommon::Cleanup()
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::Cleanup]"));
+ EmptySubdeviceCache();
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::InstallEndpointFilters
+(
+ _In_opt_ PIRP Irp,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext,
+ _Out_opt_ PUNKNOWN * UnknownTopology,
+ _Out_opt_ PUNKNOWN * UnknownWave,
+ _Out_opt_ PUNKNOWN * UnknownMiniportTopology,
+ _Out_opt_ PUNKNOWN * UnknownMiniportWave
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::InstallEndpointFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopology = NULL;
+ PUNKNOWN unknownWave = NULL;
+ BOOL bTopologyCreated = FALSE;
+ BOOL bWaveCreated = FALSE;
+ PUNKNOWN unknownMiniTopo = NULL;
+ PUNKNOWN unknownMiniWave = NULL;
+
+ // Initialize output optional parameters if needed
+ if (UnknownTopology)
+ {
+ *UnknownTopology = NULL;
+ }
+
+ if (UnknownWave)
+ {
+ *UnknownWave = NULL;
+ }
+
+ if (UnknownMiniportTopology)
+ {
+ *UnknownMiniportTopology = NULL;
+ }
+
+ if (UnknownMiniportWave)
+ {
+ *UnknownMiniportWave = NULL;
+ }
+
+ ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopology, &unknownMiniTopo);
+ if (!NT_SUCCESS(ntStatus) || NULL == unknownTopology || NULL == unknownMiniTopo)
+ {
+ bTopologyCreated = TRUE;
+
+ // Install Simple Audio Sample topology miniport for the render endpoint.
+ //
+ ntStatus = InstallSubdevice(Irp,
+ MiniportPair->TopoName, // make sure this name matches with SIMPLEAUDIOSAMPLE.<TopoName>.szPname in the inf's [Strings] section
+ MiniportPair->TemplateTopoName,
+ CLSID_PortTopology,
+ CLSID_PortTopology,
+ MiniportPair->TopoCreateCallback,
+ MiniportPair->TopoInterfacePropertyCount,
+ MiniportPair->TopoInterfaceProperties,
+ DeviceContext,
+ MiniportPair,
+ NULL,
+ IID_IPortTopology,
+ NULL,
+ &unknownTopology,
+ &unknownMiniTopo
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = CacheSubdevice(MiniportPair->TopoName, unknownTopology, unknownMiniTopo);
+ }
+ }
+
+ ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWave, &unknownMiniWave);
+ if (!NT_SUCCESS(ntStatus) || NULL == unknownWave || NULL == unknownMiniWave)
+ {
+ bWaveCreated = TRUE;
+
+ // Install Simple Audio Sample wave miniport for the render endpoint.
+ //
+ ntStatus = InstallSubdevice(Irp,
+ MiniportPair->WaveName, // make sure this name matches with SIMPLEAUDIOSAMPLE.<WaveName>.szPname in the inf's [Strings] section
+ MiniportPair->TemplateWaveName,
+ CLSID_PortWaveRT,
+ CLSID_PortWaveRT,
+ MiniportPair->WaveCreateCallback,
+ MiniportPair->WaveInterfacePropertyCount,
+ MiniportPair->WaveInterfaceProperties,
+ DeviceContext,
+ MiniportPair,
+ NULL,
+ IID_IPortWaveRT,
+ NULL,
+ &unknownWave,
+ &unknownMiniWave
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = CacheSubdevice(MiniportPair->WaveName, unknownWave, unknownMiniWave);
+ }
+ }
+
+ if (unknownTopology && unknownWave)
+ {
+ //
+ // register wave <=> topology connections
+ // This will connect bridge pins of wave and topology
+ // miniports.
+ //
+ ntStatus = ConnectTopologies(
+ unknownTopology,
+ unknownWave,
+ MiniportPair->PhysicalConnections,
+ MiniportPair->PhysicalConnectionCount);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Set output parameters.
+ //
+ if (UnknownTopology != NULL && unknownTopology != NULL)
+ {
+ unknownTopology->AddRef();
+ *UnknownTopology = unknownTopology;
+ }
+
+ if (UnknownWave != NULL && unknownWave != NULL)
+ {
+ unknownWave->AddRef();
+ *UnknownWave = unknownWave;
+ }
+ if (UnknownMiniportTopology != NULL && unknownMiniTopo != NULL)
+ {
+ unknownMiniTopo->AddRef();
+ *UnknownMiniportTopology = unknownMiniTopo;
+ }
+
+ if (UnknownMiniportWave != NULL && unknownMiniWave != NULL)
+ {
+ unknownMiniWave->AddRef();
+ *UnknownMiniportWave = unknownMiniWave;
+ }
+
+ }
+ else
+ {
+ if (bTopologyCreated && unknownTopology != NULL)
+ {
+ UnregisterSubdevice(unknownTopology);
+ RemoveCachedSubdevice(MiniportPair->TopoName);
+ }
+
+ if (bWaveCreated && unknownWave != NULL)
+ {
+ UnregisterSubdevice(unknownWave);
+ RemoveCachedSubdevice(MiniportPair->WaveName);
+ }
+ }
+
+ SAFE_RELEASE(unknownMiniTopo);
+ SAFE_RELEASE(unknownTopology);
+ SAFE_RELEASE(unknownMiniWave);
+ SAFE_RELEASE(unknownWave);
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::RemoveEndpointFilters
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PUNKNOWN UnknownTopology,
+ _In_opt_ PUNKNOWN UnknownWave
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::RemoveEndpointFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (UnknownTopology != NULL && UnknownWave != NULL)
+ {
+ ntStatus = DisconnectTopologies(
+ UnknownTopology,
+ UnknownWave,
+ MiniportPair->PhysicalConnections,
+ MiniportPair->PhysicalConnectionCount);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: DisconnectTopologies failed: 0x%x", ntStatus));
+ }
+ }
+
+
+ RemoveCachedSubdevice(MiniportPair->WaveName);
+
+ ntStatus = UnregisterSubdevice(UnknownWave);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: UnregisterSubdevice(wave) failed: 0x%x", ntStatus));
+ }
+
+ RemoveCachedSubdevice(MiniportPair->TopoName);
+
+ ntStatus = UnregisterSubdevice(UnknownTopology);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: UnregisterSubdevice(topology) failed: 0x%x", ntStatus));
+ }
+
+ //
+ // All Done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::GetFilters
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _Out_opt_ PUNKNOWN * UnknownTopologyPort,
+ _Out_opt_ PUNKNOWN * UnknownTopologyMiniport,
+ _Out_opt_ PUNKNOWN * UnknownWavePort,
+ _Out_opt_ PUNKNOWN * UnknownWaveMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::GetFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopologyPort = NULL;
+ PUNKNOWN unknownTopologyMiniport = NULL;
+ PUNKNOWN unknownWavePort = NULL;
+ PUNKNOWN unknownWaveMiniport = NULL;
+
+ // if the client requested the topology filter, find it and return it
+ if (UnknownTopologyPort != NULL || UnknownTopologyMiniport != NULL)
+ {
+ ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopologyPort, &unknownTopologyMiniport);
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (UnknownTopologyPort)
+ {
+ *UnknownTopologyPort = unknownTopologyPort;
+ }
+
+ if (UnknownTopologyMiniport)
+ {
+ *UnknownTopologyMiniport = unknownTopologyMiniport;
+ }
+ }
+ }
+
+ // if the client requested the wave filter, find it and return it
+ if (NT_SUCCESS(ntStatus) && (UnknownWavePort != NULL || UnknownWaveMiniport != NULL))
+ {
+ ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWavePort, &unknownWaveMiniport);
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (UnknownWavePort)
+ {
+ *UnknownWavePort = unknownWavePort;
+ }
+
+ if (UnknownWaveMiniport)
+ {
+ *UnknownWaveMiniport = unknownWaveMiniport;
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::SetIdlePowerManagement
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_ BOOL bEnabled
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::SetIdlePowerManagement]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ IUnknown *pUnknown = NULL;
+ PPORTCLSPOWER pPortClsPower = NULL;
+ // refcounting disable requests. Each miniport is responsible for calling this in pairs,
+ // disable on the first request to disable, enable on the last request to enable.
+
+ // make sure that we always call SetIdlePowerManagment using the IPortClsPower
+ // from the requesting port, so we don't cache a reference to a port
+ // indefinitely, preventing it from ever unloading.
+ ntStatus = GetFilters(MiniportPair, NULL, NULL, &pUnknown, NULL);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus =
+ pUnknown->QueryInterface
+ (
+ IID_IPortClsPower,
+ (PVOID*) &pPortClsPower
+ );
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (bEnabled)
+ {
+ m_dwIdleRequests--;
+
+ if (0 == m_dwIdleRequests)
+ {
+ pPortClsPower->SetIdlePowerManagement(m_pDeviceObject, TRUE);
+ }
+ }
+ else
+ {
+ if (0 == m_dwIdleRequests)
+ {
+ pPortClsPower->SetIdlePowerManagement(m_pDeviceObject, FALSE);
+ }
+
+ m_dwIdleRequests++;
+ }
+ }
+
+ SAFE_RELEASE(pUnknown);
+ SAFE_RELEASE(pPortClsPower);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+CopyRegistryValues(HANDLE _hSourceKey, HANDLE _hDestinationKey)
+/*++
+
+Routine Description:
+
+ This method copies the registry values in _hSourceKey to _hDestinationKey.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PKEY_VALUE_FULL_INFORMATION kvFullInfo = NULL;
+ ULONG ulFullInfoLength = 0;
+ ULONG ulFullInfoResultLength = 0;
+ PWSTR pwstrKeyValueName = NULL;
+ UNICODE_STRING strKeyValueName;
+ PAGED_CODE();
+ // Allocate the KEY_VALUE_FULL_INFORMATION structure
+ ulFullInfoLength = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_DEVICE_REG_KEY_LENGTH;
+ kvFullInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulFullInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, Exit);
+
+ // Iterate over each value and copy it to the destination
+ for (UINT i = 0; NT_SUCCESS(ntStatus); i++)
+ {
+ // Enumerate the next value
+ ntStatus = ZwEnumerateValueKey(_hSourceKey, i, KeyValueFullInformation, kvFullInfo, ulFullInfoLength, &ulFullInfoResultLength);
+
+ // Jump out of this loop if there are no more values
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, Exit);
+
+ // Handle incorrect buffer size
+ if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW)
+ {
+ // Free and re-allocate the KEY_VALUE_FULL_INFORMATION structure with the correct size
+ ExFreePoolWithTag(kvFullInfo, MINADAPTER_POOLTAG);
+
+ ulFullInfoLength = ulFullInfoResultLength;
+
+ kvFullInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulFullInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Try to enumerate the current value again
+ ntStatus = ZwEnumerateValueKey(_hSourceKey, i, KeyValueFullInformation, kvFullInfo, ulFullInfoLength, &ulFullInfoResultLength);
+
+ // Jump out of this loop if there are no more values
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, Exit);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+ else
+ {
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+
+ // Allocate the key value name string
+ pwstrKeyValueName = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, kvFullInfo->NameLength + sizeof(WCHAR)*2, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Copy the key value name from the full information struct
+ RtlStringCbCopyNW(pwstrKeyValueName, kvFullInfo->NameLength + sizeof(WCHAR)*2, kvFullInfo->Name, kvFullInfo->NameLength);
+
+ // Make sure the string is null terminated
+ pwstrKeyValueName[(kvFullInfo->NameLength) / sizeof(WCHAR)] = 0;
+
+ // Copy the key value name string to a UNICODE string
+ RtlInitUnicodeString(&strKeyValueName, pwstrKeyValueName);
+
+ // Write the key value from the source into the destination
+ ntStatus = ZwSetValueKey(_hDestinationKey, &strKeyValueName, 0, kvFullInfo->Type, (PVOID)((PUCHAR)kvFullInfo + kvFullInfo->DataOffset), kvFullInfo->DataLength);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+
+ loop_exit:
+ // Free the key value name string
+ if (pwstrKeyValueName)
+ {
+ ExFreePoolWithTag(pwstrKeyValueName, MINADAPTER_POOLTAG);
+ }
+
+ // Bail if anything failed
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+Exit:
+ // Free the KEY_VALUE_FULL_INFORMATION structure
+ if (kvFullInfo)
+ {
+ ExFreePoolWithTag(kvFullInfo, MINADAPTER_POOLTAG);
+ }
+
+ return ntStatus;
+}
+
+NTSTATUS
+CopyRegistryKey(HANDLE _hSourceKey, HANDLE _hDestinationKey, BOOL _bOverwrite = FALSE)
+/*++
+
+Routine Description:
+
+ This method recursively copies the registry values in _hSourceKey to _hDestinationKey.
+ Set _bOverwrite to indicate whether the first level values are copied or not.
+ Normal use is to set false for the initial call, and then all sub paths will be copied.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ PKEY_BASIC_INFORMATION kBasicInfo = NULL;
+ ULONG ulBasicInfoLength = 0;
+ ULONG ulBasicInfoResultLength = 0;
+ ULONG ulDisposition = 0;
+ PWSTR pwstrKeyName = NULL;
+ UNICODE_STRING strKeyName;
+ OBJECT_ATTRIBUTES hCurrentSourceKeyAttributes;
+ OBJECT_ATTRIBUTES hNewDestinationKeyAttributes;
+ HANDLE hCurrentSourceKey = NULL;
+ HANDLE hNewDestinationKey = NULL;
+ PAGED_CODE();
+ // Validate parameters
+ IF_TRUE_ACTION_JUMP(_hSourceKey == nullptr, ntStatus = STATUS_INVALID_PARAMETER, Exit);
+ IF_TRUE_ACTION_JUMP(_hDestinationKey == nullptr, ntStatus = STATUS_INVALID_PARAMETER, Exit);
+
+ // Allocate the KEY_BASIC_INFORMATION structure
+ ulBasicInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_DEVICE_REG_KEY_LENGTH;
+ kBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulBasicInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, Exit);
+
+ ntStatus = STATUS_SUCCESS;
+ // Iterate over each key and copy it
+ for (UINT i = 0; NT_SUCCESS(ntStatus); i++)
+ {
+ // Enumerate the next key
+ ntStatus = ZwEnumerateKey(_hSourceKey, i, KeyBasicInformation, kBasicInfo, ulBasicInfoLength, &ulBasicInfoResultLength);
+
+ // Jump out of this loop if there are no more keys
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, copy_values);
+
+ // Handle incorrect buffer size
+ if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW)
+ {
+ // Free and re-allocate the KEY_BASIC_INFORMATION structure with the correct size.
+ ExFreePoolWithTag(kBasicInfo, MINADAPTER_POOLTAG);
+ ulBasicInfoLength = ulBasicInfoResultLength;
+ kBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulBasicInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Try to enumerate the current key again.
+ ntStatus = ZwEnumerateKey(_hSourceKey, i, KeyBasicInformation, kBasicInfo, ulBasicInfoLength, &ulBasicInfoResultLength);
+
+ // Jump out of this loop if there are no more keys
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, copy_values);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+ else
+ {
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+
+ // Allocate the key name string
+ pwstrKeyName = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, kBasicInfo->NameLength + sizeof(WCHAR), MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Copy the key name from the basic information struct
+ RtlStringCbCopyNW(pwstrKeyName, kBasicInfo->NameLength + sizeof(WCHAR), kBasicInfo->Name, kBasicInfo->NameLength);
+
+ // Make sure the string is null terminated
+ pwstrKeyName[(kBasicInfo->NameLength) / sizeof(WCHAR)] = 0;
+
+ // Copy the key name string to a UNICODE string
+ RtlInitUnicodeString(&strKeyName, pwstrKeyName);
+
+ // Initialize attributes to open the currently enumerated source key
+ InitializeObjectAttributes(&hCurrentSourceKeyAttributes, &strKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, _hSourceKey, NULL);
+
+ // Open the currently enumerated source key
+ ntStatus = ZwOpenKey(&hCurrentSourceKey, KEY_READ, &hCurrentSourceKeyAttributes);
+ IF_FAILED_ACTION_JUMP(ntStatus, ZwClose(hCurrentSourceKey), loop_exit);
+
+ // Initialize attributes to create the new destination key
+ InitializeObjectAttributes(&hNewDestinationKeyAttributes, &strKeyName, OBJ_KERNEL_HANDLE, _hDestinationKey, NULL);
+
+ // Create the key at the destination
+ ntStatus = ZwCreateKey(&hNewDestinationKey, KEY_WRITE, &hNewDestinationKeyAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &ulDisposition);
+ IF_FAILED_ACTION_JUMP(ntStatus, ZwClose(hCurrentSourceKey), loop_exit);
+
+ // Now copy the contents of the currently enumerated key to the destination
+ ntStatus = CopyRegistryKey(hCurrentSourceKey, hNewDestinationKey, TRUE);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+
+ loop_exit:
+ // Free the key name string
+ if (pwstrKeyName)
+ {
+ ExFreePoolWithTag(pwstrKeyName, MINADAPTER_POOLTAG);
+ }
+
+ // Close the current source key
+ if (hCurrentSourceKey)
+ {
+ ZwClose(hCurrentSourceKey);
+ }
+
+ // Close the new destination key
+ if (hNewDestinationKey)
+ {
+ ZwClose(hNewDestinationKey);
+ }
+
+ // Bail if anything failed
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+copy_values:
+ // Copy the values
+ if (_bOverwrite)
+ {
+ ntStatus = CopyRegistryValues(_hSourceKey, _hDestinationKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+Exit:
+ // Free the basic information structure
+ if (kBasicInfo)
+ {
+ ExFreePoolWithTag(kBasicInfo, MINADAPTER_POOLTAG);
+ }
+ return ntStatus;
+}
+
+
+NTSTATUS CAdapterCommon::MigrateDeviceInterfaceTemplateParameters
+(
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_opt_ PCWSTR TemplateReferenceString
+)
+/*++
+
+Routine Description:
+
+ This method copies all of the properties from the template interface,
+ which is specified in the inf, to the actual interface being used which
+ may be dynamically generated at run time. This allows for a driver
+ to reuse a single inf entry for multiple audio endpoints. The primary
+ purpose for this is to allow for sideband audio endpoints to dynamically
+ generate the reference string at run time, tied to the peripheral connected,
+ while still having a simple static inf entry for setting up apo's or other
+ parameters.
+
+ For example, if you have an interface in your inf defined with reference string
+ "SpeakerWave". At runtime you could generate "SpeakerWave-1234ABCDE", and specify
+ "SpeakerWave" as the template name. When "SpeakerWave-1234ABCDE" is installed
+ we will copy all of the parameters that were specified in the inf for "SpeakerWave"
+ over to "SpeakerWave-1234ABCDE". You simply need to specify "SpeakerWave" as the
+ "TemplateName" in the ENDPOINT_MINIPAIRS.
+
+ By default, the first level of registry keys are not copied. Only the 2nd level and
+ deeper are copied. This way the friendly name and other PNP properties will not
+ be modified, but the EP and FX properties will be copied.
+
+Return Value:
+
+ NT status code.
+
+--*/
+
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ HANDLE hDeviceInterfaceParametersKey(NULL);
+ HANDLE hTemplateDeviceInterfaceParametersKey(NULL);
+ UNICODE_STRING TemplateSymbolicLinkName;
+ UNICODE_STRING referenceString;
+
+ RtlInitUnicodeString(&TemplateSymbolicLinkName, NULL);
+ RtlInitUnicodeString(&referenceString, TemplateReferenceString);
+
+ //
+ // Register an audio interface if not already present for the template interface, so we can access
+ // the registry path. If it's already registered, this simply returns the symbolic link name.
+ // No need to unregister it (there is no mechanism to), and we'll never make it active.
+ //
+ ntStatus = IoRegisterDeviceInterface(
+ GetPhysicalDeviceObject(),
+ &KSCATEGORY_AUDIO,
+ &referenceString,
+ &TemplateSymbolicLinkName);
+
+ // Open the template device interface's registry key path
+ ntStatus = IoOpenDeviceInterfaceRegistryKey(&TemplateSymbolicLinkName, GENERIC_READ, &hTemplateDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ // Open the new device interface's registry key path that we plan to activate
+ ntStatus = IoOpenDeviceInterfaceRegistryKey(SymbolicLinkName, GENERIC_WRITE, &hDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ // Copy the template device parameters key to the device interface key
+ ntStatus = CopyRegistryKey(hTemplateDeviceInterfaceParametersKey, hDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+Exit:
+ RtlFreeUnicodeString(&TemplateSymbolicLinkName);
+
+ if (hTemplateDeviceInterfaceParametersKey)
+ {
+ ZwClose(hTemplateDeviceInterfaceParametersKey);
+ }
+
+ if (hDeviceInterfaceParametersKey)
+ {
+ ZwClose(hDeviceInterfaceParametersKey);
+ }
+
+ return ntStatus;
+}
diff --git a/audio/simpleaudiosample/Source/Main/mintopo.cpp b/audio/simpleaudiosample/Source/Main/mintopo.cpp
new file mode 100644
index 00000000..6ab1624f
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/mintopo.cpp
@@ -0,0 +1,557 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ mintopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include "endpoints.h"
+#include "minwavert.h"
+#include "mintopo.h"
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CreateMiniportTopologySimpleAudioSample
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+)
+/*++
+
+Routine Description:
+
+ Creates a new topology miniport.
+
+Arguments:
+
+ Unknown -
+
+ RefclsId -
+
+ PoolType -
+
+ UnknownOuter -
+
+ DeviceContext -
+
+ MiniportPair -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(UnknownAdapter);
+
+ ASSERT(Unknown);
+ ASSERT(MiniportPair);
+
+ CMiniportTopology *obj =
+ new (PoolFlags, MINWAVERT_POOLTAG)
+ CMiniportTopology( UnknownOuter,
+ MiniportPair->TopoDescriptor,
+ MiniportPair->DeviceMaxChannels,
+ MiniportPair->DeviceType,
+ DeviceContext );
+ if (NULL == obj)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ obj->AddRef();
+ *Unknown = reinterpret_cast<IUnknown*>(obj);
+
+ return STATUS_SUCCESS;
+} // CreateMiniportTopologySimpleAudioSample
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportTopology::~CMiniportTopology
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Topology miniport destructor
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportTopology::~CMiniportTopology]"));
+} // ~CMiniportTopology
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopology::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest quality
+ intersection of two data ranges.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
+ submitted by client in the data range intersection property
+ request.
+
+ MyDataRange - Pin's data range to be compared with client's data range.
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter.
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned.
+
+ ResultantFormatLength - Actual length of the resultant format that is placed
+ at ResultantFormat. This should be less than or equal
+ to OutputBufferLength.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ return
+ CMiniportTopologySimpleAudioSample::DataRangeIntersection
+ (
+ PinId,
+ ClientDataRange,
+ MyDataRange,
+ OutputBufferLength,
+ ResultantFormat,
+ ResultantFormatLength
+ );
+} // DataRangeIntersection
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP
+CMiniportTopology::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure. This is the placeholder for the FromNode or ToNode fields in
+ connections which describe connections to the filter's pins.
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ return CMiniportTopologySimpleAudioSample::GetDescription(OutFilterDescriptor);
+} // GetDescription
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP
+CMiniportTopology::Init
+(
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PRESOURCELIST ResourceList,
+ _In_ PPORTTOPOLOGY Port_
+)
+/*++
+
+Routine Description:
+
+ The Init function initializes the miniport. Callers of this function
+ should run at IRQL PASSIVE_LEVEL
+
+Arguments:
+
+ UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
+
+ ResourceList - Pointer to the resource list to be supplied to the miniport
+ during initialization. The port driver is free to examine the
+ contents of the ResourceList. The port driver will not be
+ modify the ResourceList contents.
+
+ Port - Pointer to the topology port object that is linked with this miniport.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ResourceList);
+
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMiniportTopology::Init]"));
+
+ NTSTATUS ntStatus;
+
+ ntStatus =
+ CMiniportTopologySimpleAudioSample::Init
+ (
+ UnknownAdapter,
+ Port_
+ );
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Init: CMiniportTopologySimpleAudioSample::Init failed, 0x%x", ntStatus)),
+ Done);
+
+Done:
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP
+CMiniportTopology::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface for MiniportTopology
+
+Arguments:
+
+ Interface - GUID of the interface
+
+ Object - interface object to be returned.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology))
+ {
+ *Object = PVOID(PMINIPORTTOPOLOGY(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ // We reference the interface for the caller.
+ PUNKNOWN(*Object)->AddRef();
+ return(STATUS_SUCCESS);
+ }
+
+ return(STATUS_INVALID_PARAMETER);
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopology::PropertyHandlerJackDescription
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
+
+Arguments:
+
+ PropertyRequest -
+ cJackDescriptions - # of elements in the jack descriptions array.
+ JackDescriptions - Array of jack descriptions pointers.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopology::PropertyHandlerJackDescription2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions,
+ _In_ DWORD JackCapabilities
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
+
+Arguments:
+
+ PropertyRequest -
+ cJackDescriptions - # of elements in the jack descriptions array.
+ JackDescriptions - Array of jack descriptions pointers.
+ JackCapabilities - Jack capabilities flags.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription2]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
+
+ //
+ // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
+ // the jack is currently active, streaming, idle, or hardware not ready.
+ //
+ pDesc->DeviceStateInfo = 0;
+
+ //
+ // From MSDN:
+ // "If an audio device lacks jack presence detection, the IsConnected member of
+ // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
+ // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
+ // a client application can call IKsJackDescription2::GetJackDescription2 to read
+ // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
+ // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
+ // does in fact support jack presence detection. In that case, the return value of
+ // the IsConnected member can be interpreted to accurately reflect the insertion status
+ // of the jack."
+ //
+ // Bit definitions:
+ // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
+ // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
+ //
+ pDesc->JackCapabilities = JackCapabilities;
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_Topology
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_Topology]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ return
+ ((PCMiniportTopology)
+ (PropertyRequest->MajorTarget))->PropertyHandlerGeneric
+ (
+ PropertyRequest
+ );
+} // PropertyHandler_Topology
diff --git a/audio/simpleaudiosample/Source/Main/minwavert.cpp b/audio/simpleaudiosample/Source/Main/minwavert.cpp
new file mode 100644
index 00000000..1d92073d
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavert.cpp
@@ -0,0 +1,1683 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavert.cpp
+
+Abstract:
+
+ Implementation of wavert miniport.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include <limits.h>
+#include "endpoints.h"
+#include "minwavert.h"
+#include "minwavertstream.h"
+#include "micarraywavtable.h"
+
+#define EFFECTS_LIST_COUNT 2
+
+//=============================================================================
+// CMiniportWaveRT
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CreateMiniportWaveRTSimpleAudioSample
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+)
+/*++
+
+Routine Description:
+
+ Create the wavert miniport.
+
+Arguments:
+
+ Unknown -
+
+ RefClsId -
+
+ UnknownOuter -
+
+ PoolType -
+
+ UnkownAdapter -
+
+ DeviceContext -
+
+ MiniportPair -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(UnknownOuter);
+
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+ ASSERT(MiniportPair);
+
+ CMiniportWaveRT *obj = new (PoolFlags, MINWAVERT_POOLTAG) CMiniportWaveRT
+ (
+ UnknownAdapter,
+ MiniportPair,
+ DeviceContext
+ );
+ if (NULL == obj)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ obj->AddRef();
+ *Unknown = reinterpret_cast<IUnknown*>(obj);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportWaveRT::~CMiniportWaveRT
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for wavert miniport
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::~CMiniportWaveRT]"));
+
+ if (m_pDeviceFormat)
+ {
+ ExFreePoolWithTag( m_pDeviceFormat, MINWAVERT_POOLTAG );
+ m_pDeviceFormat = NULL;
+ }
+
+ if (m_pMixFormat)
+ {
+ ExFreePoolWithTag( m_pMixFormat, MINWAVERT_POOLTAG );
+ m_pMixFormat = NULL;
+ }
+
+ if (m_pbMuted)
+ {
+ ExFreePoolWithTag(m_pbMuted, MINWAVERT_POOLTAG);
+ m_pbMuted = NULL;
+ }
+
+ if (m_plVolumeLevel)
+ {
+ ExFreePoolWithTag(m_plVolumeLevel, MINWAVERT_POOLTAG);
+ m_plVolumeLevel = NULL;
+ }
+
+ if (m_pDrmPort)
+ {
+ m_pDrmPort->Release();
+ m_pDrmPort = NULL;
+ }
+
+ if (m_pPortEvents)
+ {
+ m_pPortEvents->Release();
+ m_pPortEvents = NULL;
+ }
+
+ if (m_SystemStreams)
+ {
+ ExFreePoolWithTag( m_SystemStreams, MINWAVERT_POOLTAG );
+ m_SystemStreams = NULL;
+ }
+
+} // ~CMiniportWaveRT
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest quality
+ intersection of two data ranges.
+
+ This sample just sets the ResultantFormat to be the only supported
+ format for the MicArray endpoint.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data
+ range submitted by client in the data range intersection
+ property request.
+
+ MyDataRange - Pin's data range to be compared with client's data
+ range. In this case we actually ignore our own data
+ range, because we know that we only support one range.
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter.
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned.
+
+ ResultantFormatLength - Actual length of the resultant format placed in
+ ResultantFormat. This should be less than or equal
+ to OutputBufferLength.
+
+ Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PinId);
+
+ ULONG requiredSize;
+
+ PAGED_CODE();
+
+ if (!IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ //If called for the mic array pin, set ResultantFormat to be the endpoint's only supported format.
+ //Otherwise, allow the class handler to set ResultantFormat.
+ if ((this->m_DeviceType) == eMicArrayDevice1)
+ {
+ requiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
+
+ //
+ // Validate return buffer size, if the request is only for the
+ // size of the resultant structure, return it now before
+ // returning other types of errors.
+ //
+ if (!OutputBufferLength)
+ {
+ *ResultantFormatLength = requiredSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ else if (OutputBufferLength < requiredSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //Set ResultantFormat to be the only supported format for the MicArray endpoint.
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE resultantFormat;
+ resultantFormat = (PKSDATAFORMAT_WAVEFORMATEXTENSIBLE)ResultantFormat;
+ *resultantFormat = *MicArrayPinSupportedDeviceFormats;
+ *ResultantFormatLength = requiredSize;
+
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ requiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
+
+ //
+ // Validate return buffer size, if the request is only for the
+ // size of the resultant structure, return it now before
+ // returning other types of errors.
+ //
+ if (!OutputBufferLength)
+ {
+ *ResultantFormatLength = requiredSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ else if (OutputBufferLength < requiredSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Verify channel count is supported. This routine assumes a separate data
+ // range for each supported channel count.
+ if (((PKSDATARANGE_AUDIO)MyDataRange)->MaximumChannels != ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels)
+ {
+ return STATUS_NO_MATCH;
+ }
+
+ //
+ // Ok, let the class handler do the rest.
+ //
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+} // DataRangeIntersection
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure.
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ *OutFilterDescriptor = &m_FilterDesc;
+
+ return STATUS_SUCCESS;
+} // GetDescription
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::Init
+(
+ _In_ PUNKNOWN UnknownAdapter_,
+ _In_ PRESOURCELIST ResourceList_,
+ _In_ PPORTWAVERT Port_
+)
+/*++
+
+Routine Description:
+
+ The Init function initializes the miniport. Callers of this function
+ should run at IRQL PASSIVE_LEVEL
+
+Arguments:
+
+ UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
+
+ ResourceList - Pointer to the resource list to be supplied to the miniport
+ during initialization. The port driver is free to examine the
+ contents of the ResourceList. The port driver will not be
+ modify the ResourceList contents.
+
+ Port - Pointer to the topology port object that is linked with this miniport.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(UnknownAdapter_);
+ UNREFERENCED_PARAMETER(ResourceList_);
+ UNREFERENCED_PARAMETER(Port_);
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter_);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMiniportWaveRT::Init]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ size_t size;
+
+ //
+ // Init class data members
+ //
+ m_ulSystemAllocated = 0;
+ m_SystemStreams = NULL;
+ m_bGfxEnabled = FALSE;
+ m_pMixFormat = NULL;
+ m_pDeviceFormat = NULL;
+ m_ulMixDrmContentId = 0;
+ m_pbMuted = NULL;
+ m_plVolumeLevel = NULL;
+ RtlZeroMemory(&m_MixDrmRights, sizeof(m_MixDrmRights));
+
+ //
+ // Init the audio-engine used by the render devices.
+ //
+ if (IsRenderDevice())
+ {
+ if (m_ulMaxSystemStreams == 0 )
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // System streams.
+ size = sizeof(PCMiniportWaveRTStream) * m_ulMaxSystemStreams;
+ m_SystemStreams = (PCMiniportWaveRTStream *)ExAllocatePool2(POOL_FLAG_NON_PAGED, size, MINWAVERT_POOLTAG);
+ if (m_SystemStreams == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For DRM support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IDrmPort2, (PVOID *)&m_pDrmPort)))
+ {
+ m_pDrmPort = NULL;
+ }
+ }
+
+ //
+ // For KS event support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IPortEvents, (PVOID *)&m_pPortEvents)))
+ {
+ m_pPortEvents = NULL;
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::NewStream
+(
+ _Out_ PMINIPORTWAVERTSTREAM * OutStream,
+ _In_ PPORTWAVERTSTREAM OuterUnknown,
+ _In_ ULONG Pin,
+ _In_ BOOLEAN Capture,
+ _In_ PKSDATAFORMAT DataFormat
+)
+/*++
+
+Routine Description:
+
+ The NewStream function creates a new instance of a logical stream
+ associated with a specified physical channel. Callers of NewStream should
+ run at IRQL PASSIVE_LEVEL.
+
+Arguments:
+
+ OutStream -
+
+ OuterUnknown -
+
+ Pin -
+
+ Capture -
+
+ DataFormat -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutStream);
+ ASSERT(DataFormat);
+
+ DPF_ENTER(("[CMiniportWaveRT::NewStream]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PCMiniportWaveRTStream stream = NULL;
+ GUID signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
+
+ *OutStream = NULL;
+
+ //
+ // If the data format attributes were specified, extract them.
+ //
+ if ( DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES )
+ {
+ // The attributes are aligned (QWORD alignment) after the data format
+ PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
+ ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode);
+ }
+
+ // Check if we have enough streams.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ValidateStreamCreate(Pin, Capture);
+ }
+
+ // Determine if the format is valid.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
+ }
+
+ // Instantiate a stream. Stream must be in
+ // NonPagedPool(Nx) because of file saving.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ stream = new (POOL_FLAG_NON_PAGED, MINWAVERT_POOLTAG)
+ CMiniportWaveRTStream(NULL);
+
+ if (stream)
+ {
+ stream->AddRef();
+
+ ntStatus =
+ stream->Init
+ (
+ this,
+ OuterUnknown,
+ Pin,
+ Capture,
+ DataFormat,
+ signalProcessingMode
+ );
+ }
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ *OutStream = PMINIPORTWAVERTSTREAM(stream);
+ (*OutStream)->AddRef();
+
+ // The stream has references now for the caller. The caller expects these
+ // references to be there.
+ }
+
+ // This is our private reference to the stream. The caller has
+ // its own, so we can release in any case.
+ //
+ if (stream)
+ {
+ stream->Release();
+ }
+
+ return ntStatus;
+} // NewStream
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface
+
+Arguments:
+
+ Interface - GUID
+
+ Object - interface pointer to be returned.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PMINIPORTWAVERT(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRT))
+ {
+ *Object = PVOID(PMINIPORTWAVERT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportAudioSignalProcessing))
+ {
+ *Object = PVOID(PMINIPORTAudioSignalProcessing(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ // We reference the interface for the caller.
+
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceDescription(_Out_ PDEVICE_DESCRIPTION DmaDeviceDescription)
+{
+ PAGED_CODE ();
+
+ ASSERT (DmaDeviceDescription);
+
+ DPF_ENTER(("[CMiniportWaveRT::GetDeviceDescription]"));
+
+ RtlZeroMemory (DmaDeviceDescription, sizeof (DEVICE_DESCRIPTION));
+
+ //
+ // Init device description. This sample is using the same info for all m_DeviceType(s).
+ //
+
+ DmaDeviceDescription->Master = TRUE;
+ DmaDeviceDescription->ScatterGather = TRUE;
+ DmaDeviceDescription->Dma32BitAddresses = TRUE;
+ DmaDeviceDescription->InterfaceType = PCIBus;
+ DmaDeviceDescription->MaximumLength = 0xFFFFFFFF;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::GetModes
+(
+ _In_ ULONG Pin,
+ _Out_writes_opt_(*NumSignalProcessingModes) GUID* SignalProcessingModes,
+ _Inout_ ULONG* NumSignalProcessingModes
+)
+/*
+
+1. If Pin is not a valid pin number,
+ return STATUS_INVALID_PARAMETER.
+
+2. If Pin is a valid pin number and it supports n modes (n>0),
+ init out-parameters and return STATUS_SUCCESS.
+
+3. Else this pin doesn't support any mode,
+ return STATUS_NOT_SUPPORTED.
+ example: bridge pins or another mode-not-aware pins.
+
+*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::GetModes]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+ ULONG numModes = 0;
+ MODE_AND_DEFAULT_FORMAT *modeInfo = NULL;
+
+ if (Pin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // This method is valid only on the following pins:
+ // render is offload capable:
+ // sink (#0) and offload (#1) pins.
+ // render is NOT offload capable:
+ // sink (#0) pin.
+ // capture device:
+ // source (#1) pin.
+ //
+ numModes = GetPinSupportedDeviceModes(Pin, &modeInfo);
+ if (numModes == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // If caller requests the modes, verify sufficient buffer size then return the modes
+ if (SignalProcessingModes != NULL)
+ {
+ if (*NumSignalProcessingModes < numModes)
+ {
+ *NumSignalProcessingModes = numModes;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ for (ULONG i=0; i<numModes; ++i)
+ {
+ SignalProcessingModes[i] = modeInfo[i].Mode;
+ }
+ }
+
+ ASSERT(numModes > 0);
+ *NumSignalProcessingModes = numModes;
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::ValidateStreamCreate
+(
+ _In_ ULONG _Pin,
+ _In_ BOOLEAN _Capture
+)
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::ValidateStreamCreate]"));
+
+ NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
+
+ if (_Capture)
+ {
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+
+ }
+ else
+ {
+
+ if (IsSystemRenderPin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::AcquireFormatsAndModesLock()
+{
+ KeAcquireSpinLock(&m_DeviceFormatsAndModesLock, &m_DeviceFormatsAndModesIrql);
+}
+
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::ReleaseFormatsAndModesLock()
+{
+ KeReleaseSpinLock(&m_DeviceFormatsAndModesLock, m_DeviceFormatsAndModesIrql);
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceFormats
+//
+// Return supported formats for a given pin.
+//
+// Return value
+// The number of KSDATAFORMAT_WAVEFORMATEXTENSIBLE items.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceFormats(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) KSDATAFORMAT_WAVEFORMATEXTENSIBLE **ppFormats)
+{
+ PPIN_DEVICE_FORMATS_AND_MODES pDeviceFormatsAndModes = NULL;
+
+ AcquireFormatsAndModesLock();
+
+ pDeviceFormatsAndModes = m_DeviceFormatsAndModes;
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormats != NULL);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormatsCount > 0);
+
+ if (ppFormats != NULL)
+ {
+ *ppFormats = pDeviceFormatsAndModes[PinId].WaveFormats;
+ }
+
+ ReleaseFormatsAndModesLock();
+
+ return pDeviceFormatsAndModes[PinId].WaveFormatsCount;
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceModes
+//
+// Return mode information for a given pin.
+//
+// Return value
+// The number of MODE_AND_DEFAULT_FORMAT items or 0 if none.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceModes(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) _On_failure_(_Deref_post_null_) MODE_AND_DEFAULT_FORMAT **ppModes)
+{
+ PMODE_AND_DEFAULT_FORMAT modes;
+ ULONG numModes;
+
+ AcquireFormatsAndModesLock();
+
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT((m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount == 0) == (m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat == NULL));
+
+ modes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat;
+ numModes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount;
+
+ if (ppModes != NULL)
+ {
+ if (numModes > 0)
+ {
+ *ppModes = modes;
+ }
+ else
+ {
+ // ensure that the returned pointer is NULL
+ // in the event of failure (SAL annotation above
+ // indicates that it must be NULL, and OACR sees a possibility
+ // that it might not be).
+ *ppModes = NULL;
+ }
+ }
+
+ ReleaseFormatsAndModesLock();
+ return numModes;
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemCapturePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemCapturePin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemRenderPin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemRenderPin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsBridgePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == BridgePin);
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::StreamCreated
+(
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+)
+{
+ PAGED_CODE();
+
+ PCMiniportWaveRTStream * streams = NULL;
+ ULONG count = 0;
+
+ DPF_ENTER(("[CMiniportWaveRT::StreamCreated]"));
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+
+ }
+
+ //
+ // Cache this stream's ptr.
+ //
+ if (streams != NULL)
+ {
+ ULONG i = 0;
+ for (; i<count; ++i)
+ {
+ if (streams[i] == NULL)
+ {
+ streams[i] = _Stream;
+ break;
+ }
+ }
+ ASSERT(i != count);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::StreamClosed
+(
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+)
+{
+ PAGED_CODE();
+
+ bool updateDrmRights = false;
+ PCMiniportWaveRTStream * streams = NULL;
+ ULONG count = 0;
+
+ DPF_ENTER(("[CMiniportWaveRT::StreamClosed]"));
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+ updateDrmRights = true;
+
+ }
+
+ //
+ // Cleanup.
+ //
+ if (streams != NULL)
+ {
+ ULONG i = 0;
+ for (; i<count; ++i)
+ {
+ if (streams[i] == _Stream)
+ {
+ streams[i] = NULL;
+ break;
+ }
+ }
+ ASSERT(i != count);
+ }
+
+ //
+ // Update mixed drm rights.
+ //
+ if (updateDrmRights)
+ {
+ UpdateDrmRights();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::GetAttributesFromAttributeList
+(
+ _In_ const KSMULTIPLE_ITEM *_pAttributes,
+ _In_ size_t _Size,
+ _Out_ GUID* _pSignalProcessingMode
+)
+/*++
+
+Routine Description:
+
+ Processes attributes list and return known attributes.
+
+Arguments:
+
+ _pAttributes - pointer to KSMULTIPLE_ITEM at head of an attributes list.
+
+ _Size - count of bytes in the buffer pointed to by _pAttributes. The routine
+ verifies sufficient buffer size while processing the attributes.
+
+ _pSignalProcessingMode - returns the signal processing mode extracted from
+ the attribute list, or AUDIO_SIGNALPROCESSINGMODE_DEFAULT if the attribute
+ is not present in the list.
+
+Return Value:
+
+ NT status code.
+
+Remarks
+
+ This function is currently written for a single supported attribute
+ (KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE). As additional attributes are defined in the future,
+ this function should be rewritten to be data driven through tables, etc.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::GetAttributesFromAttributeList]"));
+
+ size_t cbRemaining = _Size;
+
+ *_pSignalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
+
+ if (cbRemaining < sizeof(KSMULTIPLE_ITEM))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ cbRemaining -= sizeof(KSMULTIPLE_ITEM);
+
+ //
+ // Extract attributes.
+ //
+ PKSATTRIBUTE attributeHeader = (PKSATTRIBUTE)(_pAttributes + 1);
+
+ for (ULONG i = 0; i < _pAttributes->Count; i++)
+ {
+ if (cbRemaining < sizeof(KSATTRIBUTE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (attributeHeader->Attribute == KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE)
+ {
+ KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE* signalProcessingModeAttribute;
+
+ if (cbRemaining < sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (attributeHeader->Size != sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ signalProcessingModeAttribute = (KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE*)attributeHeader;
+
+ // Return mode to caller.
+ *_pSignalProcessingMode = signalProcessingModeAttribute->SignalProcessingMode;
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Adjust pointer and buffer size to next attribute (QWORD aligned)
+ ULONG cbAttribute = ((attributeHeader->Size + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
+
+ attributeHeader = (PKSATTRIBUTE) (((PBYTE)attributeHeader) + cbAttribute);
+ cbRemaining -= cbAttribute;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::IsFormatSupported
+(
+ _In_ ULONG _ulPin,
+ _In_ BOOLEAN _bCapture,
+ _In_ PKSDATAFORMAT _pDataFormat
+)
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::IsFormatSupported]"));
+
+ NTSTATUS ntStatus = STATUS_NO_MATCH;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pPinFormats = NULL;
+ ULONG cPinFormats = 0;
+
+ UNREFERENCED_PARAMETER(_bCapture);
+
+ if (_ulPin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ cPinFormats = GetPinSupportedDeviceFormats(_ulPin, &pPinFormats);
+
+ for (UINT iFormat = 0; iFormat < cPinFormats; iFormat++)
+ {
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pFormat = &pPinFormats[iFormat];
+ // KSDATAFORMAT VALIDATION
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.MajorFormat, _pDataFormat->MajorFormat)) { continue; }
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.SubFormat, _pDataFormat->SubFormat)) { continue; }
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.Specifier, _pDataFormat->Specifier)) { continue; }
+ if (pFormat->DataFormat.FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEX)) { continue; }
+
+ // WAVEFORMATEX VALIDATION
+ PWAVEFORMATEX pWaveFormat = reinterpret_cast<PWAVEFORMATEX>(_pDataFormat + 1);
+
+ if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+ {
+ if (pWaveFormat->wFormatTag != EXTRACT_WAVEFORMATEX_ID(&(pFormat->WaveFormatExt.SubFormat))) { continue; }
+ }
+ if (pWaveFormat->nChannels != pFormat->WaveFormatExt.Format.nChannels) { continue; }
+ if (pWaveFormat->nSamplesPerSec != pFormat->WaveFormatExt.Format.nSamplesPerSec) { continue; }
+ if (pWaveFormat->nBlockAlign != pFormat->WaveFormatExt.Format.nBlockAlign) { continue; }
+ if (pWaveFormat->wBitsPerSample != pFormat->WaveFormatExt.Format.wBitsPerSample) { continue; }
+ if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+ {
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+
+ // WAVEFORMATEXTENSIBLE VALIDATION
+ if (pWaveFormat->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { continue; }
+
+ PWAVEFORMATEXTENSIBLE pWaveFormatExt = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pWaveFormat);
+ if (pWaveFormatExt->Samples.wValidBitsPerSample != pFormat->WaveFormatExt.Samples.wValidBitsPerSample) { continue; }
+ if (pWaveFormatExt->dwChannelMask != pFormat->WaveFormatExt.dwChannelMask) { continue; }
+ if (!IsEqualGUIDAligned(pWaveFormatExt->SubFormat, pFormat->WaveFormatExt.SubFormat)) { continue; }
+
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::PropertyHandlerProposedFormat
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ PKSP_PIN kspPin = NULL;
+ PKSDATAFORMAT pKsFormat = NULL;
+ ULONG cbMinSize = 0;
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat]"));
+
+ // All properties handled by this handler require at least a KSP_PIN descriptor.
+
+ // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
+ if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Extract property descriptor from property request instance data
+ kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);
+
+ //
+ // This method is valid only on streaming pins.
+ //
+ if (IsSystemRenderPin(kspPin->PinId) ||
+ IsSystemCapturePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (IsBridgePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+
+ cbMinSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
+
+ // Handle KSPROPERTY_TYPE_BASICSUPPORT query
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ULONG flags = PropertyRequest->PropertyItem->Flags;
+
+ return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
+ }
+
+ // Verify value size
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbMinSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ if (PropertyRequest->ValueSize < cbMinSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ pKsFormat = (PKSDATAFORMAT)PropertyRequest->Value;
+ ntStatus = IsFormatSupported(kspPin->PinId, IsSystemCapturePin(kspPin->PinId) || FALSE, pKsFormat);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerProposedFormat
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT_EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ CMiniportWaveRT* miniport = reinterpret_cast<CMiniportWaveRT*>(EventRequest->MajorTarget);
+ return miniport->EventHandler_PinCapsChange(EventRequest);
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT::EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ if (*EventRequest->EventItem->Set != KSEVENTSETID_PinCapsChange)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (EventRequest->Verb)
+ {
+ // Do we support event handling?!?
+ case PCEVENT_VERB_SUPPORT:
+ break;
+ // We should add the event now!
+ case PCEVENT_VERB_ADD:
+ // If we have the interface and EventEntry is defined ...
+ if (EventRequest->EventEntry)
+ {
+ switch (EventRequest->EventItem->Id)
+ {
+ // Add pincaps format change event to support the force sample rate feature
+ case KSEVENT_PINCAPS_FORMATCHANGE:
+ m_pPortEvents->AddEventToEventList(EventRequest->EventEntry);
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ else
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ break;
+
+ case PCEVENT_VERB_REMOVE:
+ // We cannot remove the event but we can stop generating the
+ // events. However, it also doesn't hurt to always generate them ...
+ break;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::PropertyHandlerProposedFormat2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ PKSP_PIN kspPin = NULL;
+ ULONG cbMinSize = 0;
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+ ULONG numModes = 0;
+ MODE_AND_DEFAULT_FORMAT *modeInfo = NULL;
+ MODE_AND_DEFAULT_FORMAT *modeTemp = NULL;
+ PKSMULTIPLE_ITEM pKsItemsHeader = NULL;
+ PKSMULTIPLE_ITEM pKsItemsHeaderOut = NULL;
+ size_t cbItemsList = 0;
+ GUID signalProcessingMode = {0};
+ BOOLEAN bFound = FALSE;
+ ULONG i;
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat2]"));
+
+ // All properties handled by this handler require at least a KSP_PIN descriptor.
+
+ // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
+ if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Extract property descriptor from property request instance data
+ kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);
+
+ if (kspPin->PinId >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // This property is supported only on some streaming pins.
+ //
+ numModes = GetPinSupportedDeviceModes(kspPin->PinId, &modeInfo);
+
+ ASSERT((modeInfo != NULL && numModes > 0) || (modeInfo == NULL && numModes == 0));
+
+ if (modeInfo == NULL)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Even for pins that support modes, the pin might not support proposed formats
+ //
+ bFound = FALSE;
+ for (i=0, modeTemp=modeInfo; i<numModes; ++i, ++modeTemp)
+ {
+ if (modeTemp->DefaultFormat != NULL)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The property is generally supported on this pin. Handle basic support request.
+ //
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->Flags, VT_ILLEGAL);
+ }
+
+ //
+ // Get the mode if specified.
+ //
+ pKsItemsHeader = (PKSMULTIPLE_ITEM)(kspPin + 1);
+ cbItemsList = (((PBYTE)PropertyRequest->Instance) + PropertyRequest->InstanceSize) - (PBYTE)pKsItemsHeader;
+
+ ntStatus = GetAttributesFromAttributeList(pKsItemsHeader, cbItemsList, &signalProcessingMode);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+
+ //
+ // Get the info associated with this mode.
+ //
+ bFound = FALSE;
+ for (i=0; i<numModes; ++i, ++modeInfo)
+ {
+ if (modeInfo->Mode == signalProcessingMode)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ // Either the mode isn't supported, or the driver doesn't support a
+ // proprosed format for this specific mode.
+ if (!bFound || modeInfo->DefaultFormat == NULL)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Compute output data buffer.
+ //
+ cbMinSize = modeInfo->DefaultFormat->FormatSize;
+ cbMinSize = (cbMinSize + 7) & ~7;
+
+ pKsItemsHeaderOut = (PKSMULTIPLE_ITEM)((PBYTE)PropertyRequest->Value + cbMinSize);
+
+ if (cbItemsList > MAXULONG)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Total # of bytes.
+ ntStatus = RtlULongAdd(cbMinSize, (ULONG)cbItemsList, &cbMinSize);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Property not supported.
+ if (cbMinSize == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Verify value size
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbMinSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ if (PropertyRequest->ValueSize < cbMinSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Only GET is supported for this property
+ if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) == 0)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ // Copy the proposed default format.
+ RtlCopyMemory(PropertyRequest->Value, modeInfo->DefaultFormat, modeInfo->DefaultFormat->FormatSize);
+
+ // Copy back the attribute list.
+ ASSERT(cbItemsList > 0);
+ ((KSDATAFORMAT*)PropertyRequest->Value)->Flags = KSDATAFORMAT_ATTRIBUTES;
+ RtlCopyMemory(pKsItemsHeaderOut, pKsItemsHeader, cbItemsList);
+
+ PropertyRequest->ValueSize = cbMinSize;
+
+ return STATUS_SUCCESS;
+} // PropertyHandlerProposedFormat
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::UpdateDrmRights
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Updates the mixed DrmRights. This is done by creating an array of existing
+ content ids and asking DrmPort to create a new contend id with a mixed
+ DrmRights structure.
+ The new DrmRights structure should be enforced, if everything goes well.
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::UpdateDrmRights]"));
+
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ ULONG ulMixDrmContentId = 0;
+ BOOL fCreatedContentId = FALSE;
+ DRMRIGHTS MixDrmRights = {FALSE, 0, FALSE};
+ ULONG ulContentIndex = 0;
+ ULONG* ulContentIds = NULL;
+
+ //
+ // This function only runs if IID_DrmPort is implemented in Wave port.
+ //
+ if (!m_pDrmPort)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ulContentIds = new (POOL_FLAG_NON_PAGED, MINWAVERT_POOLTAG) ULONG[m_ulMaxSystemStreams + m_ulMaxOffloadStreams];
+ if (!ulContentIds)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Create an array of all StreamIds.
+ //
+ for (ULONG i = 0; i < m_ulMaxSystemStreams; i++)
+ {
+ if (m_SystemStreams[i])
+ {
+ ulContentIds[ulContentIndex] = m_SystemStreams[i]->m_ulContentId;
+ ulContentIndex++;
+ }
+ }
+
+ //
+ // Create the new contentId.
+ //
+ if (ulContentIndex)
+ {
+ ntStatus =
+ m_pDrmPort->CreateContentMixed
+ (
+ ulContentIds,
+ ulContentIndex,
+ &ulMixDrmContentId
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ fCreatedContentId = TRUE;
+ ntStatus =
+ m_pDrmPort->GetContentRights
+ (
+ ulMixDrmContentId,
+ &MixDrmRights
+ );
+ }
+ }
+
+ //
+ // If successful, destroy the old ContentId and update global rights.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_pDrmPort->DestroyContent(m_ulMixDrmContentId);
+ m_ulMixDrmContentId = ulMixDrmContentId;
+ RtlCopyMemory(&m_MixDrmRights, &MixDrmRights, sizeof(m_MixDrmRights));
+
+ //
+ // At this point the driver should enforce the new DrmRights.
+ // The sample driver handles DrmRights per stream basis, and
+ // stops writing the stream to disk, if CopyProtect = TRUE.
+ //
+ }
+
+ //
+ // Cleanup if failed
+ //
+ if (!NT_SUCCESS(ntStatus) && fCreatedContentId)
+ {
+ m_pDrmPort->DestroyContent(ulMixDrmContentId);
+ }
+
+ //
+ // Free allocated memory.
+ //
+ ASSERT(ulContentIds);
+ delete [] ulContentIds;
+ ulContentIds = NULL;
+
+ return ntStatus;
+} // UpdateDrmRights
+
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_WaveFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects general property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ CMiniportWaveRT* pWaveHelper = reinterpret_cast<CMiniportWaveRT*>(PropertyRequest->MajorTarget);
+
+ if (pWaveHelper == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ pWaveHelper->AddRef();
+
+
+ if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Pin))
+ {
+ switch (PropertyRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
+ ntStatus = pWaveHelper->PropertyHandlerProposedFormat(PropertyRequest);
+ break;
+
+ case KSPROPERTY_PIN_PROPOSEDATAFORMAT2:
+ ntStatus = pWaveHelper->PropertyHandlerProposedFormat2(PropertyRequest);
+ break;
+
+ default:
+ DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
+ }
+ }
+
+ pWaveHelper->Release();
+
+ return ntStatus;
+} // PropertyHandler_WaveFilter
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_GenericPin
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ CMiniportWaveRT* pWave = NULL;
+ CMiniportWaveRTStream * pStream = NULL;
+
+ PAGED_CODE();
+
+ if (PropertyRequest->MajorTarget == NULL ||
+ PropertyRequest->MinorTarget == NULL)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Get a ref to the miniport.
+ //
+ pWave = MajorTarget_to_Obj(PropertyRequest->MajorTarget);
+ pWave->AddRef();
+
+ //
+ // Get a ref to the stream.
+ //
+ pStream = MinorTarget_to_Obj(PropertyRequest->MinorTarget);
+ pStream->AddRef();
+
+exit:
+
+ SAFE_RELEASE(pStream);
+ SAFE_RELEASE(pWave);
+
+ return ntStatus;
+}
+
+#pragma code_seg()
+
diff --git a/audio/simpleaudiosample/Source/Main/minwavert.h b/audio/simpleaudiosample/Source/Main/minwavert.h
new file mode 100644
index 00000000..4c0ccd83
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavert.h
@@ -0,0 +1,302 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavert.h
+
+Abstract:
+
+ Definition of wavert miniport class.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
+#define _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
+
+//=============================================================================
+// Referenced Forward
+//=============================================================================
+class CMiniportWaveRTStream;
+typedef CMiniportWaveRTStream *PCMiniportWaveRTStream;
+
+//=============================================================================
+// Classes
+//=============================================================================
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportWaveRT
+//
+class CMiniportWaveRT :
+ public IMiniportWaveRT,
+ public IMiniportAudioSignalProcessing,
+ public CUnknown
+{
+private:
+ ULONG m_ulSystemAllocated;
+
+ ULONG m_ulMaxSystemStreams;
+ ULONG m_ulMaxOffloadStreams;
+ ULONG m_ulMaxLoopbackStreams;
+
+ // weak ref of running streams.
+ PCMiniportWaveRTStream * m_SystemStreams;
+
+ BOOL m_bGfxEnabled;
+ PBOOL m_pbMuted;
+ PLONG m_plVolumeLevel;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE m_pMixFormat;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE m_pDeviceFormat;
+ PCFILTER_DESCRIPTOR m_FilterDesc;
+ PIN_DEVICE_FORMATS_AND_MODES * m_DeviceFormatsAndModes;
+ KSPIN_LOCK m_DeviceFormatsAndModesLock; // To serialize access.
+ KIRQL m_DeviceFormatsAndModesIrql;
+ ULONG m_DeviceFormatsAndModesCount;
+ USHORT m_DeviceMaxChannels;
+ PDRMPORT m_pDrmPort;
+ DRMRIGHTS m_MixDrmRights;
+ ULONG m_ulMixDrmContentId;
+
+ union {
+ PVOID m_DeviceContext;
+ };
+
+protected:
+ PADAPTERCOMMON m_pAdapterCommon;
+ ULONG m_DeviceFlags;
+ eDeviceType m_DeviceType;
+ PPORTEVENTS m_pPortEvents;
+ PENDPOINT_MINIPAIR m_pMiniportPair;
+
+public:
+ NTSTATUS EventHandler_PinCapsChange
+ (
+ _In_ PPCEVENT_REQUEST EventRequest
+ );
+
+ NTSTATUS ValidateStreamCreate
+ (
+ _In_ ULONG _Pin,
+ _In_ BOOLEAN _Capture
+ );
+
+ NTSTATUS StreamCreated
+ (
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+ );
+
+ NTSTATUS StreamClosed
+ (
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+ );
+
+ NTSTATUS IsFormatSupported
+ (
+ _In_ ULONG _ulPin,
+ _In_ BOOLEAN _bCapture,
+ _In_ PKSDATAFORMAT _pDataFormat
+ );
+
+ static NTSTATUS GetAttributesFromAttributeList
+ (
+ _In_ const KSMULTIPLE_ITEM *_pAttributes,
+ _In_ size_t _Size,
+ _Out_ GUID* _pSignalProcessingMode
+ );
+
+protected:
+ NTSTATUS UpdateDrmRights
+ (
+ void
+ );
+
+public:
+ DECLARE_STD_UNKNOWN();
+
+#pragma code_seg("PAGE")
+ CMiniportWaveRT(
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext
+ )
+ :CUnknown(0),
+ m_ulMaxSystemStreams(0),
+ m_DeviceType(MiniportPair->DeviceType),
+ m_DeviceContext(DeviceContext),
+ m_DeviceMaxChannels(MiniportPair->DeviceMaxChannels),
+ m_DeviceFormatsAndModes(MiniportPair->PinDeviceFormatsAndModes),
+ m_DeviceFormatsAndModesCount(MiniportPair->PinDeviceFormatsAndModesCount),
+ m_DeviceFlags(MiniportPair->DeviceFlags),
+ m_pMiniportPair(MiniportPair)
+ {
+ PAGED_CODE();
+
+ m_pAdapterCommon = (PADAPTERCOMMON)UnknownAdapter; // weak ref.
+
+ if (MiniportPair->WaveDescriptor)
+ {
+ RtlCopyMemory(&m_FilterDesc, MiniportPair->WaveDescriptor, sizeof(m_FilterDesc));
+
+ //
+ // Get the max # of pin instances.
+ //
+ if (IsRenderDevice())
+ {
+ if (m_FilterDesc.PinCount > KSPIN_WAVE_RENDER2_SOURCE)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER2_SINK_SYSTEM].MaxFilterInstanceCount;
+ m_ulMaxLoopbackStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER2_SINK_LOOPBACK].MaxFilterInstanceCount;
+ }
+ else if(m_FilterDesc.PinCount > KSPIN_WAVE_RENDER3_SOURCE)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER3_SINK_SYSTEM].MaxFilterInstanceCount;
+ }
+ }
+ else
+ {
+ //
+ // capture bridge pin comes first in the enumeration
+ //
+ if (m_FilterDesc.PinCount > KSPIN_WAVEIN_HOST)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVEIN_HOST].MaxFilterInstanceCount;
+ }
+ }
+ }
+
+ KeInitializeSpinLock(&m_DeviceFormatsAndModesLock);
+ m_DeviceFormatsAndModesIrql = PASSIVE_LEVEL;
+ }
+
+#pragma code_seg()
+
+ ~CMiniportWaveRT();
+
+ IMP_IMiniportWaveRT;
+ IMP_IMiniportAudioSignalProcessing;
+
+ // Friends
+ friend class CMiniportWaveRTStream;
+ friend class CMiniportTopologySimpleAudioSample;
+
+ friend NTSTATUS PropertyHandler_WaveFilter
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+public:
+public:
+ NTSTATUS PropertyHandlerProposedFormat
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerProposedFormat2
+
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ PADAPTERCOMMON GetAdapterCommObj()
+ {
+ return m_pAdapterCommon;
+ };
+#pragma code_seg()
+
+ //---------------------------------------------------------------------------------------------------------
+ // volume
+ //---------------------------------------------------------------------------------------------------------
+ NTSTATUS GetVolumeChannelCount
+ (
+ _Out_ UINT32* pulChannelCount
+ );
+
+ NTSTATUS GetVolumeSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ LONG* _pVolume
+ );
+
+ NTSTATUS SetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ LONG _Volume
+ );
+
+ //-----------------------------------------------------------------------------
+ // mute
+ //-----------------------------------------------------------------------------
+ NTSTATUS GetMuteChannelCount
+ (
+ _Out_ UINT32* pulChannelCount
+ );
+
+ NTSTATUS GetMuteSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ BOOL* _pbMute
+ );
+
+ NTSTATUS SetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ BOOL _bMute
+ );
+
+private:
+ _IRQL_raises_(DISPATCH_LEVEL)
+ _Acquires_lock_(m_DeviceFormatsAndModesLock)
+ _Requires_lock_not_held_(m_DeviceFormatsAndModesLock)
+ _IRQL_saves_global_(SpinLock, m_DeviceFormatsAndModesIrql)
+ VOID AcquireFormatsAndModesLock();
+
+ _Releases_lock_(m_DeviceFormatsAndModesLock)
+ _Requires_lock_held_(m_DeviceFormatsAndModesLock)
+ _IRQL_restores_global_(SpinLock, m_DeviceFormatsAndModesIrql)
+ VOID ReleaseFormatsAndModesLock();
+
+ _Post_satisfies_(return > 0)
+ ULONG GetPinSupportedDeviceFormats(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) KSDATAFORMAT_WAVEFORMATEXTENSIBLE **ppFormats);
+
+ _Success_(return != 0)
+ ULONG GetPinSupportedDeviceModes(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) _On_failure_(_Deref_post_null_) MODE_AND_DEFAULT_FORMAT **ppModes);
+
+#pragma code_seg()
+
+protected:
+#pragma code_seg()
+ BOOL IsRenderDevice()
+ {
+ return m_DeviceType == eSpeakerDevice ? TRUE : FALSE;
+ }
+
+ BOOL IsSystemRenderPin(ULONG nPinId);
+
+ BOOL IsSystemCapturePin(ULONG nPinId);
+
+ BOOL IsBridgePin(ULONG nPinId);
+
+ // These three pins are the pins used by the audio engine for host, loopback, and offload.
+ ULONG GetSystemPinId()
+ {
+ ASSERT(IsRenderDevice());
+ return KSPIN_WAVE_RENDER2_SINK_SYSTEM;
+ }
+};
+
+typedef CMiniportWaveRT *PCMiniportWaveRT;
+
+#endif // _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
diff --git a/audio/simpleaudiosample/Source/Main/minwavertstream.cpp b/audio/simpleaudiosample/Source/Main/minwavertstream.cpp
new file mode 100644
index 00000000..27289a0e
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavertstream.cpp
@@ -0,0 +1,1644 @@
+#include "definitions.h"
+#include <limits.h>
+#include <ks.h>
+#include "endpoints.h"
+#include "minwavert.h"
+#include "minwavertstream.h"
+#define MINWAVERTSTREAM_POOLTAG 'SRWM'
+
+#pragma warning (disable : 4127)
+
+//=============================================================================
+// CMiniportWaveRTStream
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportWaveRTStream::~CMiniportWaveRTStream
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for wavertstream
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ if (NULL != m_pMiniport)
+ {
+
+ if (m_bUnregisterStream)
+ {
+ m_pMiniport->StreamClosed(m_ulPin, this);
+ m_bUnregisterStream = FALSE;
+ }
+
+ m_pMiniport->Release();
+ m_pMiniport = NULL;
+ }
+
+ if (m_pDpc)
+ {
+ ExFreePoolWithTag( m_pDpc, MINWAVERTSTREAM_POOLTAG );
+ m_pDpc = NULL;
+ }
+
+ if (m_pTimer)
+ {
+ ExFreePoolWithTag( m_pTimer, MINWAVERTSTREAM_POOLTAG );
+ m_pTimer = NULL;
+ }
+
+ if (m_pbMuted)
+ {
+ ExFreePoolWithTag( m_pbMuted, MINWAVERTSTREAM_POOLTAG );
+ m_pbMuted = NULL;
+ }
+
+ if (m_plVolumeLevel)
+ {
+ ExFreePoolWithTag( m_plVolumeLevel, MINWAVERTSTREAM_POOLTAG );
+ m_plVolumeLevel = NULL;
+ }
+
+ if (m_plPeakMeter)
+ {
+ ExFreePoolWithTag( m_plPeakMeter, MINWAVERTSTREAM_POOLTAG );
+ m_plPeakMeter = NULL;
+ }
+
+ if (m_pWfExt)
+ {
+ ExFreePoolWithTag( m_pWfExt, MINWAVERTSTREAM_POOLTAG );
+ m_pWfExt = NULL;
+ }
+ if (m_pNotificationTimer)
+ {
+ ExDeleteTimer
+ (
+ m_pNotificationTimer,
+ TRUE, // Cancel the timer if it is currently set.
+ TRUE, // Wait for the timer to finish expiring and for any callback to a ExTimerCallback routine to finish.
+ NULL
+ );
+ }
+
+ // Since we just cancelled the notification timer, wait for all queued
+ // DPCs to complete before we free the notification DPC.
+ //
+ KeFlushQueuedDpcs();
+
+ DPF_ENTER(("[CMiniportWaveRTStream::~CMiniportWaveRTStream]"));
+} // ~CMiniportWaveRTStream
+
+//=============================================================================
+#pragma code_seg("PAGE")
+
+NTSTATUS CMiniportWaveRTStream::ReadRegistrySettings()
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+ UNICODE_STRING parametersPath;
+
+ RTL_QUERY_REGISTRY_TABLE paramTable[] = {
+ // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneFrequency", &m_ulHostCaptureToneFrequency, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_ulHostCaptureToneFrequency, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneAmplitude", &m_dwHostCaptureToneAmplitude, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneAmplitude, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneDCOffset", &m_dwHostCaptureToneDCOffset, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneDCOffset, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneInitialPhase", &m_dwHostCaptureToneInitialPhase, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneInitialPhase, sizeof(DWORD) },
+ { NULL, 0, NULL, NULL, 0, NULL, 0 }
+ };
+
+ RtlInitUnicodeString(&parametersPath, NULL);
+
+ // The sizeof(WCHAR) is added to the maximum length, for allowing a space for null termination of the string.
+ parametersPath.MaximumLength =
+ g_RegistryPath.Length + sizeof(L"\\Parameters") + sizeof(WCHAR);
+
+ parametersPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, parametersPath.MaximumLength, MINWAVERT_POOLTAG);
+ if (parametersPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&parametersPath, g_RegistryPath.Buffer);
+ RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
+
+ ntStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ &paramTable[0],
+ NULL,
+ NULL
+ );
+
+ ExFreePool(parametersPath.Buffer);
+
+ return ntStatus;
+}
+
+NTSTATUS
+CMiniportWaveRTStream::Init
+(
+ _In_ PCMiniportWaveRT Miniport_,
+ _In_ PPORTWAVERTSTREAM PortStream_,
+ _In_ ULONG Pin_,
+ _In_ BOOLEAN Capture_,
+ _In_ PKSDATAFORMAT DataFormat_,
+ _In_ GUID SignalProcessingMode
+)
+/*++
+
+Routine Description:
+
+ Initializes the stream object.
+
+Arguments:
+
+ Miniport_ -
+
+ Pin_ -
+
+ DataFormat -
+
+ SignalProcessingMode - The driver uses the signalProcessingMode to configure
+ driver and/or hardware specific signal processing to be applied to this new
+ stream.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ PWAVEFORMATEX pWfEx = NULL;
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_pMiniport = NULL;
+ m_ulPin = 0;
+ m_bUnregisterStream = FALSE;
+ m_bCapture = FALSE;
+ m_ulDmaBufferSize = 0;
+ m_pDmaBuffer = NULL;
+ m_ulNotificationsPerBuffer = 0;
+ m_KsState = KSSTATE_STOP;
+ m_pTimer = NULL;
+ m_pDpc = NULL;
+ m_llPacketCounter = 0;
+ m_ullPlayPosition = 0;
+ m_ullWritePosition = 0;
+ m_ullDmaTimeStamp = 0;
+ m_hnsElapsedTimeCarryForward = 0;
+ m_ullLastDPCTimeStamp = 0;
+ m_hnsDPCTimeCarryForward = 0;
+ m_ulDmaMovementRate = 0;
+ m_byteDisplacementCarryForward = 0;
+ m_bLfxEnabled = FALSE;
+ m_pbMuted = NULL;
+ m_plVolumeLevel = NULL;
+ m_plPeakMeter = NULL;
+ m_pWfExt = NULL;
+ m_ullLinearPosition = 0;
+ m_ullPresentationPosition = 0;
+ m_ulContentId = 0;
+ m_ulCurrentWritePosition = 0;
+ m_ulLastOsReadPacket = ULONG_MAX;
+ m_ulLastOsWritePacket = ULONG_MAX;
+ m_IsCurrentWritePositionUpdated = 0;
+ m_SignalProcessingMode = SignalProcessingMode;
+ m_bEoSReceived = FALSE;
+ m_bLastBufferRendered = FALSE;
+
+ m_ulHostCaptureToneFrequency = IsEqualGUID(SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) ? 1000 : 2000;
+ m_dwHostCaptureToneAmplitude = 50;
+ m_dwHostCaptureToneDCOffset = 0;
+ m_dwHostCaptureToneInitialPhase = 0;
+
+ m_pPortStream = PortStream_;
+ InitializeListHead(&m_NotificationList);
+ m_ulNotificationIntervalMs = 0;
+
+ // Initialize the spinlock to synchronize position updates
+ KeInitializeSpinLock(&m_PositionSpinLock);
+
+ m_pNotificationTimer = ExAllocateTimer(
+ TimerNotifyRT,
+ this,
+ EX_TIMER_HIGH_RESOLUTION
+ );
+ if (!m_pNotificationTimer)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ pWfEx = GetWaveFormatEx(DataFormat_);
+ if (NULL == pWfEx)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ m_pMiniport = reinterpret_cast<CMiniportWaveRT*>(Miniport_);
+ if (m_pMiniport == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ m_pMiniport->AddRef();
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ m_ulPin = Pin_;
+ m_bCapture = Capture_;
+ m_ulDmaMovementRate = pWfEx->nAvgBytesPerSec;
+
+ m_pDpc = (PRKDPC)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(KDPC), MINWAVERTSTREAM_POOLTAG);
+ if (!m_pDpc)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_pWfExt = (PWAVEFORMATEXTENSIBLE)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(WAVEFORMATEX) + pWfEx->cbSize, MINWAVERTSTREAM_POOLTAG);
+ if (m_pWfExt == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory(m_pWfExt, pWfEx, sizeof(WAVEFORMATEX) + pWfEx->cbSize);
+
+ m_pbMuted = (PBOOL)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(BOOL), MINWAVERTSTREAM_POOLTAG);
+ if (m_pbMuted == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_plVolumeLevel = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG);
+ if (m_plVolumeLevel == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_plPeakMeter = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG);
+ if (m_plPeakMeter == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (m_bCapture)
+ {
+ ReadRegistrySettings();
+ DWORD toneFrequency = 0;
+ DWORD toneAmplitude = 0;
+ DWORD toneDCOffset = 0;
+ DWORD toneInitialPhase = 0;
+
+ double toneAmplitudeDouble = 0;
+ double toneDCOffsetDouble = 0;
+ double toneInitialPhaseDouble = 0;
+
+ toneFrequency = m_ulHostCaptureToneFrequency;
+ toneAmplitude = m_dwHostCaptureToneAmplitude;
+ toneDCOffset = m_dwHostCaptureToneDCOffset;
+ toneInitialPhase = m_dwHostCaptureToneInitialPhase;
+
+ if (labs(toneAmplitude) > 100)
+ {
+ toneAmplitude = toneAmplitude > 0 ? 100 : -100;
+ }
+
+ if (labs(toneDCOffset) > 100)
+ {
+ toneDCOffset = toneDCOffset > 0 ? 100 : -100;
+ }
+
+ DWORD abssum = labs(toneAmplitude) + labs(toneDCOffset);
+
+ if (abssum > 100)
+ {
+ toneAmplitudeDouble = ((double)toneAmplitude) / abssum;
+ toneDCOffsetDouble = ((double)toneDCOffset) / abssum;
+ }
+ else
+ {
+ toneAmplitudeDouble = ((double)toneAmplitude) / 100.0;
+ toneDCOffsetDouble = ((double)toneDCOffset) / 100.0;
+ }
+
+ if (labs(toneInitialPhase) > 31416)
+ {
+ toneInitialPhase = toneInitialPhase > 0 ? 31416 : -31416;
+ }
+
+ toneInitialPhaseDouble = (double)toneInitialPhase / 10000;
+
+ ntStatus = m_ToneGenerator.Init(toneFrequency, toneAmplitudeDouble, toneDCOffsetDouble, toneInitialPhaseDouble, m_pWfExt);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+ else if (!g_DoNotCreateDataFiles)
+ {
+ //
+ // Create an output file for the render data.
+ //
+ DPF(D_TERSE, ("SaveData %p", &m_SaveData));
+ ntStatus = m_SaveData.SetDataFormat(DataFormat_);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = m_SaveData.Initialize();
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ //
+ // Register this stream.
+ //
+ ntStatus = m_pMiniport->StreamCreated(m_ulPin, this);
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_bUnregisterStream = TRUE;
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRTStream::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface
+
+Arguments:
+
+ Interface - GUID
+
+ Object - interface pointer to be returned
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PMINIPORTWAVERTSTREAM(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStream))
+ {
+ *Object = PVOID(PMINIPORTWAVERTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStreamNotification))
+ {
+ *Object = PVOID(PMINIPORTWAVERTSTREAMNOTIFICATION(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTInputStream) && (this->m_bCapture))
+ {
+ // This interface is supported only on capture streams
+ *Object = PVOID(PMINIPORTWAVERTINPUTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTOutputStream))
+ {
+ // This interface is supported only on host render streams
+ *Object = PVOID(PMINIPORTWAVERTOUTPUTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IDrmAudioStream))
+ {
+ *Object = (PVOID)(IDrmAudioStream*)this;
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::AllocateBufferWithNotification
+(
+ _In_ ULONG NotificationCount_,
+ _In_ ULONG RequestedSize_,
+ _Out_ PMDL *AudioBufferMdl_,
+ _Out_ ULONG *ActualSize_,
+ _Out_ ULONG *OffsetFromFirstPage_,
+ _Out_ MEMORY_CACHING_TYPE *CacheType_
+)
+{
+ PAGED_CODE();
+
+ ULONG ulBufferDurationMs = 0;
+
+ if ( (0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign) )
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if ((NotificationCount_ == 0) || (RequestedSize_ % NotificationCount_ != 0))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign);
+
+ if (!m_bCapture && (!g_DoNotCreateDataFiles))
+ {
+ NTSTATUS ntStatus;
+
+ // Simple Audio Sample uses following buffer to hold data before writing to a file.
+ // Allocating larger buffer will reduce File I/O operations.
+ ntStatus = m_SaveData.SetMaxWriteSize(RequestedSize_ * 4);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ PHYSICAL_ADDRESS highAddress;
+ highAddress.HighPart = 0;
+ highAddress.LowPart = MAXULONG;
+
+ PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl (highAddress, RequestedSize_);
+
+ if (NULL == pBufferMdl)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // From MSDN:
+ // "Since the Windows audio stack does not support a mechanism to express memory access
+ // alignment requirements for buffers, audio drivers must select a caching type for mapped
+ // memory buffers that does not impose platform-specific alignment requirements. In other
+ // words, the caching type used by the audio driver for mapped memory buffers, must not make
+ // assumptions about the memory alignment requirements for any specific platform.
+ //
+ // This method maps the physical memory pages in the MDL into kernel-mode virtual memory.
+ // Typically, the miniport driver calls this method if it requires software access to the
+ // scatter-gather list for an audio buffer. In this case, the storage for the scatter-gather
+ // list must have been allocated by the IPortWaveRTStream::AllocatePagesForMdl or
+ // IPortWaveRTStream::AllocateContiguousPagesForMdl method.
+ //
+ // A WaveRT miniport driver should not require software access to the audio buffer itself."
+ //
+ m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached);
+ m_ulNotificationsPerBuffer = NotificationCount_;
+ m_ulDmaBufferSize = RequestedSize_;
+ ulBufferDurationMs = (RequestedSize_ * 1000) / m_ulDmaMovementRate;
+ m_ulNotificationIntervalMs = ulBufferDurationMs / NotificationCount_;
+
+ *AudioBufferMdl_ = pBufferMdl;
+ *ActualSize_ = RequestedSize_;
+ *OffsetFromFirstPage_ = 0;
+ *CacheType_ = MmCached;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::FreeBufferWithNotification
+(
+ _In_ PMDL Mdl_,
+ _In_ ULONG Size_
+)
+{
+ UNREFERENCED_PARAMETER(Size_);
+
+ PAGED_CODE();
+
+ if (Mdl_ != NULL)
+ {
+ if (m_pDmaBuffer != NULL)
+ {
+ m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_);
+ m_pDmaBuffer = NULL;
+ }
+
+ m_pPortStream->FreePagesFromMdl(Mdl_);
+ }
+
+ m_ulDmaBufferSize = 0;
+ m_ulNotificationsPerBuffer = 0;
+
+ return;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::RegisterNotificationEvent
+(
+ _In_ PKEVENT NotificationEvent_
+)
+{
+ UNREFERENCED_PARAMETER(NotificationEvent_);
+
+ PAGED_CODE();
+
+ NotificationListEntry *nleNew = (NotificationListEntry*)ExAllocatePool2(
+ POOL_FLAG_NON_PAGED,
+ sizeof(NotificationListEntry),
+ MINWAVERTSTREAM_POOLTAG);
+ if (NULL == nleNew)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ nleNew->NotificationEvent = NotificationEvent_;
+
+ // Fail if the notification event already exists in our list.
+ if (!IsListEmpty(&m_NotificationList))
+ {
+ PLIST_ENTRY leCurrent = m_NotificationList.Flink;
+ while (leCurrent != &m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ if (nleCurrent->NotificationEvent == NotificationEvent_)
+ {
+ ExFreePoolWithTag( nleNew, MINWAVERTSTREAM_POOLTAG );
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ InsertTailList(&m_NotificationList, &(nleNew->ListEntry));
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::UnregisterNotificationEvent
+(
+ _In_ PKEVENT NotificationEvent_
+)
+{
+ UNREFERENCED_PARAMETER(NotificationEvent_);
+
+ PAGED_CODE();
+
+ if (!IsListEmpty(&m_NotificationList))
+ {
+ PLIST_ENTRY leCurrent = m_NotificationList.Flink;
+ while (leCurrent != &m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ if (nleCurrent->NotificationEvent == NotificationEvent_)
+ {
+ RemoveEntryList( leCurrent );
+ ExFreePoolWithTag( nleCurrent, MINWAVERTSTREAM_POOLTAG );
+ return STATUS_SUCCESS;
+ }
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ return STATUS_NOT_FOUND;
+}
+
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::GetClockRegister
+(
+ _Out_ PKSRTAUDIO_HWREGISTER Register_
+)
+{
+ UNREFERENCED_PARAMETER(Register_);
+
+ PAGED_CODE();
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::GetPositionRegister
+(
+ _Out_ PKSRTAUDIO_HWREGISTER Register_
+)
+{
+ UNREFERENCED_PARAMETER(Register_);
+
+ PAGED_CODE();
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::GetHWLatency
+(
+ _Out_ PKSRTAUDIO_HWLATENCY Latency_
+)
+{
+ PAGED_CODE();
+
+ ASSERT(Latency_);
+
+ Latency_->ChipsetDelay = 0;
+ Latency_->CodecDelay = 0;
+ Latency_->FifoSize = 0;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::FreeAudioBuffer
+(
+_In_opt_ PMDL Mdl_,
+_In_ ULONG Size_
+)
+{
+ UNREFERENCED_PARAMETER(Size_);
+
+ PAGED_CODE();
+
+ if (Mdl_ != NULL)
+ {
+ if (m_pDmaBuffer != NULL)
+ {
+ m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_);
+ m_pDmaBuffer = NULL;
+ }
+
+ m_pPortStream->FreePagesFromMdl(Mdl_);
+ }
+
+ m_ulDmaBufferSize = 0;
+ m_ulNotificationsPerBuffer = 0;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::AllocateAudioBuffer
+(
+_In_ ULONG RequestedSize_,
+_Out_ PMDL *AudioBufferMdl_,
+_Out_ ULONG *ActualSize_,
+_Out_ ULONG *OffsetFromFirstPage_,
+_Out_ MEMORY_CACHING_TYPE *CacheType_
+)
+{
+ PAGED_CODE();
+
+ if ((0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign);
+
+ PHYSICAL_ADDRESS highAddress;
+ highAddress.HighPart = 0;
+ highAddress.LowPart = MAXULONG;
+
+ PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl(highAddress, RequestedSize_);
+
+ if (NULL == pBufferMdl)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // From MSDN:
+ // "Since the Windows audio stack does not support a mechanism to express memory access
+ // alignment requirements for buffers, audio drivers must select a caching type for mapped
+ // memory buffers that does not impose platform-specific alignment requirements. In other
+ // words, the caching type used by the audio driver for mapped memory buffers, must not make
+ // assumptions about the memory alignment requirements for any specific platform.
+ //
+ // This method maps the physical memory pages in the MDL into kernel-mode virtual memory.
+ // Typically, the miniport driver calls this method if it requires software access to the
+ // scatter-gather list for an audio buffer. In this case, the storage for the scatter-gather
+ // list must have been allocated by the IPortWaveRTStream::AllocatePagesForMdl or
+ // IPortWaveRTStream::AllocateContiguousPagesForMdl method.
+ //
+ // A WaveRT miniport driver should not require software access to the audio buffer itself."
+ //
+ m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached);
+
+ m_ulDmaBufferSize = RequestedSize_;
+ m_ulNotificationsPerBuffer = 0;
+
+ *AudioBufferMdl_ = pBufferMdl;
+ *ActualSize_ = RequestedSize_;
+ *OffsetFromFirstPage_ = 0;
+ *CacheType_ = MmCached;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::GetPosition
+(
+ _Out_ KSAUDIO_POSITION *Position_
+)
+{
+ NTSTATUS ntStatus;
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ if (m_KsState == KSSTATE_RUN)
+ {
+ //
+ // Get the current time and update position.
+ //
+ LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL);
+ UpdatePosition(ilQPC);
+ }
+
+ Position_->PlayOffset = m_ullPlayPosition;
+ Position_->WriteOffset = m_ullWritePosition;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+//=============================================================================
+// CMiniportWaveRTStream::GetReadPacket
+//
+// Returns information about the next packet for the OS to read.
+//
+// Return value
+//
+// Returns STATUS_DEVICE_NOT_READY if no new packets are available.
+//
+// IRQL - PASSIVE_LEVEL
+//
+// Remarks
+// Although called at passive level, this routine is non-paged code because
+// it is called in the streaming path where page faults should be avoided.
+//
+// ISSUE-2014/10/4 Will this work correctly across pause/play?
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetReadPacket
+(
+ _Out_ ULONG* PacketNumber,
+ _Out_ DWORD* Flags,
+ _Out_ ULONG64* PerformanceCounterValue,
+ _Out_ BOOL* MoreData
+)
+{
+ ULONG availablePacketNumber;
+ ULONG droppedPackets;
+
+ // The call must be from event driven mode
+ if (m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ *Flags = 0;
+
+ if (m_KsState < KSSTATE_PAUSE)
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ LONGLONG packetCounter = m_llPacketCounter;
+ ULONGLONG ullLinearPosition = m_ullLinearPosition;
+ ULONGLONG hnsElapsedTimeCarryForward = m_hnsElapsedTimeCarryForward;
+ ULONGLONG ullDmaTimeStamp = m_ullDmaTimeStamp;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // The 0-based number of the last completed packet
+ // FUTURE-2014/10/27 Update to allow different numbers of packets per WaveRT buffer
+ availablePacketNumber = LODWORD(packetCounter - 1); // Note this might be ULONG_MAX if called during the first packet
+
+ // If no new packets are available...
+ if (availablePacketNumber == m_ulLastOsReadPacket)
+ {
+ return STATUS_DEVICE_NOT_READY;
+ }
+
+ // If more than one packet has transferred since the last packet read by
+ // the OS, then those were dropped. That is, a glitch occurred.
+ droppedPackets = availablePacketNumber - m_ulLastOsReadPacket - 1;
+ if (droppedPackets > 0)
+ {
+ // Trace a glitch
+ }
+
+ // Return next packet number to be read
+ *PacketNumber = availablePacketNumber;
+
+ // Compute and return timestamp corresponding to the end of the available packet. In a real hardware
+ // driver, the timestamp would be computed in a driver and hardware specific manner. In this sample
+ // driver, it is extrapolated from the sample driver's internal simulated position correlation
+ // [m_ullLinearPosition @ m_ullDmaTimeStamp] and the sample's internal 64-bit packet counter, subtracting
+ // 1 from the packet counter to compute the time at the start of that last completed packet.
+ ULONGLONG linearPositionOfAvailablePacket = packetCounter * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ // Need to divide by (1000 * 10000 because m_ulDmaMovementRate is average bytes per sec
+ ULONGLONG carryForwardBytes = (hnsElapsedTimeCarryForward * m_ulDmaMovementRate) / 10000000;
+ ULONGLONG deltaLinearPosition = ullLinearPosition + carryForwardBytes - linearPositionOfAvailablePacket;
+ ULONGLONG deltaTimeInHns = deltaLinearPosition * 10000000 / m_ulDmaMovementRate;
+ ULONGLONG timeOfAvailablePacketInHns = ullDmaTimeStamp - deltaTimeInHns;
+ ULONGLONG timeOfAvailablePacketInQpc = timeOfAvailablePacketInHns * m_ullPerformanceCounterFrequency.QuadPart / 10000000;
+
+ *PerformanceCounterValue = timeOfAvailablePacketInQpc;
+
+ // No flags are defined yet
+ *Flags = 0;
+
+ // This sample does not internally buffer data so there is never more data
+ // than revealed by the results from this routine.
+ *MoreData = FALSE;
+
+ // Update the last packet read by the OS
+ m_ulLastOsReadPacket = availablePacketNumber;
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::SetWritePacket
+(
+ _In_ ULONG PacketNumber,
+ _In_ DWORD Flags,
+ _In_ ULONG EosPacketLength
+)
+{
+ UNREFERENCED_PARAMETER(EosPacketLength);
+ NTSTATUS ntStatus;
+
+ // The call must be from event driven mode
+ if (m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ ULONG oldLastOsWritePacket = m_ulLastOsWritePacket;
+
+ // This function should not be called once EoS has been set.
+ if (m_bEoSReceived)
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ // 1-based count of completed packets, 0-based packet number of current packet
+ LONGLONG currentPacket = m_llPacketCounter;
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // If not running, the current packet hasn't actually started transfering so OS should be writing
+ // to the current packet. If running, then the current packing is already transfering to hardware
+ // so the OS should write the packet after the current packet.
+ ULONG expectedPacket = LODWORD(currentPacket);
+ if (m_KsState == KSSTATE_RUN)
+ {
+ expectedPacket++;
+ }
+
+ // Check if OS PacketNumber is behind or too far ahead of current packet
+ LONG deltaFromExpectedPacket = PacketNumber - expectedPacket; // Modulo arithemetic
+ if (deltaFromExpectedPacket < 0)
+ {
+ return STATUS_DATA_LATE_ERROR;
+ }
+ else if (deltaFromExpectedPacket > 0)
+ {
+ return STATUS_DATA_OVERRUN;
+ }
+
+ ULONG packetSize = (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ ULONG packetIndex = PacketNumber % m_ulNotificationsPerBuffer;
+ ULONG ulCurrentWritePosition = packetIndex * packetSize;
+
+ // Check if EOS flag was passed
+ if (Flags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ m_ulLastOsWritePacket = PacketNumber;
+
+ // This function sets the current write position to the specified byte in the DMA buffer.
+ // Will check if the write position is smaller than the DMA buffer size.
+ // Will not return an error when the passed in parameter is 0.
+ // Will also check if this function was called with the same write position(in event mode only)
+ // Underruning will also be checked via timer mechanism
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ ntStatus = SetCurrentWritePositionInternal(ulCurrentWritePosition);
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ m_ulLastOsWritePacket = oldLastOsWritePacket;
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetOutputStreamPresentationPosition
+(
+ _Out_ KSAUDIO_PRESENTATION_POSITION *pPresentationPosition
+)
+{
+ ASSERT (pPresentationPosition);
+
+ // The call must be from event driven mode
+ if(m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ return GetPresentationPosition(pPresentationPosition);
+}
+
+//=============================================================================
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetPacketCount
+(
+ _Out_ ULONG *pPacketCount
+)
+{
+ ASSERT(pPacketCount);
+
+ // The call must be from event driven mode
+ if(m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ if (m_KsState == KSSTATE_RUN)
+ {
+ // Get the current time and update simulated position.
+ LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL);
+ UpdatePosition(ilQPC);
+ }
+
+ *pPacketCount = LODWORD(m_llPacketCounter);
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ return STATUS_SUCCESS;
+}
+
+//linear and presentation positions
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::GetPositions(
+ _Out_opt_ ULONGLONG* _pullLinearBufferPosition,
+ _Out_opt_ ULONGLONG* _pullPresentationPosition,
+ _Out_opt_ LARGE_INTEGER* _pliQPCTime
+)
+{
+ DPF_ENTER(("[CMiniportWaveRTStream::GetPositions]"));
+
+ NTSTATUS ntStatus;
+ LARGE_INTEGER ilQPC;
+ KIRQL oldIrql;
+
+ // Update *_pullLinearBufferPosition with the the number of bytes fetched from waveRT ever since a stream got set into RUN
+ // state.
+ // Once the stream is set to STOP state, any further read on this call would return zero.
+
+ //
+ // Get the current time and update position.
+ //
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ ilQPC = KeQueryPerformanceCounter(NULL);
+ if (m_KsState == KSSTATE_RUN)
+ {
+ UpdatePosition(ilQPC);
+ }
+ if (_pullLinearBufferPosition)
+ {
+ *_pullLinearBufferPosition = m_ullLinearPosition;
+ }
+ if (_pullPresentationPosition)
+ {
+ *_pullPresentationPosition = m_ullPresentationPosition;
+ }
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+ if (_pliQPCTime)
+ {
+ *_pliQPCTime = ilQPC;
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+NTSTATUS CMiniportWaveRTStream::GetPresentationPosition(_Out_ KSAUDIO_PRESENTATION_POSITION* _pPresentationPosition)
+{
+ ASSERT(_pPresentationPosition);
+ LARGE_INTEGER timeStamp;
+
+ DPF_ENTER(("[CMiniportWaveRTStream::GetPresentationPosition]"));
+
+ ULONGLONG ullLinearPosition = { 0 };
+ ULONGLONG ullPresentationPosition = { 0 };
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = GetPositions(&ullLinearPosition, &ullPresentationPosition, &timeStamp);
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ _pPresentationPosition->u64PositionInBlocks = ullPresentationPosition * m_pWfExt->Format.nSamplesPerSec / m_pWfExt->Format.nAvgBytesPerSec;
+ _pPresentationPosition->u64QPCPosition = (UINT64)timeStamp.QuadPart;
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::SetCurrentWritePositionInternal(_In_ ULONG _ulCurrentWritePosition)
+{
+ DPF_ENTER(("[CMiniportWaveRTStream::SetCurrentWritePositionInternal]"));
+
+ ASSERT(m_bEoSReceived == FALSE);
+
+ if (m_bEoSReceived)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (_ulCurrentWritePosition > m_ulDmaBufferSize)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ PADAPTERCOMMON pAdapterComm = m_pMiniport->GetAdapterCommObj();
+
+ //Event type: eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Target WaveRtBufferWritePosition received from portcls
+ //Parameter 4: 0
+ pAdapterComm->WriteEtwEvent(eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION,
+ m_ullLinearPosition, // replace with the correct "Current linear buffer position"
+ m_ulCurrentWritePosition,
+ _ulCurrentWritePosition, // this is new write position
+ 0); // always zero
+
+//
+// Check for eMINIPORT_GLITCH_REPORT - Same WaveRT buffer write during event driven mode.
+//
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ if (m_ulCurrentWritePosition == _ulCurrentWritePosition)
+ {
+ //Event type: eMINIPORT_GLITCH_REPORT
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Major glitch code: 3: Received same WaveRT buffer twice in a row during event driven mode
+ //Parameter 4: Minor code for the glitch cause
+ pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT,
+ m_ullLinearPosition, // replace with the correct "Current linear buffer position"
+ m_ulCurrentWritePosition,
+ 3, // received same WaveRT buffer twice in a row during event driven mode
+ _ulCurrentWritePosition);
+ }
+ }
+
+ m_ulCurrentWritePosition = _ulCurrentWritePosition;
+ InterlockedExchange(&m_IsCurrentWritePositionUpdated, 1);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::SetState
+(
+ _In_ KSSTATE State_
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ KIRQL oldIrql;
+
+ // Spew an event for a pin state change request from portcls
+ //Event type: eMINIPORT_PIN_STATE
+ switch (State_)
+ {
+ case KSSTATE_STOP:
+ if (m_KsState == KSSTATE_ACQUIRE)
+ {
+ // Acquire stream resources
+ }
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ // Reset DMA
+ m_llPacketCounter = 0;
+ m_ullPlayPosition = 0;
+ m_ullWritePosition = 0;
+ m_ullLinearPosition = 0;
+ m_ullPresentationPosition = 0;
+
+ // Reset OS read/write positions
+ m_ulLastOsReadPacket = ULONG_MAX;
+ m_ulCurrentWritePosition = 0;
+ m_ulLastOsWritePacket = ULONG_MAX;
+ m_bEoSReceived = FALSE;
+ m_bLastBufferRendered = FALSE;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // Wait until all work items are completed.
+ if (!m_bCapture && !g_DoNotCreateDataFiles)
+ {
+ m_SaveData.WaitAllWorkItems();
+ }
+ break;
+
+ case KSSTATE_ACQUIRE:
+ if (m_KsState == KSSTATE_STOP)
+ {
+ // Acquire stream resources
+ }
+ break;
+
+ case KSSTATE_PAUSE:
+
+ if (m_KsState > KSSTATE_PAUSE)
+ {
+ //
+ // Run -> Pause
+ //
+
+ // Pause DMA
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ ExCancelTimer(m_pNotificationTimer, NULL);
+ KeFlushQueuedDpcs();
+
+ // If pin is transitioning from RUN, save the time since last buffer completion event was sent
+ // so if the pin goes to RUN state again we can send the buffer completion event at correct time.
+ if (m_ullLastDPCTimeStamp > 0)
+ {
+ LARGE_INTEGER qpc;
+ LARGE_INTEGER qpcFrequency;
+ LONGLONG hnsCurrentTime;
+
+ qpc = KeQueryPerformanceCounter(&qpcFrequency);
+
+ // Convert ticks to 100ns units.
+ hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, qpc);
+ m_hnsDPCTimeCarryForward = hnsCurrentTime - m_ullLastDPCTimeStamp + m_hnsDPCTimeCarryForward;
+ }
+ }
+ }
+ // This call updates the linear buffer and presentation positions.
+ GetPositions(NULL, NULL, NULL);
+ break;
+
+ case KSSTATE_RUN:
+ // Start DMA
+ LARGE_INTEGER ullPerfCounterTemp;
+ ullPerfCounterTemp = KeQueryPerformanceCounter(&m_ullPerformanceCounterFrequency);
+ m_ullLastDPCTimeStamp = m_ullDmaTimeStamp = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ullPerfCounterTemp);
+
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ // Set timer for 1 ms. This will cause DPC to run every 1 ms but driver will send out
+ // notification events only after notification interval. This timer is used by Simple Audio Sample to
+ // emulate hardware and send out notification event. Real hardware should not use this
+ // timer to fire notification event as it will drain power if the timer is running at 1 msec.
+ ExSetTimer
+ (
+ m_pNotificationTimer,
+ (-1) * HNSTIME_PER_MILLISECOND,
+ HNSTIME_PER_MILLISECOND, // 1 ms
+ NULL
+ );
+
+ }
+
+ break;
+ }
+
+ m_KsState = State_;
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::SetFormat
+(
+ _In_ KSDATAFORMAT *DataFormat_
+)
+{
+ UNREFERENCED_PARAMETER(DataFormat_);
+
+ PAGED_CODE();
+
+ //if (!m_fCapture && !g_DoNotCreateDataFiles)
+ //{
+ // ntStatus = m_SaveData.SetDataFormat(Format);
+ //}
+
+ return STATUS_NOT_SUPPORTED;
+}
+
+#pragma code_seg()
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::UpdatePosition
+(
+ _In_ LARGE_INTEGER ilQPC
+)
+{
+ // Convert ticks to 100ns units.
+ LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ilQPC);
+
+ // Calculate the time elapsed since the last call to GetPosition() or since the
+ // DMA engine started. Note that the division by 10000 to convert to milliseconds
+ // may cause us to lose some of the time, so we will carry the remainder forward
+ // to the next GetPosition() call.
+ //
+ ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward)/10000;
+
+ // Carry forward the remainder of this division so we don't fall behind with our position too much.
+ //
+ m_hnsElapsedTimeCarryForward = (hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward) % 10000;
+
+ // Calculate how many bytes in the DMA buffer would have been processed in the elapsed
+ // time. Note that the division by 1000 to convert to milliseconds may cause us to
+ // lose some bytes, so we will carry the remainder forward to the next GetPosition() call.
+ //
+ // need to divide by 1000 because m_ulDmaMovementRate is average bytes per sec.
+
+ ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) / 1000 ;
+ m_byteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) % 1000;
+
+ // Increment presentation position even after last buffer is rendered.
+ m_ullPresentationPosition += ByteDisplacement;
+
+ if (m_bCapture)
+ {
+ // Write sine wave to buffer.
+ WriteBytes(ByteDisplacement);
+ }
+ else
+ {
+
+ if (m_bEoSReceived)
+ {
+ // since EoS flag is set, we'll need to make sure not to read data beyond EOS position.
+ // If driver's current position is less than EoS position, then make sure not to read data beyond EoS.
+ if (m_ullWritePosition <= m_ulCurrentWritePosition)
+ {
+ ByteDisplacement = min(ByteDisplacement, m_ulCurrentWritePosition - (ULONG)m_ullWritePosition);
+ }
+ // If our current position is ahead of EoS position and we'll wrap around after new position then adjust
+ // new position if it crosses EoS.
+ else if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize < m_ullWritePosition)
+ {
+ if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize > m_ulCurrentWritePosition)
+ {
+ ByteDisplacement = ByteDisplacement - (((ULONG)m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize - m_ulCurrentWritePosition);
+ }
+ }
+ }
+
+ // If the last packet was rendered(read in the sample driver's case), send out an etw event.
+ if (m_bEoSReceived && !m_bLastBufferRendered
+ && (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize == m_ulCurrentWritePosition)
+ {
+ m_bLastBufferRendered = TRUE;
+ }
+
+ if (!g_DoNotCreateDataFiles)
+ {
+ // Read from buffer and write to a file.
+ ReadBytes(ByteDisplacement);
+ }
+ }
+
+ // Increment the DMA position by the number of bytes displaced since the last
+ // call to UpdatePosition() and ensure we properly wrap at buffer length.
+ //
+ m_ullPlayPosition = m_ullWritePosition =
+ (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize;
+
+ // m_ullDmaTimeStamp is updated in both GetPostion and GetLinearPosition calls
+ // so m_ullLinearPosition needs to be updated accordingly here
+ //
+ m_ullLinearPosition += ByteDisplacement;
+
+ // Update the DMA time stamp for the next call to GetPosition()
+ //
+ m_ullDmaTimeStamp = hnsCurrentTime;
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::WriteBytes
+(
+ _In_ ULONG ByteDisplacement
+)
+/*++
+
+Routine Description:
+
+This function writes the audio buffer using a sine wave generator
+
+Arguments:
+
+ByteDisplacement - # of bytes to process.
+
+--*/
+{
+ ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;
+
+ // Normally this will loop no more than once for a single wrap, but if
+ // many bytes have been displaced then this may loops many times.
+ while (ByteDisplacement > 0)
+ {
+ ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
+
+ m_ToneGenerator.GenerateSine(m_pDmaBuffer + bufferOffset, runWrite);
+
+ bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
+ ByteDisplacement -= runWrite;
+ }
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::ReadBytes
+(
+ _In_ ULONG ByteDisplacement
+)
+/*++
+
+Routine Description:
+
+This function reads the audio buffer and saves the data in a file.
+
+Arguments:
+
+ByteDisplacement - # of bytes to process.
+
+--*/
+{
+ ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;
+
+ // Normally this will loop no more than once for a single wrap, but if
+ // many bytes have been displaced then this may loops many times.
+ while (ByteDisplacement > 0)
+ {
+ ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
+ m_SaveData.WriteData(m_pDmaBuffer + bufferOffset, runWrite);
+ bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
+ ByteDisplacement -= runWrite;
+ }
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRTStream::SetContentId
+(
+ _In_ ULONG contentId,
+ _In_ PCDRMRIGHTS drmRights
+)
+/*++
+
+Routine Description:
+
+ Sets DRM content Id for this stream. Also updates the Mixed content Id.
+
+Arguments:
+
+ contentId - new content id
+
+ drmRights - rights for this stream.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::SetContentId]"));
+
+ NTSTATUS ntStatus;
+ ULONG ulOldContentId = contentId;
+
+ m_ulContentId = contentId;
+
+ //
+ // Miniport should create a mixed DrmRights.
+ //
+ ntStatus = m_pMiniport->UpdateDrmRights();
+
+ //
+ // Restore the passed-in content Id.
+ //
+ if (!NT_SUCCESS(ntStatus))
+ {
+ m_ulContentId = ulOldContentId;
+ }
+
+ //
+ // Simple Audio Sample writes each stream seperately to disk. If the rights for this
+ // stream indicates that the stream is CopyProtected, stop writing to disk.
+ //
+ m_SaveData.Disable(drmRights->CopyProtect);
+
+ //
+ // From MSDN:
+ //
+ // This sample doesn't forward protected content, but if your driver uses
+ // lower layer drivers or a different stack to properly work, please see the
+ // following info from MSDN:
+ //
+ // "Before allowing protected content to flow through a data path, the system
+ // verifies that the data path is secure. To do so, the system authenticates
+ // each module in the data path beginning at the upstream end of the data path
+ // and moving downstream. As each module is authenticated, that module gives
+ // the system information about the next module in the data path so that it
+ // can also be authenticated. To be successfully authenticated, a module's
+ // binary file must be signed as DRM-compliant.
+ //
+ // Two adjacent modules in the data path can communicate with each other in
+ // one of several ways. If the upstream module calls the downstream module
+ // through IoCallDriver, the downstream module is part of a WDM driver. In
+ // this case, the upstream module calls the DrmForwardContentToDeviceObject
+ // function to provide the system with the device object representing the
+ // downstream module. (If the two modules communicate through the downstream
+ // module's COM interface or content handlers, the upstream module calls
+ // DrmForwardContentToInterface or DrmAddContentHandlers instead.)
+ //
+ // DrmForwardContentToDeviceObject performs the same function as
+ // PcForwardContentToDeviceObject and IDrmPort2::ForwardContentToDeviceObject."
+ //
+ // Other supported DRM DDIs for down-level module validation are:
+ // DrmForwardContentToInterfaces and DrmAddContentHandlers.
+ //
+ // For more information, see MSDN's DRM Functions and Interfaces.
+ //
+
+ return ntStatus;
+} // SetContentId
+
+//=============================================================================
+#pragma code_seg()
+void
+TimerNotifyRT
+(
+ _In_ PEX_TIMER Timer,
+ _In_opt_ PVOID DeferredContext
+)
+{
+ LARGE_INTEGER qpc;
+ LARGE_INTEGER qpcFrequency;
+ BOOL bufferCompleted = FALSE;
+
+ UNREFERENCED_PARAMETER(Timer);
+
+ _IRQL_limited_to_(DISPATCH_LEVEL);
+
+ CMiniportWaveRTStream* _this = (CMiniportWaveRTStream*)DeferredContext;
+
+ if (NULL == _this)
+ {
+ return;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&_this->m_PositionSpinLock, &oldIrql);
+
+ qpc = KeQueryPerformanceCounter(&qpcFrequency);
+
+ // Convert ticks to 100ns units.
+ LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(_this->m_ullPerformanceCounterFrequency.QuadPart, qpc);
+
+ // Calculate the time elapsed since the last we ran DPC that matched Notification interval. Note that the division by 10000
+ // to convert to milliseconds may cause us to lose some of the time, so we will carry the remainder forward.
+
+ ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward)/10000;
+
+ if (TimeElapsedInMS >= _this->m_ulNotificationIntervalMs)
+ {
+ // Carry forward the time greater than notification interval to adjust time to signal next buffer completion event accordingly.
+ _this->m_hnsDPCTimeCarryForward = hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward - (_this->m_ulNotificationIntervalMs * 10000);
+ // Save the last time DPC ran at notification interval
+ _this->m_ullLastDPCTimeStamp = hnsCurrentTime;
+ bufferCompleted = TRUE;
+ }
+
+ if (!bufferCompleted && !_this->m_bEoSReceived)
+ {
+ goto End;
+ }
+
+ _this->UpdatePosition(qpc);
+
+ if (!_this->m_bEoSReceived)
+ {
+ _this->m_llPacketCounter++;
+ }
+
+ if (_this->m_KsState != KSSTATE_RUN)
+ {
+ goto End;
+ }
+
+ PADAPTERCOMMON pAdapterComm = _this->m_pMiniport->GetAdapterCommObj();
+
+ // Simple buffer underrun detection.
+ if (!_this->IsCurrentWaveRTWritePositionUpdated() && !_this->m_bEoSReceived)
+ {
+ //Event type: eMINIPORT_GLITCH_REPORT
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Major glitch code: 1:WaveRT buffer is underrun
+ //Parameter 4: Minor code for the glitch cause
+ pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT,
+ _this->m_ullLinearPosition,
+ _this->GetCurrentWaveRTWritePosition(),
+ 1, // WaveRT buffer is underrun
+ 0);
+ }
+
+ // Send buffer completion event if either of the following is true
+ // 1. Driver consumed a complete buffer for this stream
+ // 2. Driver consumed a partial buffer containing EoS for this stream
+
+ if (!IsListEmpty(&_this->m_NotificationList) &&
+ (bufferCompleted || _this->m_bLastBufferRendered))
+ {
+ PLIST_ENTRY leCurrent = _this->m_NotificationList.Flink;
+ while (leCurrent != &_this->m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ KeSetEvent(nleCurrent->NotificationEvent, 0, 0);
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ if (_this->m_bLastBufferRendered)
+ {
+ ExCancelTimer(_this->m_pNotificationTimer, NULL);
+ }
+
+End:
+ KeReleaseSpinLock(&_this->m_PositionSpinLock, oldIrql);
+ return;
+}
+//=============================================================================
+
diff --git a/audio/simpleaudiosample/Source/Main/minwavertstream.h b/audio/simpleaudiosample/Source/Main/minwavertstream.h
new file mode 100644
index 00000000..5545e0d8
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavertstream.h
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavertstream.h
+
+Abstract:
+
+ Definition of wavert miniport class.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+#define _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+
+#include "savedata.h"
+#include "ToneGenerator.h"
+
+//
+// Structure to store notifications events in a protected list
+//
+typedef struct _NotificationListEntry
+{
+ LIST_ENTRY ListEntry;
+ PKEVENT NotificationEvent;
+} NotificationListEntry;
+
+EXT_CALLBACK TimerNotifyRT;
+
+//=============================================================================
+// Referenced Forward
+//=============================================================================
+class CMiniportWaveRT;
+typedef CMiniportWaveRT *PCMiniportWaveRT;
+
+//=============================================================================
+// Classes
+//=============================================================================
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportWaveRTStream
+//
+class CMiniportWaveRTStream :
+ public IDrmAudioStream,
+ public IMiniportWaveRTStreamNotification,
+ public IMiniportWaveRTInputStream,
+ public IMiniportWaveRTOutputStream,
+ public CUnknown
+{
+protected:
+ PPORTWAVERTSTREAM m_pPortStream;
+ LIST_ENTRY m_NotificationList;
+ PEX_TIMER m_pNotificationTimer;
+ ULONG m_ulNotificationIntervalMs;
+ ULONG m_ulCurrentWritePosition;
+ LONG m_IsCurrentWritePositionUpdated;
+
+public:
+ DECLARE_STD_UNKNOWN();
+ DEFINE_STD_CONSTRUCTOR(CMiniportWaveRTStream);
+ ~CMiniportWaveRTStream();
+
+ IMP_IMiniportWaveRTStream;
+ IMP_IMiniportWaveRTStreamNotification;
+ IMP_IMiniportWaveRTInputStream;
+ IMP_IMiniportWaveRTOutputStream;
+ IMP_IMiniportWaveRT;
+ IMP_IDrmAudioStream;
+
+ NTSTATUS Init
+ (
+ _In_ PCMiniportWaveRT Miniport,
+ _In_ PPORTWAVERTSTREAM Stream,
+ _In_ ULONG Channel,
+ _In_ BOOLEAN Capture,
+ _In_ PKSDATAFORMAT DataFormat,
+ _In_ GUID SignalProcessingMode
+ );
+
+ // Friends
+ friend class CMiniportWaveRT;
+ friend EXT_CALLBACK TimerNotifyRT;
+protected:
+ CMiniportWaveRT* m_pMiniport;
+ ULONG m_ulPin;
+ BOOLEAN m_bCapture;
+ BOOLEAN m_bUnregisterStream;
+ ULONG m_ulDmaBufferSize;
+ BYTE* m_pDmaBuffer;
+ ULONG m_ulNotificationsPerBuffer;
+ KSSTATE m_KsState;
+ PKTIMER m_pTimer;
+ PRKDPC m_pDpc;
+ ULONGLONG m_ullPlayPosition;
+ ULONGLONG m_ullWritePosition;
+ ULONGLONG m_ullLinearPosition;
+ ULONGLONG m_ullPresentationPosition;
+ ULONG m_ulLastOsReadPacket;
+ ULONG m_ulLastOsWritePacket;
+ LONGLONG m_llPacketCounter;
+ ULONGLONG m_ullDmaTimeStamp;
+ LARGE_INTEGER m_ullPerformanceCounterFrequency;
+ ULONGLONG m_hnsElapsedTimeCarryForward;
+ ULONGLONG m_ullLastDPCTimeStamp;
+ ULONGLONG m_hnsDPCTimeCarryForward;
+ ULONG m_byteDisplacementCarryForward;
+ ULONG m_ulDmaMovementRate;
+ BOOL m_bLfxEnabled;
+ PBOOL m_pbMuted;
+ PLONG m_plVolumeLevel;
+ PLONG m_plPeakMeter;
+ PWAVEFORMATEXTENSIBLE m_pWfExt;
+ ULONG m_ulContentId;
+ CSaveData m_SaveData;
+ ToneGenerator m_ToneGenerator;
+ GUID m_SignalProcessingMode;
+ BOOLEAN m_bEoSReceived;
+ BOOLEAN m_bLastBufferRendered;
+ KSPIN_LOCK m_PositionSpinLock;
+ // Member variable as config params for tone generator
+ ULONG m_ulHostCaptureToneFrequency;
+ // If abs(m_dwHostCaptureToneAmplitude) + abs(m_dwHostCaptureToneDCValue) > 100
+ // m_dwHostCaptureToneDCValue will be compensated to make the sum equal to 100
+ DWORD m_dwHostCaptureToneAmplitude; // must be between -100 to 100
+ DWORD m_dwLoopbackCaptureToneAmplitude; // must be between -100 to 100
+ DWORD m_dwHostCaptureToneDCOffset; // must be between -100 to 100
+ DWORD m_dwLoopbackCaptureToneDCOffset; // must be between -100 to 100
+ DWORD m_dwHostCaptureToneInitialPhase; // must be between -31416 to 31416
+ DWORD m_dwLoopbackCaptureToneInitialPhase; // must be between -31416 to 31416
+ // Member variable as config params for tone generator
+
+public:
+
+ NTSTATUS GetVolumeChannelCount
+ (
+ _Out_ UINT32* puiChannelCount
+ );
+
+ NTSTATUS GetVolumeSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ LONG* _pVolume
+ );
+
+ NTSTATUS SetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ LONG _Volume
+ );
+
+ NTSTATUS GetMuteChannelCount
+ (
+ _Out_ UINT32* puiChannelCount
+ );
+
+ NTSTATUS GetMuteSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ BOOL* _pbMute
+ );
+
+ NTSTATUS SetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ BOOL _bMute
+ );
+
+ //presentation
+ NTSTATUS GetPresentationPosition
+ (
+ _Out_ KSAUDIO_PRESENTATION_POSITION *_pPresentationPosition
+ );
+
+ NTSTATUS SetCurrentWritePosition
+ (
+ _In_ ULONG ulCurrentWritePosition
+ );
+
+
+ ULONG GetCurrentWaveRTWritePosition()
+ {
+ return m_ulCurrentWritePosition;
+ };
+
+ // To support simple underrun validation.
+ BOOL IsCurrentWaveRTWritePositionUpdated()
+ {
+ return InterlockedExchange(&m_IsCurrentWritePositionUpdated, 0) ? TRUE : FALSE;
+ };
+
+ GUID GetSignalProcessingMode()
+ {
+ return m_SignalProcessingMode;
+ }
+
+private:
+
+ //
+ // Helper functions.
+ //
+
+#pragma code_seg()
+
+ VOID WriteBytes
+ (
+ _In_ ULONG ByteDisplacement
+ );
+
+ VOID ReadBytes
+ (
+ _In_ ULONG ByteDisplacement
+ );
+
+ VOID UpdatePosition
+ (
+ _In_ LARGE_INTEGER ilQPC
+ );
+
+ NTSTATUS SetCurrentWritePositionInternal
+ (
+ _In_ ULONG ulCurrentWritePosition
+ );
+
+ NTSTATUS GetPositions
+ (
+ _Out_opt_ ULONGLONG * _pullLinearBufferPosition,
+ _Out_opt_ ULONGLONG * _pullPresentationPosition,
+ _Out_opt_ LARGE_INTEGER * _pliQPCTime
+ );
+
+ NTSTATUS ReadRegistrySettings();
+
+};
+typedef CMiniportWaveRTStream *PCMiniportWaveRTStream;
+#endif // _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+