From afe234056290aae04fcd0ae4a6bb1b70369e86dc Mon Sep 17 00:00:00 2001 From: CoolStar Date: Tue, 28 Nov 2023 15:14:25 -0800 Subject: [PATCH] Add I2S Audio Driver (WDM) (#15) * Add I2S Audio Driver --- README.md | 6 +- build/RockchipDrivers.sln | 36 + drivers/audio/csaudiork3x/README.md | 15 + .../Source/Filters/Filters.vcxproj | 101 + .../Source/Filters/Filters.vcxproj.Filters | 159 + .../csaudiork3x/Source/Filters/hdmitopo.cpp | 118 + .../csaudiork3x/Source/Filters/hdmitopo.h | 22 + .../csaudiork3x/Source/Filters/hdmitoptable.h | 152 + .../Source/Filters/headphonetopo.cpp | 118 + .../Source/Filters/headphonetopo.h | 22 + .../Source/Filters/headphonetoptable.h | 152 + .../Source/Filters/micarray1toptable.h | 157 + .../Source/Filters/micarraytopo.cpp | 825 +++++ .../csaudiork3x/Source/Filters/micarraytopo.h | 97 + .../Source/Filters/micarraywavtable.h | 292 ++ .../Source/Filters/micjacktopo.cpp | 118 + .../csaudiork3x/Source/Filters/micjacktopo.h | 24 + .../Source/Filters/micjacktoptable.h | 159 + .../csaudiork3x/Source/Filters/minipairs.h | 258 ++ .../Source/Filters/speakertopo.cpp | 118 + .../csaudiork3x/Source/Filters/speakertopo.h | 22 + .../Source/Filters/speakertoptable.h | 152 + .../Source/Filters/speakerwavtable.h | 246 ++ .../audio/csaudiork3x/Source/Inc/Inc.vcxproj | 79 + .../Source/Inc/Inc.vcxproj.Filters | 63 + .../audio/csaudiork3x/Source/Inc/NewDelete.h | 104 + .../audio/csaudiork3x/Source/Inc/basetopo.h | 96 + drivers/audio/csaudiork3x/Source/Inc/common.h | 480 +++ .../csaudiork3x/Source/Inc/definitions.h | 198 ++ .../audio/csaudiork3x/Source/Inc/endpoints.h | 133 + .../audio/csaudiork3x/Source/Inc/kshelper.h | 129 + .../audio/csaudiork3x/Source/Inc/mintopo.h | 81 + .../csaudiork3x/Source/Main/Main.vcxproj | 130 + .../Source/Main/Main.vcxproj.Filters | 80 + .../csaudiork3x/Source/Main/NewDelete.cpp | 141 + .../audio/csaudiork3x/Source/Main/adapter.cpp | 707 +++++ .../csaudiork3x/Source/Main/basetopo.cpp | 674 +++++ .../audio/csaudiork3x/Source/Main/common.cpp | 2689 +++++++++++++++++ .../csaudiork3x/Source/Main/csaudiork3x.inx | 315 ++ .../csaudiork3x/Source/Main/csaudiork3x.rc | 43 + .../audio/csaudiork3x/Source/Main/mintopo.cpp | 557 ++++ .../csaudiork3x/Source/Main/minwavert.cpp | 1703 +++++++++++ .../audio/csaudiork3x/Source/Main/minwavert.h | 261 ++ .../Source/Main/minwavertstream.cpp | 525 ++++ .../csaudiork3x/Source/Main/minwavertstream.h | 86 + .../Source/Utilities/Utilities.vcxproj | 90 + .../Utilities/Utilities.vcxproj.Filters | 55 + .../audio/csaudiork3x/Source/Utilities/adsp.h | 51 + .../Source/Utilities/csaudioapi.cpp | 104 + .../csaudiork3x/Source/Utilities/dma.cpp | 71 + .../audio/csaudiork3x/Source/Utilities/hw.cpp | 751 +++++ .../audio/csaudiork3x/Source/Utilities/hw.h | 192 ++ .../csaudiork3x/Source/Utilities/kshelper.cpp | 646 ++++ .../audio/csaudiork3x/Source/Utilities/rk3x.h | 413 +++ drivers/dma/pl330dma/driver.h | 94 +- drivers/dma/pl330dma/pl330.vcxproj | 4 +- drivers/dma/pl330dma/pl330.vcxproj.Filters | 12 + drivers/include/pl330dma.h | 96 + 58 files changed, 15124 insertions(+), 98 deletions(-) create mode 100644 drivers/audio/csaudiork3x/README.md create mode 100644 drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj create mode 100644 drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj.Filters create mode 100644 drivers/audio/csaudiork3x/Source/Filters/hdmitopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Filters/hdmitopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/hdmitoptable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/headphonetopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Filters/headphonetopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/headphonetoptable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micarray1toptable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micarraytopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micarraytopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micarraywavtable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micjacktopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micjacktopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/micjacktoptable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/minipairs.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/speakertopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Filters/speakertopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/speakertoptable.h create mode 100644 drivers/audio/csaudiork3x/Source/Filters/speakerwavtable.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj create mode 100644 drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj.Filters create mode 100644 drivers/audio/csaudiork3x/Source/Inc/NewDelete.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/basetopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/common.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/definitions.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/endpoints.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/kshelper.h create mode 100644 drivers/audio/csaudiork3x/Source/Inc/mintopo.h create mode 100644 drivers/audio/csaudiork3x/Source/Main/Main.vcxproj create mode 100644 drivers/audio/csaudiork3x/Source/Main/Main.vcxproj.Filters create mode 100644 drivers/audio/csaudiork3x/Source/Main/NewDelete.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/adapter.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/basetopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/common.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/csaudiork3x.inx create mode 100644 drivers/audio/csaudiork3x/Source/Main/csaudiork3x.rc create mode 100644 drivers/audio/csaudiork3x/Source/Main/mintopo.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/minwavert.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/minwavert.h create mode 100644 drivers/audio/csaudiork3x/Source/Main/minwavertstream.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Main/minwavertstream.h create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj.Filters create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/adsp.h create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/csaudioapi.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/dma.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/hw.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/hw.h create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/kshelper.cpp create mode 100644 drivers/audio/csaudiork3x/Source/Utilities/rk3x.h create mode 100644 drivers/include/pl330dma.h diff --git a/README.md b/README.md index 07996ee..77f3e6a 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ This repository contains drivers for RK35xx-based platforms, with a focus on RK3 |HDMI output|MSBDD (Inbox)|🟡 Partially working|Single display with mode limited at 1080p 60 Hz, provided by UEFI GOP.| |HDMI input||🔴 Not working|| |DisplayPort output|MSBDD (Inbox)|🟡 Partially working|Single display with mode limited at 1080p 60 Hz, provided by UEFI GOP. Only works in one orientation of the Type-C connector.| -|HDMI audio||🔴 Not working|| +|HDMI audio||🔴 WIP|I2S audio driver enumerates, but requires VOP driver| |DisplayPort audio||🔴 Not working|| -|Analog audio||🔴 Not working|| +|Analog audio|[es8323](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/audio/codecs/es8323)|🟢 Working (Orange Pi 5)|| |Digital audio||🔴 Not working|| |USB/DP Alt Mode||🔴 Not working|| |GPU||🔴 Not working|Software-rendered| @@ -30,7 +30,7 @@ This repository contains drivers for RK35xx-based platforms, with a focus on RK3 |UART||🔴 Not working|No OS driver but debugging does work on UART2, being configured by UEFI.| |GPIO|[rk3xgpio](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/gpio)|🟢 Working|| |I2C|[rk3xi2c](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/i2c)|🟢 Working|| -|I2S||🔴 Not working|| +|I2S|[csaudiork3x](https://github.com/worproject/Rockchip-Windows-Drivers/tree/master/drivers/audio/csaudiork3x)|🟢 Working|| |SPI||🔴 Not working|| |CAN bus||🔴 Not working|| |SPDIF||🔴 Not working|| diff --git a/build/RockchipDrivers.sln b/build/RockchipDrivers.sln index 7e49a62..e4b1e67 100644 --- a/build/RockchipDrivers.sln +++ b/build/RockchipDrivers.sln @@ -15,6 +15,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "es8323", "..\drivers\audio\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rk3xi2sbus", "..\drivers\audio\rk3xi2sbus\rk3xi2sbus.vcxproj", "{BA95E25D-392E-4BC9-B481-E4D9FB9AFFB4}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csaudio-Filters", "..\drivers\audio\csaudiork3x\Source\Filters\Filters.vcxproj", "{771312CF-E5A2-4676-8142-86CEBDF99E2B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csaudio-Inc", "..\drivers\audio\csaudiork3x\Source\Inc\Inc.vcxproj", "{4B664BA5-057A-41B8-B365-2C99065C4DFA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csaudio-Main", "..\drivers\audio\csaudiork3x\Source\Main\Main.vcxproj", "{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}" + ProjectSection(ProjectDependencies) = postProject + {33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {33E61864-6F2C-4F9F-BE70-8F8985A4F283} + {771312CF-E5A2-4676-8142-86CEBDF99E2B} = {771312CF-E5A2-4676-8142-86CEBDF99E2B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "csaudio-Utilities", "..\drivers\audio\csaudiork3x\Source\Utilities\Utilities.vcxproj", "{33E61864-6F2C-4F9F-BE70-8F8985A4F283}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -55,6 +67,30 @@ Global {BA95E25D-392E-4BC9-B481-E4D9FB9AFFB4}.Release|ARM64.ActiveCfg = Release|ARM64 {BA95E25D-392E-4BC9-B481-E4D9FB9AFFB4}.Release|ARM64.Build.0 = Release|ARM64 {BA95E25D-392E-4BC9-B481-E4D9FB9AFFB4}.Release|ARM64.Deploy.0 = Release|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|ARM64.Build.0 = Debug|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|ARM64.ActiveCfg = Release|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|ARM64.Build.0 = Release|ARM64 + {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|ARM64.Deploy.0 = Release|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|ARM64.Build.0 = Debug|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|ARM64.ActiveCfg = Release|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|ARM64.Build.0 = Release|ARM64 + {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|ARM64.Deploy.0 = Release|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.Build.0 = Debug|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|ARM64.ActiveCfg = Release|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|ARM64.Build.0 = Release|ARM64 + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|ARM64.Deploy.0 = Release|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|ARM64.Build.0 = Debug|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|ARM64.ActiveCfg = Release|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|ARM64.Build.0 = Release|ARM64 + {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|ARM64.Deploy.0 = Release|ARM64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/drivers/audio/csaudiork3x/README.md b/drivers/audio/csaudiork3x/README.md new file mode 100644 index 0000000..8ca3918 --- /dev/null +++ b/drivers/audio/csaudiork3x/README.md @@ -0,0 +1,15 @@ +# CoolStar Audio for Rockchip 3xxx + +Open Source driver for Rockchip 3xxx + +Currently Implemented: + +* 16-bit 48 Khz Audio Streams +* I2S TDM Streams +* Runtime Power Management +* Play / Pause / Stop support for streams +* WDM Position Counter + +Tested on Orange Pi 5 (RK3588S) + +Based off csaudioacp3x diff --git a/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj b/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj new file mode 100644 index 0000000..5afed3b --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + + {771312CF-E5A2-4676-8142-86CEBDF99E2B} + $(MSBuildProjectName) + 1 + Debug + Win32 + {F51739CE-5253-42B5-9191-57F28B5842C6} + csaudio-Filters + $(LatestTargetPlatformVersion) + + + + Windows10 + Universal + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + true + + + + $(IntDir) + + + + + + + + csaudio-Filters + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(AdditionalIncludeDirectories);..\Inc + %(PreprocessorDefinitions);_USE_WAVERT_ + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;. + %(AdditionalIncludeDirectories);..\Inc;. + %(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_ + + + 4595;%(DisableSpecificWarnings) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(AdditionalIncludeDirectories);..\Inc + %(PreprocessorDefinitions);_USE_WAVERT_ + + + sha256 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj.Filters b/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj.Filters new file mode 100644 index 0000000..1dfba70 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/Filters.vcxproj.Filters @@ -0,0 +1,159 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {75C3E63D-04EA-4EB3-B9F1-505497C51F71} + + + h;hpp;hxx;hm;inl;inc;xsd + {5E8F8D4C-2886-4109-9E78-CE5EA6DB4AC4} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {75D3016A-4ED8-4FAF-9817-394BE1112534} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.cpp b/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.cpp new file mode 100644 index 0000000..7fab62f --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.cpp @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + hdmitopo.cpp + +Abstract: + + Implementation of topology miniport for the hdmi +--*/ + +#pragma warning (disable : 4127) + +#include "definitions.h" +#include "endpoints.h" +#include "mintopo.h" +#include "hdmitopo.h" +#include "hdmitoptable.h" + + +#pragma code_seg("PAGE") +//============================================================================= +NTSTATUS +PropertyHandler_HdmiTopoFilter +( + _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_HdmiTopoFilter]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack)) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION) + { + ntStatus = pMiniport->PropertyHandlerJackDescription( + PropertyRequest, + ARRAYSIZE(HdmiJackDescriptions), + HdmiJackDescriptions + ); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2) + { + ntStatus = pMiniport->PropertyHandlerJackDescription2( + PropertyRequest, + ARRAYSIZE(HdmiJackDescriptions), + HdmiJackDescriptions, + 0 // jack capabilities + ); + } + } + + return ntStatus; +} // PropertyHandler_HdmiTopoFilter + +//============================================================================= +NTSTATUS +PropertyHandler_HdmiTopology +( + _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_HdmiTopology]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + return pMiniport->PropertyHandlerGeneric(PropertyRequest); +} // PropertyHandler_HdmiTopology + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.h b/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.h new file mode 100644 index 0000000..0fefc7a --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/hdmitopo.h @@ -0,0 +1,22 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + hdmitopo.h + +Abstract: + + Declaration of topology miniport for hdmi. +--*/ + +#ifndef _CSAUDIORK3X_HDMITOPO_H_ +#define _CSAUDIORK3X_HDMITOPO_H_ + +NTSTATUS PropertyHandler_HdmiTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +NTSTATUS PropertyHandler_HdmiTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +#endif // _CSAUDIORK3X_HEADPHONETOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/hdmitoptable.h b/drivers/audio/csaudiork3x/Source/Filters/hdmitoptable.h new file mode 100644 index 0000000..67bbf08 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/hdmitoptable.h @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakertoptable.h + +Abstract: + + Declaration of topology tables. +--*/ + +#ifndef _CSAUDIORK3X_HDMITOPTABLE_H_ +#define _CSAUDIORK3X_HDMITOPTABLE_H_ + +//============================================================================= +static +KSDATARANGE HdmiTopoPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +//============================================================================= +static +PKSDATARANGE HdmiTopoPinDataRangePointersBridge[] = +{ + &HdmiTopoPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR HdmiTopoMiniportPins[] = +{ + // KSPIN_TOPO_WAVEOUT_SOURCE + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(HdmiTopoPinDataRangePointersBridge),// DataRangesCount + HdmiTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_IN, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSCATEGORY_AUDIO, // Category + NULL, // Name + 0 // Reserved + } + }, + // KSPIN_TOPO_LINEOUT_DEST + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(HdmiTopoPinDataRangePointersBridge),// DataRangesCount + HdmiTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_OUT, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSNODETYPE_HDMI_INTERFACE, // Category + NULL, // Name + 0 // Reserved + } + } +}; + +//============================================================================= +static +KSJACK_DESCRIPTION HdmiJackDescBridge = +{ + KSAUDIO_SPEAKER_STEREO, + 0x0000, // Color spec for green + eConnTypeOtherDigital, + eGeoLocHDMI, + eGenLocPrimaryBox, + ePortConnJack, + TRUE +}; + +// Only return a KSJACK_DESCRIPTION for the physical bridge pin. +static +PKSJACK_DESCRIPTION HdmiJackDescriptions[] = +{ + NULL, + &HdmiJackDescBridge +}; + +static +PCCONNECTION_DESCRIPTOR HdmiTopoMiniportConnections[] = +{ + {PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST} //no volume controls +}; + +//============================================================================= +static +PCPROPERTY_ITEM PropertiesHdmiTopoFilter[] = +{ + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_HdmiTopoFilter + }, + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_HdmiTopoFilter + } +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHdmiTopoFilter, PropertiesHdmiTopoFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR HdmiTopoMiniportFilterDescriptor = +{ + 0, // Version + &AutomationHdmiTopoFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(HdmiTopoMiniportPins), // PinCount + HdmiTopoMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(HdmiTopoMiniportConnections), // ConnectionCount + HdmiTopoMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories +}; + +#endif // _CSAUDIORK3X_HDMITOPTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.cpp b/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.cpp new file mode 100644 index 0000000..ef527f1 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.cpp @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + headphonetopo.cpp + +Abstract: + + Implementation of topology miniport for the headphone (jack). +--*/ + +#pragma warning (disable : 4127) + +#include "definitions.h" +#include "endpoints.h" +#include "mintopo.h" +#include "headphonetopo.h" +#include "headphonetoptable.h" + + +#pragma code_seg("PAGE") +//============================================================================= +NTSTATUS +PropertyHandler_HeadphoneTopoFilter +( + _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_HeadphoneTopoFilter]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack)) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION) + { + ntStatus = pMiniport->PropertyHandlerJackDescription( + PropertyRequest, + ARRAYSIZE(HeadphoneJackDescriptions), + HeadphoneJackDescriptions + ); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2) + { + ntStatus = pMiniport->PropertyHandlerJackDescription2( + PropertyRequest, + ARRAYSIZE(HeadphoneJackDescriptions), + HeadphoneJackDescriptions, + 0 // jack capabilities + ); + } + } + + return ntStatus; +} // PropertyHandler_HeadphoneTopoFilter + +//============================================================================= +NTSTATUS +PropertyHandler_HeadphoneTopology +( + _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_HeadphoneTopology]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + return pMiniport->PropertyHandlerGeneric(PropertyRequest); +} // PropertyHandler_HeadphoneTopology + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.h b/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.h new file mode 100644 index 0000000..65ecfbb --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/headphonetopo.h @@ -0,0 +1,22 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + headphonetopo.h + +Abstract: + + Declaration of topology miniport for the headphone (jack). +--*/ + +#ifndef _CSAUDIORK3X_HEADPHONETOPO_H_ +#define _CSAUDIORK3X_HEADPHONETOPO_H_ + +NTSTATUS PropertyHandler_HeadphoneTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +NTSTATUS PropertyHandler_HeadphoneTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +#endif // _CSAUDIORK3X_HEADPHONETOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/headphonetoptable.h b/drivers/audio/csaudiork3x/Source/Filters/headphonetoptable.h new file mode 100644 index 0000000..96af1e9 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/headphonetoptable.h @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakertoptable.h + +Abstract: + + Declaration of topology tables. +--*/ + +#ifndef _CSAUDIORK3X_HEADPHONETOPTABLE_H_ +#define _CSAUDIORK3X_HEADPHONETOPTABLE_H_ + +//============================================================================= +static +KSDATARANGE HeadphoneTopoPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +//============================================================================= +static +PKSDATARANGE HeadphoneTopoPinDataRangePointersBridge[] = +{ + &HeadphoneTopoPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR HeadphoneTopoMiniportPins[] = +{ + // KSPIN_TOPO_WAVEOUT_SOURCE + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(HeadphoneTopoPinDataRangePointersBridge),// DataRangesCount + HeadphoneTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_IN, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSCATEGORY_AUDIO, // Category + NULL, // Name + 0 // Reserved + } + }, + // KSPIN_TOPO_LINEOUT_DEST + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(HeadphoneTopoPinDataRangePointersBridge),// DataRangesCount + HeadphoneTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_OUT, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSNODETYPE_HEADPHONES, // Category + NULL, // Name + 0 // Reserved + } + } +}; + +//============================================================================= +static +KSJACK_DESCRIPTION HeadphoneJackDescBridge = +{ + KSAUDIO_SPEAKER_STEREO, + 0xB3C98C, // Color spec for green + eConnType3Point5mm, + eGeoLocRight, + eGenLocPrimaryBox, + ePortConnJack, + TRUE +}; + +// Only return a KSJACK_DESCRIPTION for the physical bridge pin. +static +PKSJACK_DESCRIPTION HeadphoneJackDescriptions[] = +{ + NULL, + &HeadphoneJackDescBridge +}; + +static +PCCONNECTION_DESCRIPTOR HeadphoneTopoMiniportConnections[] = +{ + {PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST} //no volume controls +}; + +//============================================================================= +static +PCPROPERTY_ITEM PropertiesHeadphoneTopoFilter[] = +{ + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_HeadphoneTopoFilter + }, + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_HeadphoneTopoFilter + } +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHeadphoneTopoFilter, PropertiesHeadphoneTopoFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR HeadphoneTopoMiniportFilterDescriptor = +{ + 0, // Version + &AutomationHeadphoneTopoFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(HeadphoneTopoMiniportPins), // PinCount + HeadphoneTopoMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(HeadphoneTopoMiniportConnections), // ConnectionCount + HeadphoneTopoMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories +}; + +#endif // _CSAUDIORK3X_HEADPHONETOPTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/micarray1toptable.h b/drivers/audio/csaudiork3x/Source/Filters/micarray1toptable.h new file mode 100644 index 0000000..35270e5 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micarray1toptable.h @@ -0,0 +1,157 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + micarray1toptable.h + +Abstract: + + Declaration of topology tables for the mic array. + +--*/ + +#ifndef _CSAUDIORK3X_MICARRAY1TOPTABLE_H_ +#define _CSAUDIORK3X_MICARRAY1TOPTABLE_H_ + +// +// {6ae81ff4-203e-4fe1-88aa-f2d57775cd4a} +DEFINE_GUID(MICARRAY1_CUSTOM_NAME, + 0x6ae81ff4, 0x203e, 0x4fe1, 0x88, 0xaa, 0xf2, 0xd5, 0x77, 0x75, 0xcd, 0x4a); + +//============================================================================= +static +KSDATARANGE MicArray1TopoPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +//============================================================================= +static +PKSDATARANGE MicArray1TopoPinDataRangePointersBridge[] = +{ + &MicArray1TopoPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR MicArray1TopoMiniportPins[] = +{ + // KSPIN_TOPO_MIC_ELEMENTS + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(MicArray1TopoPinDataRangePointersBridge), // DataRangesCount + MicArray1TopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_IN, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSNODETYPE_MICROPHONE_ARRAY, // Category + &MICARRAY1_CUSTOM_NAME, // Name + 0 // Reserved + } + }, + + // KSPIN_TOPO_BRIDGE + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(MicArray1TopoPinDataRangePointersBridge), // DataRangesCount + MicArray1TopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_OUT, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSCATEGORY_AUDIO, // Category + NULL, // Name + 0 // Reserved + } + } +}; + +static +PCCONNECTION_DESCRIPTOR MicArray1TopoMiniportConnections[] = +{ + // FromNode, FromPin, ToNode, ToPin + { PCFILTER_NODE, KSPIN_TOPO_MIC_ELEMENTS, PCFILTER_NODE, KSPIN_TOPO_BRIDGE } +}; + + + +//============================================================================= +static +PCPROPERTY_ITEM MicArray1PropertiesTopoFilter[] = +{ + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicArrayTopoFilter + }, + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicArrayTopoFilter + }, + { + &KSPROPSETID_Audio, + KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicArrayTopoFilter + }, + { + &KSPROPSETID_Audio, + KSPROPERTY_AUDIO_MIC_SNR, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicArrayTopoFilter + }, + { + &KSPROPSETID_Audio, + KSPROPERTY_AUDIO_MIC_SENSITIVITY2, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicArrayTopoFilter + } +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArray1TopoFilter, MicArray1PropertiesTopoFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR MicArray1TopoMiniportFilterDescriptor = +{ + 0, // Version + &AutomationMicArray1TopoFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(MicArray1TopoMiniportPins), // PinCount + MicArray1TopoMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(MicArray1TopoMiniportConnections),// ConnectionCount + MicArray1TopoMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories +}; + +#endif // _CSAUDIORK3X_MICARRAY1TOPTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.cpp b/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.cpp new file mode 100644 index 0000000..fdfd46e --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.cpp @@ -0,0 +1,825 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + micarraytopo.cpp + +Abstract: + + Implementation of topology miniport for the mic array. + +--*/ + +#pragma warning (disable : 4127) + +#include "definitions.h" +#include "endpoints.h" +#include "common.h" +#include "kshelper.h" +#include "micarraytopo.h" +#include "micarray1toptable.h" + +constexpr float MICARRAY_SENSITIVITY = -46.5f; +constexpr float MICARRAY_SENSITIVITY2 = -23.5f; +constexpr float MICARRAY_SNR = 66.0f; + +constexpr inline LONG FloatToFixedPoint16_16(float fl) +{ + return (static_cast((fl) * (65536.0f))); +} + +#pragma code_seg("PAGE") + +//============================================================================= +NTSTATUS +CreateMicArrayMiniportTopology +( + _Out_ PUNKNOWN* Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType, + _In_ PUNKNOWN UnknownAdapter, + _In_opt_ PVOID DeviceContext, + _In_ PENDPOINT_MINIPAIR MiniportPair +) +/*++ + +Routine Description: + + Creates a new topology miniport. + +Arguments: + + Unknown - + + RefclsId - + + UnknownOuter - + + PoolType - + + UnknownAdapter - + + DeviceContext - + + MiniportPair - + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + ASSERT(Unknown); + ASSERT(MiniportPair); + + UNREFERENCED_PARAMETER(UnknownAdapter); + UNREFERENCED_PARAMETER(DeviceContext); + + CMicArrayMiniportTopology* obj = + new (PoolType, MINTOPORT_POOLTAG) + CMicArrayMiniportTopology(UnknownOuter, + MiniportPair->TopoDescriptor, + MiniportPair->DeviceMaxChannels, + MiniportPair->DeviceType); + if (NULL == obj) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + obj->AddRef(); + + *Unknown = reinterpret_cast(obj); + + return STATUS_SUCCESS; +} // CreateMicArrayMiniportTopology + +//============================================================================= +CMicArrayMiniportTopology::~CMicArrayMiniportTopology +( + void +) +/*++ + +Routine Description: + + Topology miniport destructor + +Arguments: + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + DPF_ENTER(("[CMicArrayMiniportTopology::~CMicArrayMiniportTopology]")); +} // ~CMicArrayMiniportTopology + +//============================================================================= +NTSTATUS +CMicArrayMiniportTopology::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. + +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 + CMiniportTopologyCsAudioRk3x::DataRangeIntersection + ( + PinId, + ClientDataRange, + MyDataRange, + OutputBufferLength, + ResultantFormat, + ResultantFormatLength + ); +} // DataRangeIntersection + +//============================================================================= +STDMETHODIMP +CMicArrayMiniportTopology::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 CMiniportTopologyCsAudioRk3x::GetDescription(OutFilterDescriptor); +} // GetDescription + +//============================================================================= +STDMETHODIMP +CMicArrayMiniportTopology::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 IUnknown 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(("[CMicArrayMiniportTopology::Init]")); + + NTSTATUS ntStatus; + + ntStatus = + CMiniportTopologyCsAudioRk3x::Init + ( + UnknownAdapter, + Port_ + ); + + return ntStatus; +} // Init + +//============================================================================= +STDMETHODIMP +CMicArrayMiniportTopology::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 + +//============================================================================= +NTSTATUS +CMicArrayMiniportTopology::PropertyHandlerMicArrayGeometry +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + +Routine Description: + + Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY ) + +Arguments: + + PropertyRequest - + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + ASSERT(PropertyRequest); + + DPF_ENTER(("[PropertyHandlerMicArrayGeometry]")); + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + ULONG nPinId = (ULONG)-1; + + if (PropertyRequest->InstanceSize >= sizeof(ULONG)) + { + nPinId = *(PULONG(PropertyRequest->Instance)); + + if (nPinId == KSPIN_TOPO_MIC_ELEMENTS) + { + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ntStatus = + PropertyHandler_BasicSupport + ( + PropertyRequest, + KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET, + VT_ILLEGAL + ); + } + else + { + ULONG cElements = 2; + ULONG cbNeeded = FIELD_OFFSET(KSAUDIO_MIC_ARRAY_GEOMETRY, KsMicCoord) + + cElements * sizeof(KSAUDIO_MICROPHONE_COORDINATES); + + 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) + { + PKSAUDIO_MIC_ARRAY_GEOMETRY pMAG = (PKSAUDIO_MIC_ARRAY_GEOMETRY)PropertyRequest->Value; + //const SHORT MicArray_180_Degrees = 31416; // 10000 * pi + const SHORT MicArray_45_Degrees = 7854; // 10000 * pi / 4 + + // fill in mic array geometry fields + pMAG->usVersion = 0x0100; // Version of Mic array specification (0x0100) + pMAG->usMicArrayType = (USHORT)KSMICARRAY_MICARRAYTYPE_LINEAR; // Type of Mic Array + pMAG->wVerticalAngleBegin = -MicArray_45_Degrees; // Work Volume Vertical Angle Begin + pMAG->wVerticalAngleEnd = MicArray_45_Degrees; // Work Volume Vertical Angle End + pMAG->wHorizontalAngleBegin = 0; // Work Volume HorizontalAngle Begin + pMAG->wHorizontalAngleEnd = 0; // Work Volume HorizontalAngle End + pMAG->usFrequencyBandLo = 100; // Low end of Freq Range + pMAG->usFrequencyBandHi = 8000; // High end of Freq Range + + pMAG->usNumberOfMicrophones = 2; // Count of microphone coordinate structures to follow. + + pMAG->KsMicCoord[0].usType = (USHORT)KSMICARRAY_MICTYPE_CARDIOID; + pMAG->KsMicCoord[0].wXCoord = 0; + pMAG->KsMicCoord[0].wYCoord = 100; + pMAG->KsMicCoord[0].wZCoord = 0; + pMAG->KsMicCoord[0].wVerticalAngle = 0; + pMAG->KsMicCoord[0].wHorizontalAngle = 0; + + pMAG->KsMicCoord[1].usType = (USHORT)KSMICARRAY_MICTYPE_CARDIOID; + pMAG->KsMicCoord[1].wXCoord = 0; + pMAG->KsMicCoord[1].wYCoord = -100; + pMAG->KsMicCoord[1].wZCoord = 0; + pMAG->KsMicCoord[1].wVerticalAngle = 0; + pMAG->KsMicCoord[1].wHorizontalAngle = 0; + ntStatus = STATUS_SUCCESS; + } + } + } + } + } + + return ntStatus; +} + +//============================================================================= +NTSTATUS +CMicArrayMiniportTopology::PropertyHandlerMicProperties +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + +Routine Description: + +Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_SNR ) +Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_SENSITIVITY2 ) + +Arguments: + +PropertyRequest - + +Return Value: + +NT status code. + +--*/ +{ + PAGED_CODE(); + + ASSERT(PropertyRequest); + + DPF_ENTER(("[PropertyHandlerMicProperties]")); + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + ULONG nPinId = (ULONG)-1; + KFLOATING_SAVE saveData; + NTSTATUS fstatus; + + if (PropertyRequest->InstanceSize >= sizeof(ULONG)) + { + nPinId = *(PULONG(PropertyRequest->Instance)); + + if (nPinId == KSPIN_TOPO_MIC_ELEMENTS) + { + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ntStatus = + PropertyHandler_BasicSupport + ( + PropertyRequest, + KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET, + VT_ILLEGAL + ); + } + else + { + ntStatus = + ValidatePropertyParams + ( + PropertyRequest, + sizeof(LONG), + 0 + ); + + if (NT_SUCCESS(ntStatus)) + { + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SNR) + { + LONG* micSNR = (LONG*)PropertyRequest->Value; + fstatus = KeSaveFloatingPointState(&saveData); + if (NT_SUCCESS(fstatus)) + { + // Return microphone SNR information. + *micSNR = FloatToFixedPoint16_16(MICARRAY_SNR); // convert float dB to fixed point arithmetic + KeRestoreFloatingPointState(&saveData); + } + ntStatus = STATUS_SUCCESS; + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SENSITIVITY2) + { + LONG* micSensitivity2 = (LONG*)PropertyRequest->Value; + fstatus = KeSaveFloatingPointState(&saveData); + if (NT_SUCCESS(fstatus)) + { + // Return microphone SNR information. + *micSensitivity2 = FloatToFixedPoint16_16(MICARRAY_SENSITIVITY2); // convert float dB to fixed point arithmetic + KeRestoreFloatingPointState(&saveData); + } + ntStatus = STATUS_SUCCESS; + } + } + else + { + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + } + } + } + } + } + + return ntStatus; +} + +//============================================================================= +NTSTATUS +CMicArrayMiniportTopology::PropertyHandlerJackDescription +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + +Routine Description: + + Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION ) + +Arguments: + + PropertyRequest - + +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 == KSPIN_TOPO_MIC_ELEMENTS) + { + 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; + + pDesc->ChannelMapping = 0; // Don't specify channel mask for array mic + pDesc->Color = 0x00000000; // Black. This is an integrated device + pDesc->ConnectionType = eConnTypeUnknown; // Integrated. + pDesc->GenLocation = eGenLocPrimaryBox; + pDesc->GeoLocation = eGeoLocFront; + pDesc->PortConnection = ePortConnIntegratedDevice; + pDesc->IsConnected = TRUE; // This is an integrated device, so it's always "connected" + + ntStatus = STATUS_SUCCESS; + } + } + } + } + } + + return ntStatus; +} + +//============================================================================= +NTSTATUS +CMicArrayMiniportTopology::PropertyHandlerJackDescription2 +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + +Routine Description: + + Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 ) + +Arguments: + + PropertyRequest - + +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 == KSPIN_TOPO_MIC_ELEMENTS) + { + 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 = 0; + + ntStatus = STATUS_SUCCESS; + } + } + } + } + } + + return ntStatus; +} + +//============================================================================= +NTSTATUS +PropertyHandler_MicArrayTopoFilter +( + _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_MicArrayTopoFilter]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PCMicArrayMiniportTopology pMiniport = (PCMicArrayMiniportTopology)PropertyRequest->MajorTarget; + + if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Audio)) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY) + { + ntStatus = pMiniport->PropertyHandlerMicArrayGeometry(PropertyRequest); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SENSITIVITY2) + { + ntStatus = pMiniport->PropertyHandlerMicProperties(PropertyRequest); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SNR) + { + ntStatus = pMiniport->PropertyHandlerMicProperties(PropertyRequest); + } + } + else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack)) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION) + { + ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2) + { + ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest); + } + } + + return ntStatus; +} // PropertyHandler_TopoFilter + +//============================================================================= +NTSTATUS +PropertyHandler_MicArrayTopology +( + _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_MicArrayTopology]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + PCMicArrayMiniportTopology pMiniport = (PCMicArrayMiniportTopology)PropertyRequest->MajorTarget; + + return pMiniport->PropertyHandlerGeneric(PropertyRequest); +} // PropertyHandler_MicArrayTopology + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.h b/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.h new file mode 100644 index 0000000..38ee7af --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micarraytopo.h @@ -0,0 +1,97 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + micarraytopo.h + +Abstract: + + Declaration of mic array topology miniport. + +--*/ + +#ifndef _CSAUDIORK3X_MICARRAYTOPO_H_ +#define _CSAUDIORK3X_MICARRAYTOPO_H_ + +#include "basetopo.h" + +//============================================================================= +// Classes +//============================================================================= + +/////////////////////////////////////////////////////////////////////////////// +// CMicArrayMiniportTopology +// + +#pragma code_seg() +class CMicArrayMiniportTopology : + public CMiniportTopologyCsAudioRk3x, + public IMiniportTopology, + public CUnknown +{ +public: + DECLARE_STD_UNKNOWN(); + CMicArrayMiniportTopology + ( + _In_opt_ PUNKNOWN UnknownOuter, + _In_ PCFILTER_DESCRIPTOR* FilterDesc, + _In_ USHORT DeviceMaxChannels, + _In_ eDeviceType DeviceType + ) + : CUnknown(UnknownOuter), + CMiniportTopologyCsAudioRk3x(FilterDesc, DeviceMaxChannels), + m_DeviceType(DeviceType) + { + ASSERT(m_DeviceType == eInputDevice); + } + + ~CMicArrayMiniportTopology(); + + IMP_IMiniportTopology; + + NTSTATUS PropertyHandlerMicArrayGeometry + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + NTSTATUS PropertyHandlerMicProperties + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + NTSTATUS PropertyHandlerJackDescription + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + NTSTATUS PropertyHandlerJackDescription2 + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + +protected: + eDeviceType m_DeviceType; + +}; + +typedef CMicArrayMiniportTopology* PCMicArrayMiniportTopology; + + +NTSTATUS +CreateMicArrayMiniportTopology( + _Out_ PUNKNOWN* Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType, + _In_ PUNKNOWN UnknownAdapter, + _In_opt_ PVOID DeviceContext, + _In_ PENDPOINT_MINIPAIR MiniportPair +); + +NTSTATUS PropertyHandler_MicArrayTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest); +NTSTATUS PropertyHandler_MicArrayTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +#endif // _CSAUDIORK3X_MICARRAYTOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/micarraywavtable.h b/drivers/audio/csaudiork3x/Source/Filters/micarraywavtable.h new file mode 100644 index 0000000..99cf364 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micarraywavtable.h @@ -0,0 +1,292 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + micarraywavtable.h + +Abstract:- + + Declaration of wave miniport tables for the mic array. + +--*/ + +#ifndef _CSAUDIORK3X_MICARRAYWAVTABLE_H_ +#define _CSAUDIORK3X_MICARRAYWAVTABLE_H_ + +// +// Mic array range. +// +#define MICARRAY_RAW_CHANNELS 2 // Channels for raw mode +#define MICARRAY_DEVICE_MAX_CHANNELS 2 // Max channels overall +#define MICARRAY_32_BITS_PER_SAMPLE_PCM 32 // 32 Bits Per Sample +#define MICARRAY_RAW_SAMPLE_RATE 48000 // Raw sample rate + +// +// Max # of pin instances. +// +#define MICARRAY_MAX_INPUT_STREAMS 1 + +//============================================================================= +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE MicArrayPinSupportedDeviceFormats[] = +{ + // 48 KHz 16-bit 2 channels + { + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } + } +}; + +// +// Supported modes (only on streaming pins). +// +static +MODE_AND_DEFAULT_FORMAT MicArrayPinSupportedDeviceModes[] = +{ + { + STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW, + &MicArrayPinSupportedDeviceFormats[0].DataFormat + } +}; + +// +// The entries here must follow the same order as the filter's pin +// descriptor array. +// +static +PIN_DEVICE_FORMATS_AND_MODES MicArrayPinDeviceFormatsAndModes[] = +{ + { + BridgePin, + NULL, + 0, + NULL, + 0 + }, + { + SystemCapturePin, + MicArrayPinSupportedDeviceFormats, + SIZEOF_ARRAY(MicArrayPinSupportedDeviceFormats), + MicArrayPinSupportedDeviceModes, + SIZEOF_ARRAY(MicArrayPinSupportedDeviceModes) + } +}; + +//============================================================================= +// Data ranges +// +// See CMiniportWaveRT::DataRangeIntersection. +// +static +KSDATARANGE_AUDIO MicArrayPinDataRangesRawStream[] = +{ + { + { + sizeof(KSDATARANGE_AUDIO), + KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + MICARRAY_RAW_CHANNELS, + MICARRAY_32_BITS_PER_SAMPLE_PCM, + MICARRAY_32_BITS_PER_SAMPLE_PCM, + MICARRAY_RAW_SAMPLE_RATE, + MICARRAY_RAW_SAMPLE_RATE + }, +}; + +static +PKSDATARANGE MicArrayPinDataRangePointersStream[] = +{ + // All supported device formats should be listed in the DataRange. + PKSDATARANGE(&MicArrayPinDataRangesRawStream[0]), + PKSDATARANGE(&PinDataRangeAttributeList), +}; + +//============================================================================= +static +KSDATARANGE MicArrayPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +static +PKSDATARANGE MicArrayPinDataRangePointersBridge[] = +{ + &MicArrayPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR MicArrayWaveMiniportPins[] = +{ + // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_BRIDGE + { + 0, + 0, + 0, + NULL, + { + 0, + NULL, + 0, + NULL, + SIZEOF_ARRAY(MicArrayPinDataRangePointersBridge), + MicArrayPinDataRangePointersBridge, + KSPIN_DATAFLOW_IN, + KSPIN_COMMUNICATION_NONE, + &KSCATEGORY_AUDIO, + NULL, + 0 + } + }, + // Wave In Streaming Pin (Capture) KSPIN_WAVE_HOST + { + MICARRAY_MAX_INPUT_STREAMS, + MICARRAY_MAX_INPUT_STREAMS, + 0, + NULL, + { + 0, + NULL, + 0, + NULL, + SIZEOF_ARRAY(MicArrayPinDataRangePointersStream), + MicArrayPinDataRangePointersStream, + KSPIN_DATAFLOW_OUT, + KSPIN_COMMUNICATION_SINK, + &KSCATEGORY_AUDIO, + &KSAUDFNAME_RECORDING_CONTROL, + 0 + } + } +}; + +//============================================================================= +static +PCNODE_DESCRIPTOR MicArrayWaveMiniportNodes[] = +{ + // KSNODE_WAVE_ADC + { + 0, // Flags + NULL, // AutomationTable + &KSNODETYPE_ADC, // Type + NULL // Name + } +}; + +//============================================================================= +static +PCCONNECTION_DESCRIPTOR MicArrayWaveMiniportConnections[] = +{ + { PCFILTER_NODE, KSPIN_WAVE_BRIDGE, KSNODE_WAVE_ADC, 1 }, + { KSNODE_WAVE_ADC, 0, PCFILTER_NODE, KSPIN_WAVEIN_HOST }, +}; + +//============================================================================= + +static +CSAUDIORK3X_PROPERTY_ITEM PropertiesMicArrayWaveFilter[] = +{ + { + { + &KSPROPSETID_General, + KSPROPERTY_GENERAL_COMPONENTID, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_WaveFilter, + }, + 0, + 0, + NULL, + NULL, + NULL, + NULL, + 0 + }, + { + { + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PROPOSEDATAFORMAT, + KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_WaveFilter, + }, + 0, + 0, + NULL, + NULL, + NULL, + NULL, + 0 + }, + { + { + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PROPOSEDATAFORMAT2, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_WaveFilter, + }, + 0, + 0, + NULL, + NULL, + NULL, + NULL, + 0 + }, +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArrayWaveFilter, PropertiesMicArrayWaveFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR MicArrayWaveMiniportFilterDescriptor = +{ + 0, // Version + &AutomationMicArrayWaveFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(MicArrayWaveMiniportPins), // PinCount + MicArrayWaveMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + SIZEOF_ARRAY(MicArrayWaveMiniportNodes), // NodeCount + MicArrayWaveMiniportNodes, // Nodes + SIZEOF_ARRAY(MicArrayWaveMiniportConnections), // ConnectionCount + MicArrayWaveMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories - use defaults (audio, render, capture) +}; + +#endif // _CSAUDIORK3X_MICARRAYWAVTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.cpp b/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.cpp new file mode 100644 index 0000000..1f2190d --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.cpp @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + usbhsmictopo.cpp + +Abstract: + + Implementation of topology miniport for the mic (external: headphone). + +--*/ +#pragma warning (disable : 4127) + +#include "definitions.h" +#include "endpoints.h" +#include "mintopo.h" +#include "micjacktopo.h" +#include "micjacktoptable.h" + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_MicJackTopoFilter +( + _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_MicJackTopoFilter]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack)) + { + switch (PropertyRequest->PropertyItem->Id) + { + case KSPROPERTY_JACK_DESCRIPTION: + ntStatus = pMiniport->PropertyHandlerJackDescription( + PropertyRequest, + ARRAYSIZE(MicJackDescriptions), + MicJackDescriptions); + break; + + case KSPROPERTY_JACK_DESCRIPTION2: + ntStatus = pMiniport->PropertyHandlerJackDescription2( + PropertyRequest, + ARRAYSIZE(MicJackDescriptions), + MicJackDescriptions, + 0 // jack capabilities + ); + break; + } + } + + return ntStatus; +} // PropertyHandler_MicJackTopoFilter + +//============================================================================= +NTSTATUS +PropertyHandler_MicJackTopology +( + _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_MicJackTopology]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + return pMiniport->PropertyHandlerGeneric(PropertyRequest); +} // PropertyHandler_HeadphoneTopology + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.h b/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.h new file mode 100644 index 0000000..bf76018 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micjacktopo.h @@ -0,0 +1,24 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + micjack.h + +Abstract: + + Declaration of topology miniport for the mic (external: headphone). + +--*/ + +#ifndef _CSAUDIORK3X_MICJACKTOPO_H_ +#define _CSAUDIORK3X_MICJACKTOPO_H_ + +// Function declarations. +NTSTATUS +PropertyHandler_MicJackTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +NTSTATUS PropertyHandler_MicJackTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +#endif // _CSAUDIORK3X_MICJACKTOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/micjacktoptable.h b/drivers/audio/csaudiork3x/Source/Filters/micjacktoptable.h new file mode 100644 index 0000000..df1be9b --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/micjacktoptable.h @@ -0,0 +1,159 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + usbhsmictopotable.h + +Abstract: + + Declaration of topology table for the USB Headset mic (external) + +--*/ + +#ifndef _CSAUDIORK3X_MICJACKTOPTABLE_H_ +#define _CSAUDIORK3X_MICJACKTOPTABLE_H_ + +//============================================================================= +static +KSDATARANGE MicJackTopoPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +//============================================================================= +static +PKSDATARANGE MicJackTopoPinDataRangePointersBridge[] = +{ + &MicJackTopoPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR MicJackTopoMiniportPins[] = +{ + // KSPIN_TOPO_MIC_ELEMENTS + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(MicJackTopoPinDataRangePointersBridge),// DataRangesCount + MicJackTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_IN, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSNODETYPE_MICROPHONE, // Category + NULL, // Name + 0 // Reserved + } + }, + + // KSPIN_TOPO_BRIDGE + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(MicJackTopoPinDataRangePointersBridge),// DataRangesCount + MicJackTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_OUT, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSCATEGORY_AUDIO, // Category + NULL, // Name + 0 // Reserved + } + } +}; + +//============================================================================= +static +KSJACK_DESCRIPTION MicJackDesc = +{ + KSAUDIO_SPEAKER_MONO, + JACKDESC_RGB(0, 0, 0), + eConnType3Point5mm, + eGeoLocRight, + eGenLocPrimaryBox, + ePortConnJack, + TRUE // NOTE: For convenience, wired headset jacks will be "unplugged" at boot. +}; + +//============================================================================= +// Only return a KSJACK_DESCRIPTION for the physical bridge pin. +static +PKSJACK_DESCRIPTION MicJackDescriptions[] = +{ + &MicJackDesc, + NULL +}; + +//============================================================================= +static +PCCONNECTION_DESCRIPTOR MicJackMiniportConnections[] = +{ + // FromNode, FromPin, ToNode, ToPin + { PCFILTER_NODE, KSPIN_TOPO_MIC_ELEMENTS, PCFILTER_NODE, KSPIN_TOPO_BRIDGE } +}; + + +//============================================================================= +static +PCPROPERTY_ITEM MicJackPropertiesTopoFilter[] = +{ + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicJackTopoFilter + }, + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_MicJackTopoFilter + } +}; + + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicJackTopoFilter, + MicJackPropertiesTopoFilter); + + +//============================================================================= +static +PCFILTER_DESCRIPTOR MicJackTopoMiniportFilterDescriptor = +{ + 0, // Version + &AutomationMicJackTopoFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(MicJackTopoMiniportPins), // PinCount + MicJackTopoMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(MicJackMiniportConnections),// ConnectionCount + MicJackMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories +}; + +#endif // _CSAUDIORK3X_MICJACKTOPTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/minipairs.h b/drivers/audio/csaudiork3x/Source/Filters/minipairs.h new file mode 100644 index 0000000..1e0ea43 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/minipairs.h @@ -0,0 +1,258 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + minipairs.h + +Abstract: + + Local audio endpoint filter definitions. +--*/ + +#ifndef _CSAUDIORK3X_MINIPAIRS_H_ +#define _CSAUDIORK3X_MINIPAIRS_H_ + +#include "headphonetopo.h" +#include "hdmitopo.h" +#include "speakertopo.h" +#include "headphonetoptable.h" +#include "hdmitoptable.h" +#include "speakertoptable.h" +#include "speakerwavtable.h" + +#include "micjacktopo.h" +#include "micarraytopo.h" +#include "micjacktoptable.h" +#include "micarray1toptable.h" +#include "micarraywavtable.h" + + +NTSTATUS +CreateMiniportWaveRTCsAudioRk3x +( + _Out_ PUNKNOWN *, + _In_ REFCLSID, + _In_opt_ PUNKNOWN, + _In_ POOL_TYPE, + _In_ PUNKNOWN, + _In_opt_ PVOID, + _In_ PENDPOINT_MINIPAIR +); + +NTSTATUS +CreateMiniportTopologyCsAudioRk3x +( + _Out_ PUNKNOWN *, + _In_ REFCLSID, + _In_opt_ PUNKNOWN, + _In_ POOL_TYPE, + _In_ PUNKNOWN, + _In_opt_ PVOID, + _In_ PENDPOINT_MINIPAIR +); + +// +// Render miniports. +// + +/********************************************************************* +* Topology/Wave bridge connection for speaker (internal) * +* * +* +------+ +------+ * +* | Wave | | Topo | * +* | | | | * +* System --->|0 1|--------------->|0 1|---> Line Out * +* | | | | * +* +------+ +------+ * +*********************************************************************/ +static +PHYSICALCONNECTIONTABLE SpeakerTopologyPhysicalConnections[] = +{ + { + KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn + KSPIN_WAVE_RENDER3_SOURCE, // WaveOut + CONNECTIONTYPE_WAVE_OUTPUT + } +}; + +static +ENDPOINT_MINIPAIR SpeakerMiniports = +{ + eOutputDevice, + L"TopologySpeaker", // make sure this or the template name matches with KSNAME_TopologySpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportTopologyCsAudioRk3x, + &SpeakerTopoMiniportFilterDescriptor, + 0, NULL, // Interface properties + L"WaveSpeaker", // make sure this or the template name matches with KSNAME_WaveSpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportWaveRTCsAudioRk3x, + &SpeakerWaveMiniportFilterDescriptor, + 0, // Interface properties + NULL, + SPEAKER_DEVICE_MAX_CHANNELS, + SpeakerPinDeviceFormatsAndModes, + SIZEOF_ARRAY(SpeakerPinDeviceFormatsAndModes), + SpeakerTopologyPhysicalConnections, + SIZEOF_ARRAY(SpeakerTopologyPhysicalConnections), + ENDPOINT_NO_FLAGS, +}; + +static +ENDPOINT_MINIPAIR HeadphoneMiniports = +{ + eOutputDevice, + L"TopologyHeadphones", // make sure this or the template name matches with KSNAME_TopologySpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportTopologyCsAudioRk3x, + &HeadphoneTopoMiniportFilterDescriptor, + 0, NULL, // Interface properties + L"WaveHeadphones", // make sure this or the template name matches with KSNAME_WaveSpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportWaveRTCsAudioRk3x, + &SpeakerWaveMiniportFilterDescriptor, + 0, // Interface properties + NULL, + SPEAKER_DEVICE_MAX_CHANNELS, + SpeakerPinDeviceFormatsAndModes, + SIZEOF_ARRAY(SpeakerPinDeviceFormatsAndModes), + SpeakerTopologyPhysicalConnections, + SIZEOF_ARRAY(SpeakerTopologyPhysicalConnections), + ENDPOINT_NO_FLAGS, +}; + +static +ENDPOINT_MINIPAIR HdmiMiniports = +{ + eOutputDevice, + L"TopologyHdmi", // make sure this or the template name matches with KSNAME_TopologySpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportTopologyCsAudioRk3x, + &HdmiTopoMiniportFilterDescriptor, + 0, NULL, // Interface properties + L"WaveHdmi", // make sure this or the template name matches with KSNAME_WaveSpeaker in the inf's [Strings] section + NULL, // optional template name + CreateMiniportWaveRTCsAudioRk3x, + &SpeakerWaveMiniportFilterDescriptor, + 0, // Interface properties + NULL, + SPEAKER_DEVICE_MAX_CHANNELS, + SpeakerPinDeviceFormatsAndModes, + SIZEOF_ARRAY(SpeakerPinDeviceFormatsAndModes), + SpeakerTopologyPhysicalConnections, + SIZEOF_ARRAY(SpeakerTopologyPhysicalConnections), + ENDPOINT_NO_FLAGS, +}; + +// +// Capture miniports. +// + +/********************************************************************* +* Topology/Wave bridge connection for mic array 1 (front) * +* * +* +------+ +------+ * +* | Topo | | Wave | * +* | | | | * +* Mic in --->|0 1|===>|0 1|---> Capture Host Pin * +* | | | | * +* +------+ +------+ * +*********************************************************************/ +static +PHYSICALCONNECTIONTABLE MicArray1TopologyPhysicalConnections[] = +{ + { + KSPIN_TOPO_BRIDGE, // TopologyOut + KSPIN_WAVE_BRIDGE, // WaveIn + CONNECTIONTYPE_TOPOLOGY_OUTPUT + } +}; + +static +ENDPOINT_MINIPAIR MicArray1Miniports = +{ + eInputDevice, + L"TopologyMicArray1", // make sure this or the template name matches with KSNAME_TopologyMicArray1 in the inf's [Strings] section + NULL, // optional template name + CreateMicArrayMiniportTopology, + &MicArray1TopoMiniportFilterDescriptor, + 0, NULL, // Interface properties + L"WaveMicArray1", // make sure this or the tempalte name matches with KSNAME_WaveMicArray1 in the inf's [Strings] section + NULL, // optional template name + CreateMiniportWaveRTCsAudioRk3x, + &MicArrayWaveMiniportFilterDescriptor, + 0, // Interface properties + NULL, + MICARRAY_DEVICE_MAX_CHANNELS, + MicArrayPinDeviceFormatsAndModes, + SIZEOF_ARRAY(MicArrayPinDeviceFormatsAndModes), + MicArray1TopologyPhysicalConnections, + SIZEOF_ARRAY(MicArray1TopologyPhysicalConnections), + ENDPOINT_NO_FLAGS, +}; + +static +ENDPOINT_MINIPAIR MicJackMiniports = +{ + eInputDevice, + L"TopologyMicJack", // make sure this or the template name matches with KSNAME_TopologyMicArray1 in the inf's [Strings] section + NULL, // optional template name + CreateMiniportTopologyCsAudioRk3x, + &MicJackTopoMiniportFilterDescriptor, + 0, NULL, // Interface properties + L"WaveMicJack", // make sure this or the tempalte name matches with KSNAME_WaveMicArray1 in the inf's [Strings] section + NULL, // optional template name + CreateMiniportWaveRTCsAudioRk3x, + &MicArrayWaveMiniportFilterDescriptor, + 0, // Interface properties + NULL, + MICARRAY_DEVICE_MAX_CHANNELS, + MicArrayPinDeviceFormatsAndModes, + SIZEOF_ARRAY(MicArrayPinDeviceFormatsAndModes), + MicArray1TopologyPhysicalConnections, + SIZEOF_ARRAY(MicArray1TopologyPhysicalConnections), + ENDPOINT_NO_FLAGS, +}; + + +//============================================================================= +// +// Render miniport pairs. NOTE: the split of render and capture is arbitrary and +// unnessary, this array could contain capture endpoints. +// +static +PENDPOINT_MINIPAIR g_RenderEndpoints[] = +{ + &HeadphoneMiniports +}; + +static +PENDPOINT_MINIPAIR g_RenderHDMIEndpoints[] = +{ + &HdmiMiniports +}; + +#define g_cRenderEndpoints (SIZEOF_ARRAY(g_RenderEndpoints)) + +//============================================================================= +// +// Capture miniport pairs. NOTE: the split of render and capture is arbitrary and +// unnessary, this array could contain render endpoints. +// +static +PENDPOINT_MINIPAIR g_CaptureEndpoints[] = +{ + &MicJackMiniports +}; + +#define g_cCaptureEndpoints (SIZEOF_ARRAY(g_CaptureEndpoints)) + +//============================================================================= +// +// Total miniports = # endpoints * 2 (topology + wave). +// +#define g_MaxMiniports ((g_cRenderEndpoints + g_cCaptureEndpoints) * 2) + +#endif // _CSAUDIORK3X_MINIPAIRS_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/speakertopo.cpp b/drivers/audio/csaudiork3x/Source/Filters/speakertopo.cpp new file mode 100644 index 0000000..d1635ef --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/speakertopo.cpp @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakertopo.cpp + +Abstract: + + Implementation of topology miniport for the speaker (internal). +--*/ + +#pragma warning (disable : 4127) + +#include "definitions.h" +#include "endpoints.h" +#include "mintopo.h" +#include "speakertopo.h" +#include "speakertoptable.h" + + +#pragma code_seg("PAGE") +//============================================================================= +NTSTATUS +PropertyHandler_SpeakerTopoFilter +( + _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_SpeakerTopoFilter]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack)) + { + if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION) + { + ntStatus = pMiniport->PropertyHandlerJackDescription( + PropertyRequest, + ARRAYSIZE(SpeakerJackDescriptions), + SpeakerJackDescriptions + ); + } + else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2) + { + ntStatus = pMiniport->PropertyHandlerJackDescription2( + PropertyRequest, + ARRAYSIZE(SpeakerJackDescriptions), + SpeakerJackDescriptions, + 0 // jack capabilities + ); + } + } + + return ntStatus; +} // PropertyHandler_SpeakerTopoFilter + +//============================================================================= +NTSTATUS +PropertyHandler_SpeakerTopology +( + _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_SpeakerTopology]")); + + // PropertryRequest structure is filled by portcls. + // MajorTarget is a pointer to miniport object for miniports. + // + PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget; + + return pMiniport->PropertyHandlerGeneric(PropertyRequest); +} // PropertyHandler_SpeakerTopology + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Filters/speakertopo.h b/drivers/audio/csaudiork3x/Source/Filters/speakertopo.h new file mode 100644 index 0000000..6ce8c81 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/speakertopo.h @@ -0,0 +1,22 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakertopo.h + +Abstract: + + Declaration of topology miniport for the speaker (internal). +--*/ + +#ifndef _CSAUDIORK3X_SPEAKERTOPO_H_ +#define _CSAUDIORK3X_SPEAKERTOPO_H_ + +NTSTATUS PropertyHandler_SpeakerTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +NTSTATUS PropertyHandler_SpeakerTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest); + +#endif // _CSAUDIORK3X_SPEAKERTOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/speakertoptable.h b/drivers/audio/csaudiork3x/Source/Filters/speakertoptable.h new file mode 100644 index 0000000..6539831 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/speakertoptable.h @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakertoptable.h + +Abstract: + + Declaration of topology tables. +--*/ + +#ifndef _CSAUDIORK3X_SPEAKERTOPTABLE_H_ +#define _CSAUDIORK3X_SPEAKERTOPTABLE_H_ + +//============================================================================= +static +KSDATARANGE SpeakerTopoPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +//============================================================================= +static +PKSDATARANGE SpeakerTopoPinDataRangePointersBridge[] = +{ + &SpeakerTopoPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR SpeakerTopoMiniportPins[] = +{ + // KSPIN_TOPO_WAVEOUT_SOURCE + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(SpeakerTopoPinDataRangePointersBridge),// DataRangesCount + SpeakerTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_IN, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSCATEGORY_AUDIO, // Category + NULL, // Name + 0 // Reserved + } + }, + // KSPIN_TOPO_LINEOUT_DEST + { + 0, + 0, + 0, // InstanceCount + NULL, // AutomationTable + { // KsPinDescriptor + 0, // InterfacesCount + NULL, // Interfaces + 0, // MediumsCount + NULL, // Mediums + SIZEOF_ARRAY(SpeakerTopoPinDataRangePointersBridge),// DataRangesCount + SpeakerTopoPinDataRangePointersBridge, // DataRanges + KSPIN_DATAFLOW_OUT, // DataFlow + KSPIN_COMMUNICATION_NONE, // Communication + &KSNODETYPE_SPEAKER, // Category + NULL, // Name + 0 // Reserved + } + } +}; + +//============================================================================= +static +KSJACK_DESCRIPTION SpeakerJackDescBridge = +{ + KSAUDIO_SPEAKER_STEREO, + 0xB3C98C, // Color spec for green + eConnTypeAtapiInternal, + eGeoLocFront, + eGenLocInternal, + ePortConnIntegratedDevice, + TRUE +}; + +// Only return a KSJACK_DESCRIPTION for the physical bridge pin. +static +PKSJACK_DESCRIPTION SpeakerJackDescriptions[] = +{ + NULL, + &SpeakerJackDescBridge +}; + +static +PCCONNECTION_DESCRIPTOR SpeakerTopoMiniportConnections[] = +{ + {PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST} //no volume controls +}; + +//============================================================================= +static +PCPROPERTY_ITEM PropertiesSpeakerTopoFilter[] = +{ + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_SpeakerTopoFilter + }, + { + &KSPROPSETID_Jack, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_TYPE_GET | + KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_SpeakerTopoFilter + } +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerTopoFilter, PropertiesSpeakerTopoFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR SpeakerTopoMiniportFilterDescriptor = +{ + 0, // Version + &AutomationSpeakerTopoFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(SpeakerTopoMiniportPins), // PinCount + SpeakerTopoMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(SpeakerTopoMiniportConnections), // ConnectionCount + SpeakerTopoMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories +}; + +#endif // _CSAUDIORK3X_SPEAKERTOPTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Filters/speakerwavtable.h b/drivers/audio/csaudiork3x/Source/Filters/speakerwavtable.h new file mode 100644 index 0000000..852da5a --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Filters/speakerwavtable.h @@ -0,0 +1,246 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + speakerwavtable.h + +Abstract: + + Declaration of wave miniport tables for the render endpoints. +--*/ + +#ifndef _CSAUDIORK3X_SPEAKERWAVTABLE_H_ +#define _CSAUDIORK3X_SPEAKERWAVTABLE_H_ + +// To keep the code simple assume device supports only 48KHz, 16-bit, stereo (PCM and NON-PCM) + +#define SPEAKER_DEVICE_MAX_CHANNELS 2 // Max Channels. + +#define SPEAKER_HOST_MAX_CHANNELS 2 // Max Channels. +#define SPEAKER_HOST_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample +#define SPEAKER_HOST_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample +#define SPEAKER_HOST_MIN_SAMPLE_RATE 48000 // Min Sample Rate +#define SPEAKER_HOST_MAX_SAMPLE_RATE 48000 // Max Sample Rate + +// +// Max # of pin instances. +// +#define SPEAKER_MAX_INPUT_SYSTEM_STREAMS 1 + +//============================================================================= + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE SpeakerHostPinSupportedDeviceFormats[] = +{ + { // 0 + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } + } +}; + +// +// Supported modes (only on streaming pins). +// +static +MODE_AND_DEFAULT_FORMAT SpeakerHostPinSupportedDeviceModes[] = +{ + { + STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT, + &SpeakerHostPinSupportedDeviceFormats[0].DataFormat // 48KHz + } +}; + +// +// The entries here must follow the same order as the filter's pin +// descriptor array. +// +static +PIN_DEVICE_FORMATS_AND_MODES SpeakerPinDeviceFormatsAndModes[] = +{ + { + SystemRenderPin, + SpeakerHostPinSupportedDeviceFormats, + SIZEOF_ARRAY(SpeakerHostPinSupportedDeviceFormats), + SpeakerHostPinSupportedDeviceModes, + SIZEOF_ARRAY(SpeakerHostPinSupportedDeviceModes) + }, + { + BridgePin, + NULL, + 0, + NULL, + 0 + } +}; + +//============================================================================= +static +KSDATARANGE_AUDIO SpeakerPinDataRangesStream[] = +{ + { // 0 + { + sizeof(KSDATARANGE_AUDIO), + KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + SPEAKER_HOST_MAX_CHANNELS, + SPEAKER_HOST_MIN_BITS_PER_SAMPLE, + SPEAKER_HOST_MAX_BITS_PER_SAMPLE, + SPEAKER_HOST_MIN_SAMPLE_RATE, + SPEAKER_HOST_MAX_SAMPLE_RATE + } +}; + +static +PKSDATARANGE SpeakerPinDataRangePointersStream[] = +{ + PKSDATARANGE(&SpeakerPinDataRangesStream[0]), + PKSDATARANGE(&PinDataRangeAttributeList), +}; + +//============================================================================= +static +KSDATARANGE SpeakerPinDataRangesBridge[] = +{ + { + sizeof(KSDATARANGE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) + } +}; + +static +PKSDATARANGE SpeakerPinDataRangePointersBridge[] = +{ + &SpeakerPinDataRangesBridge[0] +}; + +//============================================================================= +static +PCPIN_DESCRIPTOR SpeakerWaveMiniportPins[] = +{ + // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER3_SINK_SYSTEM + { + SPEAKER_MAX_INPUT_SYSTEM_STREAMS, + SPEAKER_MAX_INPUT_SYSTEM_STREAMS, + 0, + NULL, // AutomationTable + { + 0, + NULL, + 0, + NULL, + SIZEOF_ARRAY(SpeakerPinDataRangePointersStream), + SpeakerPinDataRangePointersStream, + KSPIN_DATAFLOW_IN, + KSPIN_COMMUNICATION_SINK, + &KSCATEGORY_AUDIO, + NULL, + 0 + } + }, + // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_RENDER3_SOURCE + { + 0, + 0, + 0, + NULL, + { + 0, + NULL, + 0, + NULL, + SIZEOF_ARRAY(SpeakerPinDataRangePointersBridge), + SpeakerPinDataRangePointersBridge, + KSPIN_DATAFLOW_OUT, + KSPIN_COMMUNICATION_NONE, + &KSCATEGORY_AUDIO, + NULL, + 0 + } + }, +}; + +//============================================================================= +// +// ---------------------------- +// | | +// Host Pin 0-->| |--> 1 KSPIN_WAVE_RENDER3_SOURCE +// | | +// ---------------------------- +static +PCCONNECTION_DESCRIPTOR SpeakerWaveMiniportConnections[] = +{ + { PCFILTER_NODE, KSPIN_WAVE_RENDER3_SINK_SYSTEM, PCFILTER_NODE, KSPIN_WAVE_RENDER3_SOURCE } +}; + +//============================================================================= +static +PCPROPERTY_ITEM PropertiesSpeakerWaveFilter[] = +{ + { + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PROPOSEDATAFORMAT, + KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_WaveFilter + }, + { + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PROPOSEDATAFORMAT2, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + PropertyHandler_WaveFilter + } +}; + +DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerWaveFilter, PropertiesSpeakerWaveFilter); + +//============================================================================= +static +PCFILTER_DESCRIPTOR SpeakerWaveMiniportFilterDescriptor = +{ + 0, // Version + &AutomationSpeakerWaveFilter, // AutomationTable + sizeof(PCPIN_DESCRIPTOR), // PinSize + SIZEOF_ARRAY(SpeakerWaveMiniportPins), // PinCount + SpeakerWaveMiniportPins, // Pins + sizeof(PCNODE_DESCRIPTOR), // NodeSize + 0, // NodeCount + NULL, // Nodes + SIZEOF_ARRAY(SpeakerWaveMiniportConnections), // ConnectionCount + SpeakerWaveMiniportConnections, // Connections + 0, // CategoryCount + NULL // Categories - use defaults (audio, render, capture) +}; + +#endif // _CSAUDIORK3X_SPEAKERWAVTABLE_H_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj b/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj new file mode 100644 index 0000000..35e6494 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj @@ -0,0 +1,79 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + + {4B664BA5-057A-41B8-B365-2C99065C4DFA} + $(MSBuildProjectName) + 1 + Debug + Win32 + {F51739CE-5253-42B5-9191-57F28B5842C6} + csaudio-Inc + $(LatestTargetPlatformVersion) + + + + Windows10 + Universal + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + true + + + + $(IntDir) + + + + + + + + csaudio-Inc + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(PreprocessorDefinitions);_USE_WAVERT_ + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;. + %(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_ + + + 4595;%(DisableSpecificWarnings) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(PreprocessorDefinitions);_USE_WAVERT_ + + + sha256 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj.Filters b/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj.Filters new file mode 100644 index 0000000..121a566 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/Inc.vcxproj.Filters @@ -0,0 +1,63 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {54BE0AAC-642F-4D50-80D1-CA3C4BB4BB4C} + + + h;hpp;hxx;hm;inl;inc;xsd + {6A00B9EC-DB03-4D51-B351-60DE9C0C51A1} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {887357BD-50C0-40E6-85E8-87E0F45862DB} + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Inc/NewDelete.h b/drivers/audio/csaudiork3x/Source/Inc/NewDelete.h new file mode 100644 index 0000000..5124992 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/NewDelete.h @@ -0,0 +1,104 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + +NewDelete.h + +Abstract: + +Declaration of placement new and delete operators. +--*/ +#pragma once + +#ifdef _NEW_DELETE_OPERATORS_ + +/***************************************************************************** +* Functions +*/ + +/***************************************************************************** +* ::new() +***************************************************************************** +* New function for creating objects with a specified allocation tag and +* pool type +*/ +PVOID operator new +( + size_t iSize, + POOL_TYPE poolType, + ULONG tag +); + + +/***************************************************************************** +* ::new() +***************************************************************************** +* New function for creating objects with a specified pool type. +*/ +PVOID operator new +( + size_t iSize, + POOL_TYPE poolType +); + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Delete with tag function. +*/ +void __cdecl operator delete +( + PVOID pVoid, + ULONG tag +); + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Sized Delete function. +*/ +void __cdecl operator delete +( + _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid, + _In_ size_t cbSize +); + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Basic Delete function. +*/ +void __cdecl operator delete +( + PVOID pVoid +); + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Sized Array Delete function. +*/ +void __cdecl operator delete[] +( + _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid, + _In_ size_t cbSize +); + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Array Delete function. +*/ +void __cdecl operator delete[] +( + _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid +); + +#endif//_NEW_DELETE_OPERATORS_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/basetopo.h b/drivers/audio/csaudiork3x/Source/Inc/basetopo.h new file mode 100644 index 0000000..4ea9268 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/basetopo.h @@ -0,0 +1,96 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + basetopo.h + +Abstract: + + Declaration of topology miniport. +--*/ + +#ifndef _CSAUDIORK3X_BASETOPO_H_ +#define _CSAUDIORK3X_BASETOPO_H_ + +//============================================================================= +// Classes +//============================================================================= + +/////////////////////////////////////////////////////////////////////////////// +// CMiniportTopologyCsAudioRk3x +// + +class CMiniportTopologyCsAudioRk3x +{ + protected: + PADAPTERCOMMON m_AdapterCommon; // Adapter common object. + PPCFILTER_DESCRIPTOR m_FilterDescriptor; // Filter descriptor. + PPORTEVENTS m_PortEvents; // Event interface. + USHORT m_DeviceMaxChannels; // Max device channels. + + public: + CMiniportTopologyCsAudioRk3x( + _In_ PCFILTER_DESCRIPTOR *FilterDesc, + _In_ USHORT DeviceMaxChannels + ); + + ~CMiniportTopologyCsAudioRk3x(); + + NTSTATUS GetDescription + ( + _Out_ PPCFILTER_DESCRIPTOR * Description + ); + + NTSTATUS 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 + ); + + NTSTATUS Init + ( + _In_ PUNKNOWN UnknownAdapter, + _In_ PPORTTOPOLOGY Port_ + ); + + // PropertyHandlers. + NTSTATUS PropertyHandlerGeneric + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + NTSTATUS PropertyHandlerMuxSource + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + NTSTATUS PropertyHandlerDevSpecific + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest + ); + + VOID AddEventToEventList + ( + _In_ PKSEVENT_ENTRY EventEntry + ); + + VOID GenerateEventList + ( + _In_opt_ GUID *Set, + _In_ ULONG EventId, + _In_ BOOL PinEvent, + _In_ ULONG PinId, + _In_ BOOL NodeEvent, + _In_ ULONG NodeId + ); +}; + +#endif diff --git a/drivers/audio/csaudiork3x/Source/Inc/common.h b/drivers/audio/csaudiork3x/Source/Inc/common.h new file mode 100644 index 0000000..fd9e52e --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/common.h @@ -0,0 +1,480 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + Common.h + +Abstract: + + CAdapterCommon class declaration. +--*/ + +#ifndef _CSAUDIORK3X_COMMON_H_ +#define _CSAUDIORK3X_COMMON_H_ + +#define HNSTIME_PER_MILLISECOND 10000 + +//============================================================================= +// Macros +//============================================================================= + +#define UNREFERENCED_VAR(status) \ + status = status + +//------------------------------------------------------------------------- +// Description: +// +// jump to the given label. +// +// Parameters: +// +// label - [in] label to jump if condition is met +// +#define JUMP(label) \ + goto label; + +//------------------------------------------------------------------------- +// Description: +// +// If the condition evaluates to TRUE, jump to the given label. +// +// Parameters: +// +// condition - [in] Code that fits in if statement +// label - [in] label to jump if condition is met +// +#define IF_TRUE_JUMP(condition, label) \ + if (condition) \ + { \ + goto label; \ + } + +//------------------------------------------------------------------------- +// Description: +// +// If the condition evaluates to TRUE, perform the given statement +// then jump to the given label. +// +// Parameters: +// +// condition - [in] Code that fits in if statement +// action - [in] action to perform in body of if statement +// label - [in] label to jump if condition is met +// +#define IF_TRUE_ACTION_JUMP(condition, action, label) \ + if (condition) \ + { \ + action; \ + goto label; \ + } + +//------------------------------------------------------------------------- +// Description: +// +// If the ntStatus is not NT_SUCCESS, perform the given statement then jump to +// the given label. +// +// Parameters: +// +// ntStatus - [in] Value to check +// action - [in] action to perform in body of if statement +// label - [in] label to jump if condition is met +// +#define IF_FAILED_ACTION_JUMP(ntStatus, action, label) \ + if (!NT_SUCCESS(ntStatus)) \ + { \ + action; \ + goto label; \ + } + +//------------------------------------------------------------------------- +// Description: +// +// If the ntStatus passed is not NT_SUCCESS, jump to the given label. +// +// Parameters: +// +// ntStatus - [in] Value to check +// label - [in] label to jump if condition is met +// +#define IF_FAILED_JUMP(ntStatus, label) \ + if (!NT_SUCCESS(ntStatus)) \ + { \ + goto label; \ + } + +#define SAFE_RELEASE(p) {if (p) { (p)->Release(); (p) = nullptr; } } +#define SAFE_DELETE_PTR_WITH_TAG(ptr, tag) if(ptr) { ExFreePoolWithTag((ptr), tag); (ptr) = NULL; } + +// JACKDESC_RGB(r, g, b) +#define JACKDESC_RGB(r, g, b) \ + ((COLORREF)((r << 16) | (g << 8) | (b))) + +// Min/Max defines. +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +#define MINWAVERT_POOLTAG 'RWNM' +#define MINTOPORT_POOLTAG 'RTNM' +#define MINADAPTER_POOLTAG 'uAyS' + +typedef enum +{ + eOutputDevice = 0, + eInputDevice, + eMaxDeviceType, +} eDeviceType; + +// +// Signal processing modes and default formats structs. +// +typedef struct _MODE_AND_DEFAULT_FORMAT { + GUID Mode; + KSDATAFORMAT* DefaultFormat; +} MODE_AND_DEFAULT_FORMAT, *PMODE_AND_DEFAULT_FORMAT; + +// +// Enumeration of the various types of pins implemented in this driver. +// +typedef enum +{ + NoPin, + BridgePin, + SystemRenderPin, + SystemCapturePin, +} PINTYPE; + +// +// PIN_DEVICE_FORMATS_AND_MODES +// +// Used to specify a pin's type (e.g. system, offload, etc.), formats, and +// modes. Conceptually serves similar purpose as the PCPIN_DESCRIPTOR to +// define a pin, but is more specific to driver implementation. +// +// Arrays of these structures follow the same order as the filter's +// pin descriptor array so that KS pin IDs can serve as an index. +// +typedef struct _PIN_DEVICE_FORMATS_AND_MODES +{ + PINTYPE PinType; + + KSDATAFORMAT_WAVEFORMATEXTENSIBLE * WaveFormats; + ULONG WaveFormatsCount; + + MODE_AND_DEFAULT_FORMAT * ModeAndDefaultFormat; + ULONG ModeAndDefaultFormatCount; + +} PIN_DEVICE_FORMATS_AND_MODES, *PPIN_DEVICE_FORMATS_AND_MODES; + +// forward declaration. +typedef struct _ENDPOINT_MINIPAIR *PENDPOINT_MINIPAIR; + +// both wave & topology miniport create function prototypes have this form: +typedef HRESULT (*PFNCREATEMINIPORT)( + _Out_ PUNKNOWN * Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType, + _In_ PUNKNOWN UnknownAdapter, + _In_opt_ PVOID DeviceContext, + _In_ PENDPOINT_MINIPAIR MiniportPair +); + +//============================================================================= +// +//============================================================================= +typedef struct _CSAUDIORK3X_DEVPROPERTY { + const DEVPROPKEY *PropertyKey; + DEVPROPTYPE Type; + ULONG BufferSize; + __field_bcount_opt(BufferSize) PVOID Buffer; +} CSAUDIORK3X_DEVPROPERTY, PCSAUDIORK3X_DEVPROPERTY; + +#define ENDPOINT_NO_FLAGS 0x00000000 +#define ENDPOINT_CELLULAR_PROVIDER1 0x00000008 +#define ENDPOINT_CELLULAR_PROVIDER2 0x00000010 + +// +// Endpoint miniport pair (wave/topology) descriptor. +// +typedef struct _ENDPOINT_MINIPAIR +{ + eDeviceType DeviceType; + + // Topology miniport. + PWSTR TopoName; // make sure this or the template name matches with CSAUDIORK3X..szPname in the inf's [Strings] section + PWSTR TemplateTopoName; // optional template name + PFNCREATEMINIPORT TopoCreateCallback; + PCFILTER_DESCRIPTOR* TopoDescriptor; + ULONG TopoInterfacePropertyCount; + const CSAUDIORK3X_DEVPROPERTY* TopoInterfaceProperties; + + // Wave RT miniport. + PWSTR WaveName; // make sure this or the template name matches with CSAUDIORK3X..szPname in the inf's [Strings] section + PWSTR TemplateWaveName; // optional template name + PFNCREATEMINIPORT WaveCreateCallback; + PCFILTER_DESCRIPTOR* WaveDescriptor; + ULONG WaveInterfacePropertyCount; + const CSAUDIORK3X_DEVPROPERTY* WaveInterfaceProperties; + + USHORT DeviceMaxChannels; + PIN_DEVICE_FORMATS_AND_MODES* PinDeviceFormatsAndModes; + ULONG PinDeviceFormatsAndModesCount; + + // Miniport physical connections. + PHYSICALCONNECTIONTABLE* PhysicalConnections; + ULONG PhysicalConnectionCount; + + // General endpoint flags (one of more ENDPOINT_, see above) + ULONG DeviceFlags; +} ENDPOINT_MINIPAIR; + +//============================================================================= +// Defines +//============================================================================= + +DEFINE_GUID(IID_IAdapterCommon, +0x7eda2950, 0xbf9f, 0x11d0, 0x87, 0x1f, 0x0, 0xa0, 0xc9, 0x11, 0xb5, 0x44); + +//============================================================================= +// Interfaces +//============================================================================= + +/////////////////////////////////////////////////////////////////////////////// +// IAdapterCommon +// +DECLARE_INTERFACE_(IAdapterCommon, IUnknown) +{ + STDMETHOD_(NTSTATUS, Init) + ( + THIS_ + _In_ PRESOURCELIST ResourceList, + _In_ PDEVICE_OBJECT DeviceObject + ) PURE; + + STDMETHOD_(PDEVICE_OBJECT, GetDeviceObject) + ( + THIS + ) PURE; + + STDMETHOD_(PDEVICE_OBJECT, GetPhysicalDeviceObject) + ( + THIS + ) PURE; + + STDMETHOD_(WDFDEVICE, GetWdfDevice) + ( + THIS + ) PURE; + + STDMETHOD_(VOID, SetWaveServiceGroup) + ( + THIS_ + _In_ PSERVICEGROUP ServiceGroup + ) PURE; + + STDMETHOD_(NTSTATUS, PrepareDMA) + ( + THIS_ + _In_ eDeviceType deviceType, + _In_ PMDL mdl, + _In_ IPortWaveRTStream * stream, + _In_ UINT32 byteCount + ) PURE; + + STDMETHOD_(NTSTATUS, StartDMA) + ( + THIS_ + _In_ eDeviceType deviceType + ) PURE; + STDMETHOD_(NTSTATUS, StopDMA) + ( + THIS_ + _In_ eDeviceType deviceType + ) PURE; + STDMETHOD_(NTSTATUS, CurrentPosition) + ( + THIS_ + _In_ eDeviceType deviceType, + _Out_ UINT32 * linkPos, + _Out_ UINT64 * linearPos + ) PURE; + STDMETHOD_(char *, GetTopology) + ( + THIS_ + _Out_ BOOLEAN *isJack + ) PURE; + + STDMETHOD_(BOOL, bDevSpecificRead) + ( + THIS_ + ) PURE; + + STDMETHOD_(VOID, bDevSpecificWrite) + ( + THIS_ + _In_ BOOL bDevSpecific + ); + + STDMETHOD_(INT, iDevSpecificRead) + ( + THIS_ + ) PURE; + + STDMETHOD_(VOID, iDevSpecificWrite) + ( + THIS_ + _In_ INT iDevSpecific + ); + + STDMETHOD_(UINT, uiDevSpecificRead) + ( + THIS_ + ) PURE; + + STDMETHOD_(VOID, uiDevSpecificWrite) + ( + THIS_ + _In_ UINT uiDevSpecific + ); + + STDMETHOD_(ULONG, MixerMuxRead) + ( + THIS + ); + + STDMETHOD_(VOID, MixerMuxWrite) + ( + THIS_ + _In_ ULONG Index + ); + + STDMETHOD_(LONG, MixerPeakMeterRead) + ( + THIS_ + _In_ ULONG Index, + _In_ ULONG Channel + ) PURE; + + STDMETHOD_(VOID, MixerReset) + ( + THIS + ) PURE; + + STDMETHOD_(NTSTATUS, WriteEtwEvent) + ( + THIS_ + _In_ EPcMiniportEngineEvent miniportEventType, + _In_ ULONGLONG ullData1, + _In_ ULONGLONG ullData2, + _In_ ULONGLONG ullData3, + _In_ ULONGLONG ullData4 + ) PURE; + + STDMETHOD_(VOID, SetEtwHelper) + ( + THIS_ + PPORTCLSETWHELPER _pPortClsEtwHelper + ) PURE; + + STDMETHOD_(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 CSAUDIORK3X_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 + ); + + STDMETHOD_(NTSTATUS, UnregisterSubdevice) + ( + THIS_ + _In_opt_ PUNKNOWN UnknownPort + ); + + STDMETHOD_(NTSTATUS, ConnectTopologies) + ( + THIS_ + _In_ PUNKNOWN UnknownTopology, + _In_ PUNKNOWN UnknownWave, + _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections, + _In_ ULONG PhysicalConnectionCount + ); + + STDMETHOD_(NTSTATUS, DisconnectTopologies) + ( + THIS_ + _In_ PUNKNOWN UnknownTopology, + _In_ PUNKNOWN UnknownWave, + _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections, + _In_ ULONG PhysicalConnectionCount + ); + + STDMETHOD_(NTSTATUS, InstallEndpointFilters) + ( + THIS_ + _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 + ); + + STDMETHOD_(NTSTATUS, RemoveEndpointFilters) + ( + THIS_ + _In_ PENDPOINT_MINIPAIR MiniportPair, + _In_opt_ PUNKNOWN UnknownTopology, + _In_opt_ PUNKNOWN UnknownWave + ); + + STDMETHOD_(NTSTATUS, GetFilters) + ( + THIS_ + _In_ PENDPOINT_MINIPAIR MiniportPair, + _Out_opt_ PUNKNOWN *UnknownTopologyPort, + _Out_opt_ PUNKNOWN *UnknownTopologyMiniport, + _Out_opt_ PUNKNOWN *UnknownWavePort, + _Out_opt_ PUNKNOWN *UnknownWaveMiniport + ); + + STDMETHOD_(NTSTATUS, SetIdlePowerManagement) + ( + THIS_ + _In_ PENDPOINT_MINIPAIR MiniportPair, + _In_ BOOL bEnable + ); + + STDMETHOD_(VOID, Cleanup)(); + +}; + +typedef IAdapterCommon *PADAPTERCOMMON; + +//============================================================================= +// Function Prototypes +//============================================================================= +NTSTATUS +NewAdapterCommon +( + _Out_ PUNKNOWN * Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType +); + +#endif //_CSAUDIORK3X_COMMON_H_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/definitions.h b/drivers/audio/csaudiork3x/Source/Inc/definitions.h new file mode 100644 index 0000000..a7c6fb7 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/definitions.h @@ -0,0 +1,198 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + Definitions.h + +Abstract: + + Header file for common stuff. +--*/ + +#ifndef _CSAUDIORK3X_DEFINITIONS_H_ +#define _CSAUDIORK3X_DEFINITIONS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "NewDelete.h" + +//============================================================================= +// Defines +//============================================================================= + +// Product Id +// {836BA6D1-3FF7-4411-8BCD-469553452DCE} +#define STATIC_PID_CSAUDIORK3X\ + 0x836ba6d1, 0x3ff7, 0x4411, 0x8b, 0xcd, 0x46, 0x95, 0x53, 0x45, 0x2d, 0xce +DEFINE_GUIDSTRUCT("836BA6D1-3FF7-4411-8BCD-469553452DCE", PID_CSAUDIORK3X); +#define PID_CSAUDIORK3X DEFINE_GUIDNAMED(PID_CSAUDIORK3X) + +// Pool tag used for CSAUDIORK3X allocations +#define CSAUDIORK3X_POOLTAG 'SASM' + +// Debug module name +#define STR_MODULENAME "CSAUDIORK3X: " + +// Debug utility macros +#define D_FUNC 4 +#define D_BLAB DEBUGLVL_BLAB +#define D_VERBOSE DEBUGLVL_VERBOSE +#define D_TERSE DEBUGLVL_TERSE +#define D_ERROR DEBUGLVL_ERROR +#define DPF _DbgPrintF +#define DPF_ENTER(x) DPF(D_FUNC, x) + +// Channel orientation +#define CHAN_LEFT 0 +#define CHAN_RIGHT 1 +#define CHAN_MASTER (-1) + +// Dma Settings. +#define DMA_BUFFER_SIZE 0x16000 + +#define KSPROPERTY_TYPE_ALL KSPROPERTY_TYPE_BASICSUPPORT | \ + KSPROPERTY_TYPE_GET | \ + KSPROPERTY_TYPE_SET + +// Specific node numbers +#define DEV_SPECIFIC_VT_BOOL 9 +#define DEV_SPECIFIC_VT_I4 10 +#define DEV_SPECIFIC_VT_UI4 11 + +#define _100NS_PER_MILLISECOND 10000 // number of 100ns units per millisecond + +// Default volume settings. +#define VOLUME_STEPPING_DELTA 0x8000 +#define VOLUME_SIGNED_MAXIMUM 0x00000000 +#define VOLUME_SIGNED_MINIMUM (-96 * 0x10000) + +// Default peak meter settings +#define PEAKMETER_STEPPING_DELTA 0x1000 +#define PEAKMETER_SIGNED_MAXIMUM LONG_MAX +#define PEAKMETER_SIGNED_MINIMUM LONG_MIN + +#define VALUE_NORMALIZE_P(v, step) \ + ((((v) + (step)/2) / (step)) * (step)) + +#define VALUE_NORMALIZE(v, step) \ + ((v) > 0 ? VALUE_NORMALIZE_P((v), (step)) : -(VALUE_NORMALIZE_P(-(v), (step)))) + +#define VALUE_NORMALIZE_IN_RANGE_EX(v, min, max, step) \ + ((v) > (max) ? (max) : \ + (v) < (min) ? (min) : \ + VALUE_NORMALIZE((v), (step))) + +// to normalize volume values. +#define VOLUME_NORMALIZE_IN_RANGE(v) \ + VALUE_NORMALIZE_IN_RANGE_EX((v), VOLUME_SIGNED_MINIMUM, VOLUME_SIGNED_MAXIMUM, VOLUME_STEPPING_DELTA) + +// to normalize sample peak meter. +#define PEAKMETER_NORMALIZE_IN_RANGE(v) \ + VALUE_NORMALIZE_IN_RANGE_EX((v), PEAKMETER_SIGNED_MINIMUM, PEAKMETER_SIGNED_MAXIMUM, PEAKMETER_STEPPING_DELTA) + +#define ALL_CHANNELS_ID UINT32_MAX + +// Macros to assist with pin instance counting +#define VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(status, allocated, max) \ + status = (allocated < max) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES + +#define ALLOCATE_PIN_INSTANCE_RESOURCES(allocated) \ + allocated++ + +#define FREE_PIN_INSTANCE_RESOURCES(allocated) \ + allocated-- + +// Define the value data type for supported sound detector patterns. Only +// one pattern type is supported in this sample. +typedef struct { + KSMULTIPLE_ITEM MultipleItem; + GUID PatternType[1]; +} CONTOSO_SUPPORTEDPATTERNSVALUE; + +//============================================================================= +// Typedefs +//============================================================================= + +// Flags to identify stream processing mode +typedef enum { + CONNECTIONTYPE_TOPOLOGY_OUTPUT = 0, + CONNECTIONTYPE_WAVE_OUTPUT = 1 +} CONNECTIONTYPE; + +// Connection table for registering topology/wave bridge connection +typedef struct _PHYSICALCONNECTIONTABLE +{ + ULONG ulTopology; + ULONG ulWave; + CONNECTIONTYPE eType; +} PHYSICALCONNECTIONTABLE, *PPHYSICALCONNECTIONTABLE; + +// +// This is the structure of the portclass FDO device extension Nt has created +// for us. We keep the adapter common object here. +// +struct IAdapterCommon; +typedef struct _PortClassDeviceContext // 32 64 Byte offsets for 32 and 64 bit architectures +{ + ULONG_PTR m_pulReserved1[2]; // 0-7 0-15 First two pointers are reserved. + PDEVICE_OBJECT m_DoNotUsePhysicalDeviceObject; // 8-11 16-23 Reserved pointer to our Physical Device Object (PDO). + PVOID m_pvReserved2; // 12-15 24-31 Reserved pointer to our Start Device function. + PVOID m_pvReserved3; // 16-19 32-39 "Out Memory" according to DDK. + IAdapterCommon* m_pCommon; // 20-23 40-47 Pointer to our adapter common object. + PVOID m_pvUnused1; // 24-27 48-55 Unused space. + PVOID m_pvUnused2; // 28-31 56-63 Unused space. + + // Anything after above line should not be used. + // This actually goes on for (64*sizeof(ULONG_PTR)) but it is all opaque. +} PortClassDeviceContext; + +// +// Major/MinorTarget to object casting. +// +#define MajorTarget_to_Obj(ptr) \ + reinterpret_cast(ptr) + +#define MinorTarget_to_Obj(ptr) \ + static_cast(reinterpret_cast(ptr)) + +// +// Global settings. +// +extern DWORD g_DoNotCreateDataFiles; +extern DWORD g_DisableBthScoBypass; +extern UNICODE_STRING g_RegistryPath; + +//============================================================================= +// Function prototypes +//============================================================================= + +// Generic topology handler +NTSTATUS PropertyHandler_Topology +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +); + +// Default WaveFilter automation table. +// Handles the GeneralComponentId request. +NTSTATUS PropertyHandler_WaveFilter +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +); + +NTSTATUS PropertyHandler_GenericPin +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +); + +// common.h uses some of the above definitions. +#include "common.h" +#include "kshelper.h" + +#endif // _CSAUDIORK3X_DEFINITIONS_H_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/endpoints.h b/drivers/audio/csaudiork3x/Source/Inc/endpoints.h new file mode 100644 index 0000000..cdab242 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/endpoints.h @@ -0,0 +1,133 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + endpoints.h + +Abstract: + + Node and Pin numbers and other common definitions for simple audio sample. +--*/ + +#ifndef _CSAUDIORK3X_ENDPOINTS_H_ +#define _CSAUDIORK3X_ENDPOINTS_H_ + +// Name Guid +// {0104947F-82AE-4291-A6F3-5E2DE1AD7DC2} +#define STATIC_NAME_SIMPLE_AUDIO_SAMPLE\ + 0x104947f, 0x82ae, 0x4291, 0xa6, 0xf3, 0x5e, 0x2d, 0xe1, 0xad, 0x7d, 0xc2 +DEFINE_GUIDSTRUCT("0104947F-82AE-4291-A6F3-5E2DE1AD7DC2", NAME_SIMPLE_AUDIO_SAMPLE); +#define NAME_SIMPLE_AUDIO_SAMPLE DEFINE_GUIDNAMED(NAME_SIMPLE_AUDIO_SAMPLE) + +//---------------------------------------------------- +// New defines for the render endpoints. +//---------------------------------------------------- + +// Default pin instances. +#define MAX_INPUT_SYSTEM_STREAMS 1 + +// Wave pins - no mix, no offload +enum +{ + KSPIN_WAVE_RENDER3_SINK_SYSTEM = 0, + KSPIN_WAVE_RENDER3_SOURCE +}; + +// Wave pins - offloading is NOT supported. +enum +{ + KSPIN_WAVE_RENDER2_SINK_SYSTEM = 0, + KSPIN_WAVE_RENDER2_SINK_LOOPBACK, + KSPIN_WAVE_RENDER2_SOURCE +}; + +// Wave Topology nodes - offloading is NOT supported. +enum +{ + KSNODE_WAVE_SUM = 0, + KSNODE_WAVE_VOLUME, + KSNODE_WAVE_MUTE, + KSNODE_WAVE_PEAKMETER +}; + +// Topology pins. +enum +{ + KSPIN_TOPO_WAVEOUT_SOURCE = 0, + KSPIN_TOPO_LINEOUT_DEST, +}; + +// Topology nodes. +enum +{ + KSNODE_TOPO_WAVEOUT_VOLUME = 0, + KSNODE_TOPO_WAVEOUT_MUTE, + KSNODE_TOPO_WAVEOUT_PEAKMETER +}; + +//---------------------------------------------------- +// New defines for the capture endpoints. +//---------------------------------------------------- + +// Default pin instances. +#define MAX_INPUT_STREAMS 1 // Number of capture streams. + +// Wave pins +enum +{ + KSPIN_WAVE_BRIDGE = 0, + KSPIN_WAVEIN_HOST, +}; + +// Wave Topology nodes. +enum +{ + KSNODE_WAVE_ADC = 0 +}; + +// Wave Topology nodes. +enum +{ + KSNODE_WAVE_DAC = 0 +}; + +// topology pins. +enum +{ + KSPIN_TOPO_MIC_ELEMENTS, + KSPIN_TOPO_BRIDGE +}; + +// topology nodes. +enum +{ + KSNODE_TOPO_VOLUME, + KSNODE_TOPO_MUTE, + KSNODE_TOPO_PEAKMETER +}; + +// data format attribute range definitions. +static +KSATTRIBUTE PinDataRangeSignalProcessingModeAttribute = +{ + sizeof(KSATTRIBUTE), + 0, + STATICGUIDOF(KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE), +}; + +static +PKSATTRIBUTE PinDataRangeAttributes[] = +{ + &PinDataRangeSignalProcessingModeAttribute, +}; + +static +KSATTRIBUTE_LIST PinDataRangeAttributeList = +{ + ARRAYSIZE(PinDataRangeAttributes), + PinDataRangeAttributes, +}; + +#endif // _CSAUDIORK3X_ENDPOINTS_H_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/kshelper.h b/drivers/audio/csaudiork3x/Source/Inc/kshelper.h new file mode 100644 index 0000000..10e5c01 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/kshelper.h @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + kshelper.h + +Abstract: + + Helper functions for simple audio sample +--*/ +#ifndef _CSAUDIORK3X_KSHELPER_H_ +#define _CSAUDIORK3X_KSHELPER_H_ + +#include +#include + +PWAVEFORMATEX +GetWaveFormatEx +( + _In_ PKSDATAFORMAT pDataFormat +); + +NTSTATUS +ValidatePropertyParams +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG cbValueSize, + _In_ ULONG cbInstanceSize = 0 +); + +NTSTATUS +PropertyHandler_BasicSupport +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG Flags, + _In_ DWORD PropTypeSetId +); + +NTSTATUS +PropertyHandler_BasicSupportPeakMeter2 +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG MaxChannels +); + +NTSTATUS +PropertyHandler_CpuResources +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +); + +NTSTATUS +PropertyHandler_PeakMeter2 +( + _In_ PADAPTERCOMMON AdapterCommon, + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG MaxChannels +); + +//============================================================================= +// Property helpers +//============================================================================= + +NTSTATUS +CsAudioRk3xPropertyDispatch +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +); + +// Use this structure to define property items with extra data allowing easier +// definition of separate get, set, and support handlers dispatched through +// CsAudioRk3xPropertyDispatch. +typedef struct +{ + PCPROPERTY_ITEM PropertyItem; // Standard PCPROPERTY_ITEM + ULONG MinProperty; // Minimum size of the property instance data + ULONG MinData; // Minimum size of the property value + PCPFNPROPERTY_HANDLER GetHandler; // Property get handler (NULL if GET not supported) + PCPFNPROPERTY_HANDLER SetHandler; // Property set handler (NULL if SET not supported) + PCPFNPROPERTY_HANDLER SupportHandler; // Property support handler (NULL for common handler) + VOID *ContextData; // Optional context information for the handler, NULL for unused + ULONG ContextDataSize; // Size of the data held at ContextData, 0 for unused +} CSAUDIORK3X_PROPERTY_ITEM; + +// The following macros facilitate adding property handlers to a class, allowing +// easier declaration and definition of a "thunk" routine that directly handles +// the property request and calls into a class instance method. Note that as +// written, the thunk routine assumes PAGED_CODE. +#define DECLARE_CLASSPROPERTYHANDLER(theClass, theMethod) \ +NTSTATUS theClass##_##theMethod \ +( \ + _In_ PPCPROPERTY_REQUEST PropertyRequest \ +); + +#define DECLARE_PROPERTYHANDLER(theMethod) \ +NTSTATUS theMethod \ +( \ + _In_ PPCPROPERTY_REQUEST PropertyRequest \ +); + +#define DEFINE_CLASSPROPERTYHANDLER(theClass, theMethod) \ +NTSTATUS theClass##_##theMethod \ +( \ + _In_ PPCPROPERTY_REQUEST PropertyRequest \ +) \ +{ \ + NTSTATUS status; \ + \ + PAGED_CODE(); \ + \ + theClass* p = reinterpret_cast(PropertyRequest->MajorTarget); \ + \ + p->AddRef(); \ + status = p->theMethod(PropertyRequest); \ + p->Release(); \ + \ + return status; \ +} \ +NTSTATUS theClass::theMethod \ +( \ + _In_ PPCPROPERTY_REQUEST PropertyRequest \ +) + + + + +#endif // _CSAUDIORK3X_KSHELPER_H_ diff --git a/drivers/audio/csaudiork3x/Source/Inc/mintopo.h b/drivers/audio/csaudiork3x/Source/Inc/mintopo.h new file mode 100644 index 0000000..b3a5333 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Inc/mintopo.h @@ -0,0 +1,81 @@ + +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + minitopo.h + +Abstract: + + Declaration of topology miniport. +--*/ + +#ifndef _CSAUDIORK3X_MINTOPO_H_ +#define _CSAUDIORK3X_MINTOPO_H_ + +#include "basetopo.h" + +//============================================================================= +// Classes +//============================================================================= + +/////////////////////////////////////////////////////////////////////////////// +// CMiniportTopology +// + +class CMiniportTopology : + public CMiniportTopologyCsAudioRk3x, + public IMiniportTopology, + public CUnknown +{ + private: + eDeviceType m_DeviceType; + + union { + PVOID m_DeviceContext; + }; + +public: + DECLARE_STD_UNKNOWN(); + CMiniportTopology + ( + _In_opt_ PUNKNOWN UnknownOuter, + _In_ PCFILTER_DESCRIPTOR *FilterDesc, + _In_ USHORT DeviceMaxChannels, + _In_ eDeviceType DeviceType, + _In_opt_ PVOID DeviceContext + ) + : CUnknown(UnknownOuter), + CMiniportTopologyCsAudioRk3x(FilterDesc, DeviceMaxChannels), + m_DeviceType(DeviceType), + m_DeviceContext(DeviceContext) + { + } + + ~CMiniportTopology(); + + IMP_IMiniportTopology; + + NTSTATUS PropertyHandlerJackDescription + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG cJackDescriptions, + _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions + ); + + NTSTATUS PropertyHandlerJackDescription2 + ( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG cJackDescriptions, + _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions, + _In_ DWORD JackCapabilities + ); + + PVOID GetDeviceContext() { return m_DeviceContext; } +}; + +typedef CMiniportTopology *PCMiniportTopology; + +#endif // _CSAUDIORK3X_MINTOPO_H_ diff --git a/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj b/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj new file mode 100644 index 0000000..b8a8682 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj @@ -0,0 +1,130 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + + {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF} + $(MSBuildProjectName) + 1 + Debug + Win32 + {2A9A946E-F017-4E0D-BF75-AD81E7E97D64} + $(LatestTargetPlatformVersion) + csaudiork3x + + + + Windows10 + Universal + KMDF + WindowsKernelModeDriver10.0 + Driver + Spectre + + + true + + + + + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION + %(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + true + Level4 + %(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION + %(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION + %(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE + + + sha256 + + + + csaudiork3x + + + + %(AdditionalDependencies);$(OutDir)\csaudio-Utilities.lib + + + %(AdditionalDependencies);$(OutDir)\csaudio-Filters.lib + + + + %(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_;POOL_ZERO_DOWN_LEVEL_SUPPORT + %(AdditionalIncludeDirectories);..\Utilities;. + %(AdditionalIncludeDirectories);..\Filters;. + %(AdditionalIncludeDirectories);..\Inc;..\..\..\..\include;. + + + + + %(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower + %(AdditionalIncludeDirectories);..\Utilities + %(AdditionalIncludeDirectories);..\Filters + %(AdditionalIncludeDirectories);..\Inc + + + %(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower + %(AdditionalIncludeDirectories);..\Utilities + %(AdditionalIncludeDirectories);..\Filters + %(AdditionalIncludeDirectories);..\Inc + + + 1.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj.Filters b/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj.Filters new file mode 100644 index 0000000..8dd848e --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/Main.vcxproj.Filters @@ -0,0 +1,80 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {7FE326AE-6214-4FE0-A27B-F229A098BDBC} + + + h;hpp;hxx;hm;inl;inc;xsd + {64C16D2B-849C-4264-A615-18A8E8AC9505} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {46FAF4E8-F18C-4797-9CFA-2F3473BCB316} + + + inf;inv;inx;mof;mc; + {EE8F0A00-C1F0-4CB4-80E3-5FCC378E0BF4} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Header Files + + + + + Driver Files + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Main/NewDelete.cpp b/drivers/audio/csaudiork3x/Source/Main/NewDelete.cpp new file mode 100644 index 0000000..8d74c06 --- /dev/null +++ b/drivers/audio/csaudiork3x/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 +} +#else +#include +#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_TYPE poolType, + ULONG tag +) +{ + PVOID result = ExAllocatePoolZero(poolType, iSize, tag); + + return result; +} + + +/***************************************************************************** +* ::new() +***************************************************************************** +* New function for creating objects with a specified allocation tag. +*/ +PVOID operator new +( + size_t iSize, + POOL_TYPE poolType +) +{ + PVOID result = ExAllocatePoolZero(poolType, iSize, CSAUDIORK3X_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, CSAUDIORK3X_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, CSAUDIORK3X_POOLTAG); + } +} + + +/***************************************************************************** +* ::delete() +***************************************************************************** +* Array Delete function. +*/ +void __cdecl operator delete[] +( + _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid +) +{ + if (pVoid) + { + ExFreePoolWithTag(pVoid, CSAUDIORK3X_POOLTAG); + } +} +#endif//_NEW_DELETE_OPERATORS_ diff --git a/drivers/audio/csaudiork3x/Source/Main/adapter.cpp b/drivers/audio/csaudiork3x/Source/Main/adapter.cpp new file mode 100644 index 0000000..af1f0c4 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/adapter.cpp @@ -0,0 +1,707 @@ +/*++ + +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; + +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") +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; + + // + // Default to NonPagedPoolNx for non paged pool allocations where supported. + // + + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); + + DPF(D_TERSE, ("[DriverEntry]")); + + 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; + + char *topologyName = _pAdapterCommon->GetTopology(NULL); + if (strcmp(topologyName, "hdmi") == 0) { + ppAeMiniports = g_RenderHDMIEndpoints; + } + + 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); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + PADAPTERCOMMON pAdapterCommon = NULL; + PUNKNOWN pUnknownCommon = NULL; + PortClassDeviceContext* pExtension = static_cast(DeviceObject->DeviceExtension); + + DPF_ENTER(("[StartDevice]")); + + // + // create a new adapter common object + // + ntStatus = NewAdapterCommon( + &pUnknownCommon, + IID_IAdapterCommon, + NULL, + NonPagedPool + ); + IF_FAILED_JUMP(ntStatus, Exit); + + ntStatus = pUnknownCommon->QueryInterface( IID_IAdapterCommon,(PVOID *) &pAdapterCommon); + IF_FAILED_JUMP(ntStatus, Exit); + + ntStatus = pAdapterCommon->Init(ResourceList, 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); + + BOOLEAN isJack; + pAdapterCommon->GetTopology(&isJack); + if (isJack) { + // + // 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(_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/drivers/audio/csaudiork3x/Source/Main/basetopo.cpp b/drivers/audio/csaudiork3x/Source/Main/basetopo.cpp new file mode 100644 index 0000000..62dc366 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/basetopo.cpp @@ -0,0 +1,674 @@ +/*++ + +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") +CMiniportTopologyCsAudioRk3x::CMiniportTopologyCsAudioRk3x +( + _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; +} // CMiniportTopologyCsAudioRk3x + +CMiniportTopologyCsAudioRk3x::~CMiniportTopologyCsAudioRk3x +( + void +) +/*++ + +Routine Description: + + Topology miniport destructor + +Arguments: + +Return Value: + + void + +--*/ +{ + PAGED_CODE(); + + DPF_ENTER(("[%s]",__FUNCTION__)); + + SAFE_RELEASE(m_AdapterCommon); + SAFE_RELEASE(m_PortEvents); +} // ~CMiniportTopologyCsAudioRk3x + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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(("[CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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_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 +CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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 +CMiniportTopologyCsAudioRk3x::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(("[CMiniportTopologyCsAudioRk3x::GenerateEventList]")); + + ASSERT(m_PortEvents != NULL); + + m_PortEvents->GenerateEventList( + Set, + EventId, + PinEvent, + PinId, + NodeEvent, + NodeId); +} + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Main/common.cpp b/drivers/audio/csaudiork3x/Source/Main/common.cpp new file mode 100644 index 0000000..bc9d72a --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/common.cpp @@ -0,0 +1,2689 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + common.cpp + +Abstract: + + Implementation of the AdapterCommon class. +--*/ + +#pragma warning (disable : 4127) + +#include +#include "definitions.h" +#include "hw.h" +#include "endpoints.h" + +//============================================================================= +// 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; + + PCCsAudioRk3xHW m_pHW; // HW object + PPORTCLSETWHELPER m_pPortClsEtwHelper; + + DWORD m_dwIdleRequests; + + //===================================================================== + // Default CUnknown + DECLARE_STD_UNKNOWN(); + DEFINE_STD_CONSTRUCTOR(CAdapterCommon); + ~CAdapterCommon(); + + //===================================================================== + // Default IAdapterPowerManagement + IMP_IAdapterPowerManagement; + + //===================================================================== + // IAdapterCommon methods + + STDMETHODIMP_(NTSTATUS) Init + ( + _In_ PRESOURCELIST ResourceList, + _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_(NTSTATUS) PrepareDMA( + _In_ eDeviceType deviceType, + _In_ PMDL mdl, + _In_ IPortWaveRTStream* stream, + _In_ UINT32 byteCount + ); + + STDMETHODIMP_(NTSTATUS) StartDMA( + _In_ eDeviceType deviceType + ); + STDMETHODIMP_(NTSTATUS) StopDMA( + _In_ eDeviceType deviceType + ); + STDMETHODIMP_(NTSTATUS) CurrentPosition( + _In_ eDeviceType deviceType, + _Out_ UINT32* linkPos, + _Out_ UINT64* linearPos + ); + STDMETHODIMP_(char*) GetTopology( + _Out_ BOOLEAN* isJack + ); + + 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_(ULONG) MixerMuxRead(void); + + STDMETHODIMP_(void) MixerMuxWrite + ( + _In_ ULONG Index + ); + + STDMETHODIMP_(void) MixerReset(void); + + 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 CSAUDIORK3X_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_TYPE PoolType + ); + +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 CSAUDIORK3X_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 + + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS CsAudioRk3xIoSetDeviceInterfacePropertyDataMultiple +( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ ULONG cPropertyCount, + _In_reads_opt_(cPropertyCount) const CSAUDIORK3X_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_TYPE PoolType +) +/*++ + +Routine Description: + + Creates a new CAdapterCommon + +Arguments: + + Unknown - + + UnknownOuter - + + PoolType + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + ASSERT(Unknown); + + NTSTATUS ntStatus; + + // + // Allocate an adapter object. + // + CAdapterCommon *p = new(PoolType, 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) + { + m_pHW->rk3x_deinit(); + delete m_pHW; + m_pHW = NULL; + } + + SAFE_RELEASE(m_pPortClsEtwHelper); + SAFE_RELEASE(m_pServiceGroupWave); + + if (m_WdfDevice) + { + WdfObjectDelete(m_WdfDevice); + m_WdfDevice = NULL; + } +} // ~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_ PRESOURCELIST ResourceList, + _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]")); + UNREFERENCED_PARAMETER(ResourceList); + + 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); + + RKDSP_BUS_INTERFACE RKdspInterface; + ntStatus = WdfFdoQueryForInterface(m_WdfDevice, &GUID_RKDSP_BUS_INTERFACE, (PINTERFACE)&RKdspInterface, sizeof(RKdspInterface), 1, NULL); + if (!NT_SUCCESS(ntStatus)) { + DPF(D_TERSE, ("Unable to query RKdsp Interface")); + } + IF_FAILED_JUMP(ntStatus, Done); + + // Initialize HW. + // + m_pHW = new (NonPagedPool, CSAUDIORK3X_POOLTAG) CCsAudioRk3xHW(&RKdspInterface, m_WdfDevice); + if (!m_pHW) + { + DPF(D_TERSE, ("Insufficient memory for Rockchip I2S HW")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + IF_FAILED_JUMP(ntStatus, Done); + + if (!m_pHW->ResourcesValidated()) + { + DPF(D_TERSE, ("Insufficient resources for Rockchip I2S HW")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + IF_FAILED_JUMP(ntStatus, Done); + + ntStatus = m_pHW->rk3x_init(); + if (!NT_SUCCESS(ntStatus)) + { + DPF(D_TERSE, ("Unable to in initialize Rockchip I2S")); + } + IF_FAILED_JUMP(ntStatus, Done); + + m_pHW->MixerReset(); +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_(NTSTATUS) +CAdapterCommon::PrepareDMA( + _In_ eDeviceType deviceType, + _In_ PMDL mdl, + _In_ IPortWaveRTStream* stream, + _In_ UINT32 byteCount +) { + if (m_pHW) { + return m_pHW->rk3x_program_dma(deviceType, mdl, stream, byteCount); + } + return STATUS_NO_SUCH_DEVICE; +} + +//============================================================================= +#pragma code_seg() +STDMETHODIMP_(NTSTATUS) +CAdapterCommon::StartDMA( + _In_ eDeviceType deviceType +) { + if (m_pHW) { + return m_pHW->rk3x_play(deviceType); + } + return STATUS_NO_SUCH_DEVICE; +} + +//============================================================================= +#pragma code_seg() +STDMETHODIMP_(NTSTATUS) +CAdapterCommon::StopDMA( + _In_ eDeviceType deviceType +) { + if (m_pHW) { + return m_pHW->rk3x_stop(deviceType); + } + return STATUS_NO_SUCH_DEVICE; +} + +//============================================================================= +#pragma code_seg() +STDMETHODIMP_(NTSTATUS) +CAdapterCommon::CurrentPosition( + _In_ eDeviceType deviceType, + _Out_ UINT32* linkPos, + _Out_ UINT64* linearPos +) { + if (m_pHW) { + return m_pHW->rk3x_current_position(deviceType, linkPos, linearPos); + } + return STATUS_NO_SUCH_DEVICE; +} + +//============================================================================= +#pragma code_seg() +STDMETHODIMP_(char*) +CAdapterCommon::GetTopology( + _Out_ BOOLEAN* isJack +) { + if (m_pHW) { + if (isJack) + *isJack = m_pHW->isJack; + return m_pHW->rkTPLG.audio_tplg; + } + return ""; +} + +//============================================================================= +#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_(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::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; +} // MixerPeakMeterRead + +//============================================================================= +#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) + { + DPF + ( + D_VERBOSE, + ("Entering D%u", ULONG(NewState.DeviceState) - ULONG(PowerDeviceD0)) + ); + // switch on new state + // + switch (NewState.DeviceState) + { + case PowerDeviceD0: + m_pHW->rk3x_init(); + break; + case PowerDeviceD1: + case PowerDeviceD2: + break; + case PowerDeviceD3: + m_pHW->rk3x_deinit(); + break; + default: + + DPF(D_VERBOSE, ("Unknown Device Power State")); + break; + } + m_PowerState = NewState.DeviceState; + } +} // 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 CSAUDIORK3X_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 = CsAudioRk3xIoSetDeviceInterfacePropertyDataMultiple(AudioSymbolicLinkName, cPropertyCount, pProperties); + + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: CsAudioRk3xIoSetDeviceInterfacePropertyDataMultiple(...): 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 CSAUDIORK3X_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, + NonPagedPool, + 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(NonPagedPool, 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 CSAUDIORK3X..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 CSAUDIORK3X..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)ExAllocatePoolZero(NonPagedPool, 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)ExAllocatePoolZero(NonPagedPool, 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)ExAllocatePoolZero(NonPagedPool, 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)ExAllocatePoolZero(NonPagedPool, 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)ExAllocatePoolZero(NonPagedPool, 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)ExAllocatePoolZero(NonPagedPool, 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/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.inx b/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.inx new file mode 100644 index 0000000..d096410 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.inx @@ -0,0 +1,315 @@ +[Version] +Signature = "$Windows NT$" +Class = MEDIA +Provider = %ProviderName% +ClassGUID = {4d36e96c-e325-11ce-bfc1-08002be10318} +CatalogFile = csaudiork3x.cat +PnpLockDown = 1 + +[SourceDisksNames] +222="CAAUDIORK3X Driver Disk","",222 + +[SourceDisksFiles] +csaudiork3x.sys=222 + +[SignatureAttributes] +csaudiork3x.sys=SignatureAttributes.DRM + +[SignatureAttributes.DRM] +DRMLevel=1300 + +[SignatureAttributes.PETrust] +PETrust=true + +[Manufacturer] +%MfgName%=CAAUDIORK3X,NT$ARCH$ + +[CAAUDIORK3X.NT$ARCH$] +%CAAUDIORK3X_SA.DeviceDesc%=CAAUDIORK3X_SA, CSAUDIO\RK&CLTR + +[DestinationDirs] +CAAUDIORK3X_SA.CopyList=13 ; 13=Package's DriverStore directory + +;====================================================== +; CAAUDIORK3X_SA +;====================================================== +[CAAUDIORK3X_SA.CopyList] +csaudiork3x.sys + +[CAAUDIORK3X_SA.AddReg] +HKR,,AssociatedFilters,,"wdmaud,swmidi,redbook" +HKR,,Driver,,csaudiork3x.sys + +; +; For demo only, please review these power management settings for your architecture. +; +HKR,PowerSettings,SingleComponentMultiFxStates,3,1,0,0,0 ; Turn on multi Fx support. +HKR,PowerSettings,ConservationIdleTime,3,3,0,0,0 ; 3 seconds for idle power management when on battery +HKR,PowerSettings,PerformanceIdleTime,3,3,0,0,0 ; 3 seconds for idle power management when on AC power +HKR,PowerSettings,IdlePowerState,3,3,0,0,0 ; go to D3 for idle power management + +HKR,Drivers,SubClasses,,"wave,midi,mixer" + +HKR,Drivers\wave\wdmaud.drv,Driver,,wdmaud.drv +HKR,Drivers\midi\wdmaud.drv,Driver,,wdmaud.drv +HKR,Drivers\mixer\wdmaud.drv,Driver,,wdmaud.drv + +HKR,Drivers\wave\wdmaud.drv,Description,,%CAAUDIORK3X_SA.DeviceDesc% +HKR,Drivers\mixer\wdmaud.drv,Description,,%CAAUDIORK3X_SA.DeviceDesc% + +;====================================================== +; capture interfaces: mic array (internal: front) +;====================================================== +[CAAUDIORK3X.I.WaveMicArray1] +AddReg=CAAUDIORK3X.I.WaveMicArray1.AddReg +[CAAUDIORK3X.I.WaveMicArray1.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.WaveMicArray1.szPname% + +[CAAUDIORK3X.I.TopologyMicArray1] +AddReg=CAAUDIORK3X.I.TopologyMicArray1.AddReg + +[CAAUDIORK3X.I.TopologyMicArray1.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.TopologyMicArray1.szPname% + +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% + +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +;====================================================== +; capture interfaces: mic (jack) +;====================================================== +[CAAUDIORK3X.I.WaveMicJack] +AddReg=CAAUDIORK3X.I.WaveMicJack.AddReg +[CAAUDIORK3X.I.WaveMicJack.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.WaveMicJack.szPname% + +[CAAUDIORK3X.I.TopologyMicJack] +AddReg=CAAUDIORK3X.I.TopologyMicJack.AddReg + +[CAAUDIORK3X.I.TopologyMicJack.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.TopologyMicJack.szPname% + +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% + +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +;====================================================== +; render interfaces: speaker (internal) +;====================================================== +[CAAUDIORK3X.I.WaveSpeaker] +AddReg=CAAUDIORK3X.I.WaveSpeaker.AddReg + +[CAAUDIORK3X.I.WaveSpeaker.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.WaveSpeaker.szPname% + +[CAAUDIORK3X.I.TopologySpeaker] +AddReg=CAAUDIORK3X.I.TopologySpeaker.AddReg + +[CAAUDIORK3X.I.TopologySpeaker.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.TopologySpeaker.szPname% + +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% + +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + + +;====================================================== +; render interfaces: headphones (jack) +;====================================================== +[CAAUDIORK3X.I.WaveHeadphones] +AddReg=CAAUDIORK3X.I.WaveHeadphones.AddReg + +[CAAUDIORK3X.I.WaveHeadphones.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.WaveHeadphones.szPname% + +[CAAUDIORK3X.I.TopologyHeadphones] +AddReg=CAAUDIORK3X.I.TopologyHeadphones.AddReg + +[CAAUDIORK3X.I.TopologyHeadphones.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.TopologyHeadphones.szPname% + +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% + +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +;====================================================== +; render interfaces: hdmi +;====================================================== +[CAAUDIORK3X.I.WaveHdmi] +AddReg=CAAUDIORK3X.I.WaveHdmi.AddReg + +[CAAUDIORK3X.I.WaveHdmi.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.WaveHdmi.szPname% + +[CAAUDIORK3X.I.TopologyHdmi] +AddReg=CAAUDIORK3X.I.TopologyHdmi.AddReg + +[CAAUDIORK3X.I.TopologyHdmi.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%CAAUDIORK3X.TopologyHdmi.szPname% + +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% + +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +;====================================================== +; CAAUDIORK3X_SA +;====================================================== +[CAAUDIORK3X_SA.NT] +Include=ks.inf,wdmaudio.inf +Needs=KS.Registration, WDMAUDIO.Registration +CopyFiles=CAAUDIORK3X_SA.CopyList +AddReg=CAAUDIORK3X_SA.AddReg + +[CAAUDIORK3X_SA.NT.Interfaces] +; +; Interfaces for speaker (internal) render endpoint. +; +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_WaveSpeaker%, CAAUDIORK3X.I.WaveSpeaker +AddInterface=%KSCATEGORY_RENDER%, %KSNAME_WaveSpeaker%, CAAUDIORK3X.I.WaveSpeaker +AddInterface=%KSCATEGORY_REALTIME%, %KSNAME_WaveSpeaker%, CAAUDIORK3X.I.WaveSpeaker +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_TopologySpeaker%, CAAUDIORK3X.I.TopologySpeaker +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_TopologySpeaker%, CAAUDIORK3X.I.TopologySpeaker + +; +; Interfaces for headphone (internal) render endpoint. +; +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_WaveHeadphones%, CAAUDIORK3X.I.WaveHeadphones +AddInterface=%KSCATEGORY_RENDER%, %KSNAME_WaveHeadphones%, CAAUDIORK3X.I.WaveHeadphones +AddInterface=%KSCATEGORY_REALTIME%, %KSNAME_WaveHeadphones%, CAAUDIORK3X.I.WaveHeadphones +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_TopologyHeadphones%, CAAUDIORK3X.I.TopologyHeadphones +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_TopologyHeadphones%, CAAUDIORK3X.I.TopologyHeadphones + +; +; Interfaces for hdmi render endpoint. +; +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_WaveHdmi%, CAAUDIORK3X.I.WaveHdmi +AddInterface=%KSCATEGORY_RENDER%, %KSNAME_WaveHdmi%, CAAUDIORK3X.I.WaveHdmi +AddInterface=%KSCATEGORY_REALTIME%, %KSNAME_WaveHdmi%, CAAUDIORK3X.I.WaveHdmi +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_TopologyHdmi%, CAAUDIORK3X.I.TopologyHdmi +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_TopologyHdmi%, CAAUDIORK3X.I.TopologyHdmi + +; +; Interfaces for microphone array 1 (internal: front) capture endpoint. +; +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_WaveMicArray1%, CAAUDIORK3X.I.WaveMicArray1 +AddInterface=%KSCATEGORY_REALTIME%, %KSNAME_WaveMicArray1%, CAAUDIORK3X.I.WaveMicArray1 +AddInterface=%KSCATEGORY_CAPTURE%, %KSNAME_WaveMicArray1%, CAAUDIORK3X.I.WaveMicArray1 +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_TopologyMicArray1%, CAAUDIORK3X.I.TopologyMicArray1 +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_TopologyMicArray1%, CAAUDIORK3X.I.TopologyMicArray1 + +; +; Interfaces for microphone array 1 (internal: front) capture endpoint. +; +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_WaveMicJack%, CAAUDIORK3X.I.WaveMicJack +AddInterface=%KSCATEGORY_REALTIME%, %KSNAME_WaveMicJack%, CAAUDIORK3X.I.WaveMicJack +AddInterface=%KSCATEGORY_CAPTURE%, %KSNAME_WaveMicJack%, CAAUDIORK3X.I.WaveMicJack +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_TopologyMicJack%, CAAUDIORK3X.I.TopologyMicJack +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_TopologyMicJack%, CAAUDIORK3X.I.TopologyMicJack + +[CAAUDIORK3X_SA.NT.Services] +AddService=CsAudioRk3x,0x00000002,CsAudioRk3x_Service_Inst + +[CsAudioRk3x_Service_Inst] +DisplayName=%CsAudioRk3x.SvcDesc% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%13%\csaudiork3x.sys + +[CAAUDIORK3X_SA.NT.HW] +AddReg = AUDIOHW.AddReg + +[AUDIOHW.AddReg] +; FILE_DEVICE_SOUND +HKR,,DeviceType,0x10001,0x0000001D +; SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)" + + +;====================================================== +; WDF +;====================================================== +[CAAUDIORK3X_SA.NT.Wdf] +KmdfService = CsAudioRk3x, CAAUDIORK3X_SA_WdfSect +[CAAUDIORK3X_SA_WdfSect] +KmdfLibraryVersion = $KMDFVERSION$ + +;====================================================== +; COMMON +;====================================================== +[Strings] + +;Non-localizable + +KSNAME_WaveSpeaker="WaveSpeaker" +KSNAME_TopologySpeaker="TopologySpeaker" + +KSNAME_WaveHeadphones="WaveHeadphones" +KSNAME_TopologyHeadphones="TopologyHeadphones" + +KSNAME_WaveHdmi="WaveHdmi" +KSNAME_TopologyHdmi="TopologyHdmi" + +KSNAME_WaveMicArray1="WaveMicArray1" +KSNAME_TopologyMicArray1="TopologyMicArray1" + +KSNAME_WaveMicJack="WaveMicJack" +KSNAME_TopologyMicJack="TopologyMicJack" + +Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}" +KSCATEGORY_AUDIO="{6994AD04-93EF-11D0-A3CC-00A0C9223196}" +KSCATEGORY_RENDER="{65E8773E-8F56-11D0-A3B9-00A0C9223196}" +KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}" +KSCATEGORY_REALTIME ="{EB115FFC-10C8-4964-831D-6DCB02E6F23F}" +KSCATEGORY_TOPOLOGY = "{DDA54A40-1E4C-11D1-A050-405705C10000}" + +KSNODETYPE_ANY = "{00000000-0000-0000-0000-000000000000}" + +PKEY_AudioEndpoint_Association = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},2" +PKEY_AudioEndpoint_Supports_EventDriven_Mode = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},7" + +MEDIA_CATEGORIES = "MediaCategories" +MicArray1CustomNameGUID = {6ae81ff4-203e-4fe1-88aa-f2d57775cd4a} + +;Localizable + +ProviderName = "CoolStar" +MfgName = "Rockchip" +MsCopyRight = "(C) 2023, CoolStar" + +CAAUDIORK3X_SA.DeviceDesc="Rockchip I2S Audio (WDM)" +CsAudioRk3x.SvcDesc="Rockchip I2S Audio (WDM)" + +;; friendly names +CAAUDIORK3X.WaveSpeaker.szPname="Rockchip Speaker" +CAAUDIORK3X.TopologySpeaker.szPname="Rockchip Speaker" + +CAAUDIORK3X.WaveHeadphones.szPname="Rockchip Headphones" +CAAUDIORK3X.TopologyHeadphones.szPname="Rockchip Headphones" + +CAAUDIORK3X.WaveHdmi.szPname="Rockchip HDMI" +CAAUDIORK3X.TopologyHdmi.szPname="Rockchip HDMI" + +CAAUDIORK3X.WaveMicArray1.szPname="Rockchip Microphone Array - Front" +CAAUDIORK3X.TopologyMicArray1.szPname="Rockchip Topology Microphone Array - Front" + +CAAUDIORK3X.WaveMicJack.szPname="Rockchip Microphone" +CAAUDIORK3X.TopologyMicJack.szPname="Rockchip Topology Microphone" + +MicArray1CustomName= "Internal Microphone Array - Front" + diff --git a/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.rc b/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.rc new file mode 100644 index 0000000..7ad967c --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/csaudiork3x.rc @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + CsAudioRk3x.rc + +Abstract: + +--*/ + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SOUND +#define VER_FILEDESCRIPTION_STR "CoolStar I2S Audio (Rockchip 3xxx)" +#define VER_INTERNALNAME_STR "CsAudioRk3x.sys" +#define VER_ORIGINALFILENAME_STR "CsAudioRk3x.sys" + +#define VER_LEGALCOPYRIGHT_YEARS "2023" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." + +#define VER_FILEVERSION 1,0,0,0 +#define VER_PRODUCTVERSION_STR "1.0.0.0" +#define VER_PRODUCTVERSION 1,0,0,0 +#define LVER_PRODUCTVERSION_STR L"1.0.0.0" + +#define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) +#ifdef DEBUG +#define VER_FILEFLAGS (VS_FF_DEBUG) +#else +#define VER_FILEFLAGS (0) +#endif + +#define VER_FILEOS VOS_NT_WINDOWS32 + +#define VER_COMPANYNAME_STR "CoolStar" +#define VER_PRODUCTNAME_STR "CoolStar I2S Audio" + +#include "common.ver" + + diff --git a/drivers/audio/csaudiork3x/Source/Main/mintopo.cpp b/drivers/audio/csaudiork3x/Source/Main/mintopo.cpp new file mode 100644 index 0000000..a4db784 --- /dev/null +++ b/drivers/audio/csaudiork3x/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 +CreateMiniportTopologyCsAudioRk3x +( + _Out_ PUNKNOWN * Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType, + _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 (PoolType, MINWAVERT_POOLTAG) + CMiniportTopology( UnknownOuter, + MiniportPair->TopoDescriptor, + MiniportPair->DeviceMaxChannels, + MiniportPair->DeviceType, + DeviceContext ); + if (NULL == obj) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + obj->AddRef(); + *Unknown = reinterpret_cast(obj); + + return STATUS_SUCCESS; +} // CreateMiniportTopologyCsAudioRk3x + +//============================================================================= +#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 + CMiniportTopologyCsAudioRk3x::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 CMiniportTopologyCsAudioRk3x::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 = + CMiniportTopologyCsAudioRk3x::Init + ( + UnknownAdapter, + Port_ + ); + + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("Init: CMiniportTopologyCsAudioRk3x::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/drivers/audio/csaudiork3x/Source/Main/minwavert.cpp b/drivers/audio/csaudiork3x/Source/Main/minwavert.cpp new file mode 100644 index 0000000..0823293 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/minwavert.cpp @@ -0,0 +1,1703 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + minwavert.cpp + +Abstract: + + Implementation of wavert miniport. +--*/ + +#pragma warning (disable : 4127) + +#include "definitions.h" +#include +#include "endpoints.h" +#include "minwavert.h" +#include "minwavertstream.h" +#include "micarraywavtable.h" + +#define EFFECTS_LIST_COUNT 2 + +//============================================================================= +// CMiniportWaveRT +//============================================================================= + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CreateMiniportWaveRTCsAudioRk3x +( + _Out_ PUNKNOWN * Unknown, + _In_ REFCLSID, + _In_opt_ PUNKNOWN UnknownOuter, + _In_ POOL_TYPE PoolType, + _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 (PoolType, MINWAVERT_POOLTAG) CMiniportWaveRT + ( + UnknownAdapter, + MiniportPair, + DeviceContext + ); + if (NULL == obj) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + obj->AddRef(); + *Unknown = reinterpret_cast(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_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; + } + + if (m_pAdapterCommon) { + SAFE_RELEASE(m_pAdapterCommon); + } + +} // ~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/jack pins, set ResultantFormat to be the endpoint's only supported format. + //Otherwise, allow the class handler to set ResultantFormat. + if ((this->m_DeviceType) == eInputDevice) + { + 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_pMixFormat = NULL; + m_pDeviceFormat = NULL; + m_ulMixDrmContentId = 0; + 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 *)ExAllocatePoolZero(NonPagedPool, 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 (NonPagedPool, 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 = ACPIBus; + 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 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]")); + + ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated); + + if (IsSystemCapturePin(_Pin)) + { + return STATUS_SUCCESS; + } + else if (IsSystemRenderPin(_Pin)) + { + streams = m_SystemStreams; + count = m_ulMaxSystemStreams; + + } + + // + // Cache this stream's ptr. + // + if (streams != NULL) + { + ULONG i = 0; + for (; iCount; 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(_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(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(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; iDefaultFormat != 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; iMode == 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 (NonPagedPool, 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(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() +NTSTATUS +CMiniportWaveRT::AcquireDMA(_In_ PCMiniportWaveRTStream _Stream, UINT32 byteCount) { + if (!m_pAdapterCommon) { + return STATUS_NO_SUCH_DEVICE; + } + return m_pAdapterCommon->PrepareDMA(m_DeviceType, _Stream->m_pMDL, _Stream->m_pPortStream, byteCount); +} + +NTSTATUS +CMiniportWaveRT::StartDMA() { + if (!m_pAdapterCommon) { + return STATUS_NO_SUCH_DEVICE; + } + return m_pAdapterCommon->StartDMA(m_DeviceType); +} + +NTSTATUS +CMiniportWaveRT::StopDMA() { + if (!m_pAdapterCommon) { + return STATUS_NO_SUCH_DEVICE; + } + return m_pAdapterCommon->StopDMA(m_DeviceType); +} + +NTSTATUS +CMiniportWaveRT::CurrentPosition(UINT32* linkPos, UINT64* linearPos) { + if (!m_pAdapterCommon) { + return STATUS_NO_SUCH_DEVICE; + } + return m_pAdapterCommon->CurrentPosition(m_DeviceType, linkPos, linearPos); +} + +#pragma code_seg() diff --git a/drivers/audio/csaudiork3x/Source/Main/minwavert.h b/drivers/audio/csaudiork3x/Source/Main/minwavert.h new file mode 100644 index 0000000..1b781bd --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/minwavert.h @@ -0,0 +1,261 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + minwavert.h + +Abstract: + + Definition of wavert miniport class. +--*/ + +#ifndef _CSAUDIOACP3X_MINWAVERT_H_ +#define _CSAUDIOACP3X_MINWAVERT_H_ + +//============================================================================= +// Referenced Forward +//============================================================================= +class CMiniportWaveRTStream; +class CAdapterCommon; +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; + + 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 AcquireDMA( + _In_ PCMiniportWaveRTStream _Stream, + _In_ UINT32 byteCount + ); + + NTSTATUS StartDMA(); + + NTSTATUS StopDMA(); + + NTSTATUS CurrentPosition(UINT32* linkPos, UINT64* linearPos); + + 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; + if (m_pAdapterCommon) + m_pAdapterCommon->AddRef(); + + 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 CMiniportTopologyCsAudioAcp3x; + + 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 (PADAPTERCOMMON)m_pAdapterCommon; + }; +#pragma code_seg() + +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 == eOutputDevice); + } + + 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 // _CSAUDIOACP3X_MINWAVERT_H_ diff --git a/drivers/audio/csaudiork3x/Source/Main/minwavertstream.cpp b/drivers/audio/csaudiork3x/Source/Main/minwavertstream.cpp new file mode 100644 index 0000000..95c03a1 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/minwavertstream.cpp @@ -0,0 +1,525 @@ +#include "definitions.h" +#include +#include +#include "endpoints.h" +#include "minwavert.h" +#include "minwavertstream.h" +#include "rk3x.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_pWfExt) + { + ExFreePoolWithTag( m_pWfExt, MINWAVERTSTREAM_POOLTAG ); + m_pWfExt = 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::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(); + UNREFERENCED_PARAMETER(SignalProcessingMode); + + PWAVEFORMATEX pWfEx = NULL; + NTSTATUS ntStatus = STATUS_SUCCESS; + + m_pMiniport = NULL; + m_ulPin = 0; + m_bUnregisterStream = FALSE; + m_bCapture = FALSE; + m_ulDmaBufferSize = 0; + m_KsState = KSSTATE_STOP; + m_ulDmaMovementRate = 0; + m_pWfExt = NULL; + m_ulContentId = 0; + + m_pPortStream = PortStream_; + + // Initialize the spinlock to synchronize position updates + KeInitializeSpinLock(&m_PositionSpinLock); + + pWfEx = GetWaveFormatEx(DataFormat_); + if (NULL == pWfEx) + { + return STATUS_UNSUCCESSFUL; + } + + m_pMiniport = reinterpret_cast(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_pWfExt = (PWAVEFORMATEXTENSIBLE)ExAllocatePoolZero(NonPagedPool, sizeof(WAVEFORMATEX) + pWfEx->cbSize, MINWAVERTSTREAM_POOLTAG); + if (m_pWfExt == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(m_pWfExt, pWfEx, sizeof(WAVEFORMATEX) + pWfEx->cbSize); + + if (m_bCapture) + { + + //Initialize Capture hardware + } + else + { + //Initialize Render hardware + } + + // + // 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_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::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 = FIFO_SIZE; +} + +//============================================================================= +#pragma code_seg("PAGE") +VOID CMiniportWaveRTStream::FreeAudioBuffer +( +_In_opt_ PMDL Mdl_, +_In_ ULONG Size_ +) +{ + UNREFERENCED_PARAMETER(Size_); + + PAGED_CODE(); + + if (Mdl_ != NULL) + { + m_pPortStream->FreePagesFromMdl(Mdl_); + } + + m_ulDmaBufferSize = 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 zeroAddress = { 0 }; + + PHYSICAL_ADDRESS highAddress; + highAddress.HighPart = 0; + highAddress.LowPart = MAXULONG; + + PMDL pBufferMdl = m_pPortStream->AllocateContiguousPagesForMdl(zeroAddress, highAddress, RequestedSize_); + + if (NULL == pBufferMdl) + { + return STATUS_UNSUCCESSFUL; + } + + m_pMDL = pBufferMdl; + + m_ulDmaBufferSize = RequestedSize_; + + *AudioBufferMdl_ = pBufferMdl; + *ActualSize_ = RequestedSize_; + *OffsetFromFirstPage_ = 0; + *CacheType_ = MmNonCached; + + return STATUS_SUCCESS; +} + +//============================================================================= +#pragma code_seg() +NTSTATUS CMiniportWaveRTStream::GetPosition +( + _Out_ KSAUDIO_POSITION *Position_ +) +{ + NTSTATUS ntStatus; + + KIRQL oldIrql; + KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql); + + UINT64 linearPos; + m_pMiniport->CurrentPosition(NULL, &linearPos); + Position_->PlayOffset = linearPos; + Position_->WriteOffset = linearPos + FIFO_SIZE; + + KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); + + ntStatus = STATUS_SUCCESS; + + return ntStatus; +} + +//============================================================================= +#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); + + m_pMiniport->StopDMA(); + if (!NT_SUCCESS(ntStatus)) { + return ntStatus; + } + + KeReleaseSpinLock(&m_PositionSpinLock, oldIrql); + break; + + case KSSTATE_ACQUIRE: + if (m_KsState == KSSTATE_STOP) + { + // Acquire stream resources + } + break; + + case KSSTATE_PAUSE: + m_pMiniport->CurrentPosition(&m_lastLinkPos, &m_lastLinearPos); + m_pMiniport->StopDMA(); + break; + + case KSSTATE_RUN: + // Start DMA + ntStatus = m_pMiniport->AcquireDMA(this, m_ulDmaBufferSize); + if (!NT_SUCCESS(ntStatus)) { + return ntStatus; + } + + m_pMiniport->StartDMA(); + if (!NT_SUCCESS(ntStatus)) { + return ntStatus; + } + + 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("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(); + UNREFERENCED_PARAMETER(drmRights); + + 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; + } + + // + // 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 + diff --git a/drivers/audio/csaudiork3x/Source/Main/minwavertstream.h b/drivers/audio/csaudiork3x/Source/Main/minwavertstream.h new file mode 100644 index 0000000..2d577a6 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Main/minwavertstream.h @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + minwavertstream.h + +Abstract: + + Definition of wavert miniport class. +--*/ + +#ifndef _CSAUDIOACP3X_MINWAVERTSTREAM_H_ +#define _CSAUDIOACP3X_MINWAVERTSTREAM_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 IMiniportWaveRTStream, + public IDrmAudioStream, + public CUnknown +{ +public: + PPORTWAVERTSTREAM m_pPortStream; + PMDL m_pMDL; + + DECLARE_STD_UNKNOWN(); + DEFINE_STD_CONSTRUCTOR(CMiniportWaveRTStream); + ~CMiniportWaveRTStream(); + + IMP_IMiniportWaveRTStream; + 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; +protected: + CMiniportWaveRT* m_pMiniport; + ULONG m_ulPin; + BOOLEAN m_bCapture; + BOOLEAN m_bUnregisterStream; + ULONG m_ulDmaBufferSize; + KSSTATE m_KsState; + ULONG m_ulDmaMovementRate; + PWAVEFORMATEXTENSIBLE m_pWfExt; + ULONG m_ulContentId; + KSPIN_LOCK m_PositionSpinLock; + UINT32 m_lastLinkPos; + UINT64 m_lastLinearPos; + +}; +typedef CMiniportWaveRTStream *PCMiniportWaveRTStream; +#endif // _CSAUDIOACP3X_MINWAVERTSTREAM_H_ + diff --git a/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj b/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj new file mode 100644 index 0000000..25accdc --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj @@ -0,0 +1,90 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + + {33E61864-6F2C-4F9F-BE70-8F8985A4F283} + $(MSBuildProjectName) + 1 + Debug + Win32 + {F51739CE-5253-42B5-9191-57F28B5842C6} + csaudio-Utilities + $(LatestTargetPlatformVersion) + + + + Windows10 + Universal + KMDF + WindowsKernelModeDriver10.0 + StaticLibrary + + + true + + + + $(IntDir) + + + + + + + + csaudio-Utilities + + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(AdditionalIncludeDirectories);..\Inc + %(PreprocessorDefinitions);_USE_WAVERT_ + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;. + %(AdditionalIncludeDirectories);..\Inc;..\..\..\..\include;. + %(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_ + + + 4595;%(DisableSpecificWarnings) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);.. + %(AdditionalIncludeDirectories);..\Inc + %(PreprocessorDefinitions);_USE_WAVERT_ + + + sha256 + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj.Filters b/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj.Filters new file mode 100644 index 0000000..393518d --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/Utilities.vcxproj.Filters @@ -0,0 +1,55 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {CDBBEDA3-98E9-4C7A-BDB1-25EC47D0B087} + + + h;hpp;hxx;hm;inl;inc;xsd + {FA3DF57E-BA19-4783-831B-CF9D4D594F70} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {CB830E4F-01DA-4D35-9789-E7DB0D02A79C} + + + inf;inv;inx;mof;mc; + {49F92783-3B39-4D0C-A153-8C346F754749} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Utilities/adsp.h b/drivers/audio/csaudiork3x/Source/Utilities/adsp.h new file mode 100644 index 0000000..2f4bd19 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/adsp.h @@ -0,0 +1,51 @@ +// +// The GUID_RKDSP_BUS_INTERFACE interface GUID +// +// {863DD2AC-5B54-4C57-8487-782F9ADFE8D7} +DEFINE_GUID(GUID_RKDSP_BUS_INTERFACE, + 0x863dd2ac, 0x5b54, 0x4c57, 0x84, 0x87, 0x78, 0x2f, 0x9a, 0xdf, 0xe8, 0xd7); + +#define RKTPLG_MAGIC '$RKC' + +typedef struct _RK_TPLG { + UINT32 magic; + UINT32 length; + char dma_name[32]; + UINT32 tx; + UINT32 rx; + char audio_tplg[32]; +} RK_TPLG, *PRK_TPLG; + +typedef struct _TPLG_INFO { + PVOID rkTplg; + UINT64 rkTplgSz; +} TPLG_INFO, * PTPLG_INFO; + +typedef _Must_inspect_result_ NTSTATUS(*PGET_ADSP_RESOURCES) (_In_ PVOID _context, _Out_ _PCI_BAR* acpBar, PTPLG_INFO tplgInfo); +typedef _Must_inspect_result_ NTSTATUS(*PDSP_SET_POWER_STATE) (_In_ PVOID _context, _In_ DEVICE_POWER_STATE newPowerState); +typedef _Must_inspect_result_ BOOL(*PADSP_INTERRUPT_CALLBACK)(PVOID context); +typedef VOID(*PADSP_DPC_CALLBACK)(PVOID context); +typedef _Must_inspect_result_ NTSTATUS(*PADSP_QUEUE_DPC)(PVOID context); +typedef _Must_inspect_result_ NTSTATUS(*PREGISTER_ADSP_INTERRUPT) (_In_ PVOID _context, _In_ PADSP_INTERRUPT_CALLBACK callback, _In_ PADSP_DPC_CALLBACK dpcCallback, _In_ PVOID callbackContext); +typedef _Must_inspect_result_ NTSTATUS(*PUNREGISTER_ADSP_INTERRUPT) (_In_ PVOID _context); + +typedef struct _RKDSP_BUS_INTERFACE +{ + // + // First we define the standard INTERFACE structure ... + // + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; + + // + // Then we expand the structure with the ADSP_BUS_INTERFACE stuff. + + PGET_ADSP_RESOURCES GetResources; + PDSP_SET_POWER_STATE SetDSPPowerState; + PREGISTER_ADSP_INTERRUPT RegisterInterrupt; + PUNREGISTER_ADSP_INTERRUPT UnregisterInterrupt; + PADSP_QUEUE_DPC QueueDPCForInterrupt; +} RKDSP_BUS_INTERFACE, * PRKDSP_BUS_INTERFACE; \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Utilities/csaudioapi.cpp b/drivers/audio/csaudiork3x/Source/Utilities/csaudioapi.cpp new file mode 100644 index 0000000..a81d60e --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/csaudioapi.cpp @@ -0,0 +1,104 @@ +#include "definitions.h" +#include "hw.h" + +VOID CsAudioCallbackFunction( + CCsAudioRk3xHW* hw, + CsAudioArg* arg, + PVOID Argument2 +) { + if (!hw) { + return; + } + + if (Argument2 == &hw->CsAudioArg2) { + return; + } + + CsAudioArg localArg; + RtlZeroMemory(&localArg, sizeof(CsAudioArg)); + RtlCopyMemory(&localArg, arg, min(arg->argSz, sizeof(CsAudioArg))); + + hw->CSAudioAPICalled(localArg); +} + +NTSTATUS CCsAudioRk3xHW::CSAudioAPIInit() { + NTSTATUS status; + + UNICODE_STRING CSAudioCallbackAPI; + RtlInitUnicodeString(&CSAudioCallbackAPI, L"\\CallBack\\CsAudioCallbackAPI"); + + + OBJECT_ATTRIBUTES attributes; + InitializeObjectAttributes(&attributes, + &CSAudioCallbackAPI, + OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, + NULL, + NULL + ); + status = ExCreateCallback(&this->CSAudioAPICallback, &attributes, TRUE, TRUE); + if (!NT_SUCCESS(status)) { + return status; + } + + this->CSAudioAPICallbackObj = ExRegisterCallback(this->CSAudioAPICallback, + (PCALLBACK_FUNCTION)CsAudioCallbackFunction, + this + ); + if (!this->CSAudioAPICallbackObj) { + + return STATUS_NO_CALLBACK_ACTIVE; + } + + CsAudioArg arg; + RtlZeroMemory(&arg, sizeof(CsAudioArg)); + arg.argSz = sizeof(CsAudioArg); + arg.endpointType = CSAudioEndpointTypeDSP; + arg.endpointRequest = CSAudioEndpointRegister; + ExNotifyCallback(this->CSAudioAPICallback, &arg, &CsAudioArg2); + + return status; +} + +NTSTATUS CCsAudioRk3xHW::CSAudioAPIDeinit() { + if (this->CSAudioAPICallbackObj) { + ExUnregisterCallback(this->CSAudioAPICallbackObj); + this->CSAudioAPICallbackObj = NULL; + } + + if (this->CSAudioAPICallback) { + ObfDereferenceObject(this->CSAudioAPICallback); + this->CSAudioAPICallback = NULL; + } + return STATUS_SUCCESS; +} + +void CCsAudioRk3xHW::CSAudioAPICalled(CsAudioArg arg) { + if (arg.endpointRequest == CSAudioEndpointRegister) { + CsAudioArg newArg; + RtlZeroMemory(&newArg, sizeof(CsAudioArg)); + newArg.argSz = sizeof(CsAudioArg); + newArg.endpointType = arg.endpointType; + newArg.endpointRequest = CSAudioEndpointStop; + ExNotifyCallback(this->CSAudioAPICallback, &newArg, &CsAudioArg2); + } +} + +CSAudioEndpointType CCsAudioRk3xHW::GetCSAudioEndpoint(eDeviceType deviceType) { + switch (deviceType) { + case eOutputDevice: + return CSAudioEndpointTypeHeadphone; + case eInputDevice: + return CSAudioEndpointTypeMicJack; + } + return CSAudioEndpointTypeDSP; +} + +eDeviceType CCsAudioRk3xHW::GetDeviceType(CSAudioEndpointType endpointType) { + switch (endpointType) { + case CSAudioEndpointTypeHeadphone: + return eOutputDevice; + case CSAudioEndpointTypeMicJack: + return eInputDevice; + } + return eOutputDevice; +} \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Utilities/dma.cpp b/drivers/audio/csaudiork3x/Source/Utilities/dma.cpp new file mode 100644 index 0000000..71ecb58 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/dma.cpp @@ -0,0 +1,71 @@ +#include "definitions.h" +#include "hw.h" + +NTSTATUS CCsAudioRk3xHW::connectDMA() { + WDF_OBJECT_ATTRIBUTES objectAttributes; + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = this->m_wdfDevice; + + WDFIOTARGET ioTarget; + + NTSTATUS status = WdfIoTargetCreate(this->m_wdfDevice, + &objectAttributes, + &ioTarget + ); + if (!NT_SUCCESS(status)) + { + DbgPrint("Error creating IoTarget object - 0x%x\n", + status); + if (ioTarget) + WdfObjectDelete(ioTarget); + return status; + } + + DECLARE_UNICODE_STRING_SIZE(busDosDeviceName, 25); + status = RtlUnicodeStringPrintf(&busDosDeviceName, L"\\DosDevices\\%hs", this->rkTPLG.dma_name); + if (!NT_SUCCESS(status)) { + DbgPrint("Error building symbolic link name - %!STATUS!", + status); + + return status; + } + + WDF_IO_TARGET_OPEN_PARAMS openParams; + WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( + &openParams, + &busDosDeviceName, + (GENERIC_READ | GENERIC_WRITE)); + + openParams.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE; + openParams.CreateDisposition = FILE_OPEN; + openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; + + PL330DMA_INTERFACE_STANDARD DmaInterface; + RtlZeroMemory(&DmaInterface, sizeof(DmaInterface)); + + status = WdfIoTargetOpen(ioTarget, &openParams); + if (!NT_SUCCESS(status)) + { + DbgPrint("Error opening IoTarget object - 0x%x\n", + status); + WdfObjectDelete(ioTarget); + return status; + } + + status = WdfIoTargetQueryForInterface(ioTarget, + &GUID_PL330DMA_INTERFACE_STANDARD, + (PINTERFACE)&DmaInterface, + sizeof(DmaInterface), + 1, + NULL); + WdfIoTargetClose(ioTarget); + ioTarget = NULL; + if (!NT_SUCCESS(status)) { + DbgPrint("WdfFdoQueryForInterface failed 0x%x\n", status); + return status; + } + + this->m_DMAInterface = DmaInterface; + return status; +} \ No newline at end of file diff --git a/drivers/audio/csaudiork3x/Source/Utilities/hw.cpp b/drivers/audio/csaudiork3x/Source/Utilities/hw.cpp new file mode 100644 index 0000000..7d8ad40 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/hw.cpp @@ -0,0 +1,751 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + hw.cpp + +Abstract: + + Implementation of Simple Audio Sample HW class. + Simple Audio Sample HW has an array for storing mixer and volume settings + for the topology. +--*/ +#include "definitions.h" +#include "hw.h" + +BOOL I2SInterrupt(PVOID pHW) { + CCsAudioRk3xHW* hw = (CCsAudioRk3xHW*)pHW; + + return hw->rk3x_irq(); +} + +//============================================================================= +// CCsAudioRk3xHW +//============================================================================= + +//============================================================================= +#pragma code_seg("PAGE") +CCsAudioRk3xHW::CCsAudioRk3xHW( + _In_ PRKDSP_BUS_INTERFACE RKdspInterface, + _In_ WDFDEVICE wdfDevice +) +: m_ulMux(0), + m_bDevSpecific(FALSE), + m_iDevSpecific(0), + m_uiDevSpecific(0) +/*++ + +Routine Description: + + Constructor for CsAudioRk3xHW. + +Arguments: + +Return Value: + + void + +--*/ +{ + PAGED_CODE(); + +#if USERKHW + TPLG_INFO tplgInfo = { 0 }; + + RKdspInterface->GetResources(RKdspInterface->Context, &m_MMIO, &tplgInfo); + + RtlZeroMemory(&this->outputStream, sizeof(this->outputStream)); + RtlZeroMemory(&this->inputStream, sizeof(this->inputStream)); + + m_rkdspInterface = *RKdspInterface; + m_wdfDevice = wdfDevice; + + this->m_rkdspInterface.RegisterInterrupt(this->m_rkdspInterface.Context, &I2SInterrupt, NULL, this); + + if (tplgInfo.rkTplg && tplgInfo.rkTplgSz > offsetof(RK_TPLG, length)) { + PRK_TPLG rawSofTplg = (PRK_TPLG)tplgInfo.rkTplg; + if (rawSofTplg->magic == RKTPLG_MAGIC) { + RtlCopyMemory(&this->rkTPLG, tplgInfo.rkTplg, min(tplgInfo.rkTplgSz, sizeof(RK_TPLG))); + } + this->rkTPLG.magic = RKTPLG_MAGIC; + this->rkTPLG.length = sizeof(RK_TPLG); + } +#endif + + MixerReset(); +} // CsAudioRk3xHW +#pragma code_seg() + +bool CCsAudioRk3xHW::ResourcesValidated() { + if (!m_MMIO.Base.Base) + return false; + + if (!NT_SUCCESS(connectDMA())) + return false; + + this->isJack = (strcmp(this->rkTPLG.audio_tplg, JACK_TPLG) == 0); + + if (this->isJack) { + if (!NT_SUCCESS(this->CSAudioAPIInit())) + return false; + } + + return true; +} + +CCsAudioRk3xHW::~CCsAudioRk3xHW() { + this->m_rkdspInterface.UnregisterInterrupt(this->m_rkdspInterface.Context); + + this->CSAudioAPIDeinit(); +} + +#if USERKHW +static UINT32 read32(PVOID addr) { + UINT32 ret = *(UINT32*)addr; + //DbgPrint("Read from %p: 0x%x\n", addr, ret); + return ret; +} + +static void write32(PVOID addr, UINT32 data) { + *(UINT32*)addr = data; + //DbgPrint("Write to %p: 0x%x\n", addr, data); +} + +UINT32 CCsAudioRk3xHW::i2s_read32(UINT32 reg) +{ + return read32(m_MMIO.Base.baseptr + reg); +} + +void CCsAudioRk3xHW::i2s_write32(UINT32 reg, UINT32 val) +{ + write32(m_MMIO.Base.baseptr + reg, val); +} + +void CCsAudioRk3xHW::i2s_update32(UINT32 reg, UINT32 mask, UINT32 val) +{ + UINT32 tmp = i2s_read32(reg); + tmp &= ~mask; + tmp |= val; + i2s_write32(reg, tmp); +} +#endif + +struct rk_stream* CCsAudioRk3xHW::rk_get_stream(eDeviceType deviceType) { + switch (deviceType) { + case eOutputDevice: + return &this->outputStream; + case eInputDevice: + return &this->inputStream; + default: + return NULL; + } +} + +NTSTATUS CCsAudioRk3xHW::rk3x_init() { +#if USERKHW + + this->m_rkdspInterface.SetDSPPowerState(this->m_rkdspInterface.Context, PowerDeviceD0); + + //write defaults + i2s_write32(I2S_TXCR, 0x7200000f); + i2s_write32(I2S_RXCR, 0x01c8000f); + i2s_write32(I2S_CKR, 0x00001f1f); + i2s_write32(I2S_DMACR, 0x001f0000); + i2s_write32(I2S_INTCR, 0x01f00000); + i2s_write32(I2S_TDM_TXCR, 0x00003eff); + i2s_write32(I2S_TDM_RXCR, 0x00003eff); + i2s_write32(I2S_CLKDIV, 0x00000707); + + UINT32 clk_trcm = 0 << I2S_CKR_TRCM_SHIFT; + i2s_update32(I2S_DMACR, I2S_DMACR_TDL_MASK, I2S_DMACR_TDL(16)); + i2s_update32(I2S_DMACR, I2S_DMACR_RDL_MASK, I2S_DMACR_RDL(16)); + i2s_update32(I2S_CKR, I2S_CKR_TRCM_MASK, clk_trcm); + + //Set fmt + i2s_update32(I2S_CKR, I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER); //cbs cfs + i2s_update32(I2S_CKR, + I2S_CKR_CKP_MASK | I2S_CKR_TLP_MASK | I2S_CKR_RLP_MASK, + I2S_CKR_CKP_NORMAL | I2S_CKR_TLP_NORMAL | I2S_CKR_RLP_NORMAL); //nb nf + i2s_update32(I2S_TXCR, + I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK, + I2S_TXCR_IBM_NORMAL); //daifmt i2s + i2s_update32(I2S_RXCR, + I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK, + I2S_RXCR_IBM_NORMAL); //daifmt i2s + + //Set bclk (bclk = 4, lrclk = 64, fmt = 0xf) + i2s_update32(I2S_CLKDIV, + I2S_CLKDIV_TXM_MASK | I2S_CLKDIV_RXM_MASK, + I2S_CLKDIV_TXM(4) | I2S_CLKDIV_RXM(4)); + i2s_update32(I2S_CKR, + I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK, + I2S_CKR_TSD(64) | I2S_CKR_RSD(64)); + + i2s_update32(I2S_TXCR, + I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, + I2S_TXCR_VDW(16)); + i2s_update32(I2S_RXCR, + I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK, + I2S_RXCR_VDW(16)); + + //set path + i2s_update32(I2S_TXCR, + I2S_TXCR_PATH_MASK(0), + I2S_TXCR_PATH(0, 3)); + i2s_update32(I2S_TXCR, + I2S_TXCR_PATH_MASK(1), + I2S_TXCR_PATH(1, 2)); + i2s_update32(I2S_TXCR, + I2S_TXCR_PATH_MASK(2), + I2S_TXCR_PATH(2, 1)); + i2s_update32(I2S_TXCR, + I2S_TXCR_PATH_MASK(3), + I2S_TXCR_PATH(3, 0)); + + i2s_update32(I2S_RXCR, + I2S_RXCR_PATH_MASK(0), + I2S_RXCR_PATH(0, 1)); + i2s_update32(I2S_RXCR, + I2S_RXCR_PATH_MASK(1), + I2S_RXCR_PATH(1, 3)); + i2s_update32(I2S_RXCR, + I2S_RXCR_PATH_MASK(2), + I2S_RXCR_PATH(2, 2)); + i2s_update32(I2S_RXCR, + I2S_RXCR_PATH_MASK(3), + I2S_RXCR_PATH(3, 0)); + + return STATUS_SUCCESS; +#else + return STATUS_SUCCESS; +#endif +} + +NTSTATUS CCsAudioRk3xHW::rk3x_deinit() { +#if USERKHW + this->m_rkdspInterface.SetDSPPowerState(this->m_rkdspInterface.Context, PowerDeviceD3); + + return STATUS_SUCCESS; +#else + return STATUS_SUCCESS; +#endif +} + +BOOLEAN CCsAudioRk3xHW::rk3x_irq() { + UINT32 val = i2s_read32(I2S_INTSR); + + if (val & I2S_INTSR_TXUI_ACT) { + DbgPrint("TX FIFO Underrun\n"); + i2s_update32(I2S_INTCR, + I2S_INTCR_TXUIC, I2S_INTCR_TXUIC); + i2s_update32(I2S_INTCR, + I2S_INTCR_TXUIE_MASK, + I2S_INTCR_TXUIE(0)); + } + + if (val & I2S_INTSR_RXOI_ACT) { + DbgPrint("RX FIFO Overrun\n"); + i2s_update32(I2S_INTCR, + I2S_INTCR_RXOIC, I2S_INTCR_RXOIC); + i2s_update32(I2S_INTCR, + I2S_INTCR_RXOIE_MASK, + I2S_INTCR_RXOIE(0)); + } + + return TRUE; +} + +NTSTATUS CCsAudioRk3xHW::rk3x_program_dma(eDeviceType deviceType, PMDL mdl, IPortWaveRTStream *stream, UINT32 byteCount) { +#if USERKHW + struct rk_stream *i2sStream = rk_get_stream(deviceType); + if (!i2sStream) { + return STATUS_INVALID_PARAMETER; + } + + if (i2sStream->dmaThread) { + return STATUS_SUCCESS; //already allocated. Return + } + + int pageCount = stream->GetPhysicalPagesCount(mdl); + if (pageCount < 1) { + return STATUS_NO_MEMORY; + } + + int dmaIndex = 0; + UINT32 deviceReg = 0; + switch (deviceType) { + case eOutputDevice: + dmaIndex = this->rkTPLG.tx; + i2sStream->recording = FALSE; + deviceReg = I2S_TXDR; + break; + case eInputDevice: + dmaIndex = this->rkTPLG.rx; + i2sStream->recording = TRUE; + deviceReg = I2S_RXDR; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + PVOID dmaContext = this->m_DMAInterface.InterfaceHeader.Context; + + i2sStream->bufferBaseAddress = stream->GetPhysicalPageAddress(mdl, 0); + i2sStream->bufferBytes = byteCount; + i2sStream->dmaThread = this->m_DMAInterface.GetChannel(dmaContext, dmaIndex); + + if (!i2sStream->dmaThread) { + return STATUS_UNSUCCESSFUL; + } + + UINT32 srcAddr; + UINT32 dstAddr; + if (i2sStream->recording) { + srcAddr = this->m_MMIO.PhysAddr.LowPart + deviceReg; + dstAddr = i2sStream->bufferBaseAddress.LowPart; + } else { + srcAddr = i2sStream->bufferBaseAddress.LowPart; + dstAddr = this->m_MMIO.PhysAddr.LowPart + deviceReg; + } + + if (!i2sStream->recording) { + return this->m_DMAInterface.SubmitAudioDMA( + dmaContext, + i2sStream->dmaThread, + i2sStream->recording, + i2sStream->bufferBaseAddress.LowPart, + this->m_MMIO.PhysAddr.LowPart + deviceReg, + byteCount, + byteCount / 2 + ); + } + else { + return this->m_DMAInterface.SubmitAudioDMA( + dmaContext, + i2sStream->dmaThread, + i2sStream->recording, + this->m_MMIO.PhysAddr.LowPart + deviceReg, + i2sStream->bufferBaseAddress.LowPart, + byteCount, + byteCount / 2 + ); + } +#else + return STATUS_SUCCESS; +#endif +} + +NTSTATUS CCsAudioRk3xHW::rk3x_play(eDeviceType deviceType) { +#if USERKHW + struct rk_stream* i2sStream = rk_get_stream(deviceType); + if (!i2sStream) { + return STATUS_INVALID_PARAMETER; + } + + if (!i2sStream->dmaThread) { + return STATUS_INVALID_DEVICE_STATE; + } + + if (i2sStream->isActive) { + return STATUS_SUCCESS; + } + + switch (deviceType) { + case eOutputDevice: + i2s_update32(I2S_DMACR, I2S_DMACR_TDE_MASK, I2S_DMACR_TDE(1)); + i2s_update32(I2S_XFER, I2S_XFER_TXS_MASK, I2S_XFER_TXS_START); + break; + case eInputDevice: + i2s_update32(I2S_DMACR, I2S_DMACR_RDE_MASK, I2S_DMACR_RDE(1)); + i2s_update32(I2S_XFER, I2S_XFER_RXS_MASK, I2S_XFER_RXS_START); + break; + default: + return STATUS_INVALID_PARAMETER; + } +#endif + + i2sStream->isActive = TRUE; + + if (this->isJack) { + CsAudioArg arg; + RtlZeroMemory(&arg, sizeof(CsAudioArg)); + arg.argSz = sizeof(CsAudioArg); + arg.endpointType = GetCSAudioEndpoint(deviceType); + arg.endpointRequest = CSAudioEndpointStart; + ExNotifyCallback(this->CSAudioAPICallback, &arg, &CsAudioArg2); + } + return STATUS_SUCCESS; +} + +NTSTATUS CCsAudioRk3xHW::rk3x_stop(eDeviceType deviceType) { +#if USERKHW + struct rk_stream* i2sStream = rk_get_stream(deviceType); + if (!i2sStream) { + return STATUS_INVALID_PARAMETER; + } + + if (!i2sStream->isActive) { + return STATUS_SUCCESS; + } + + if (!i2sStream->dmaThread) { + return STATUS_INVALID_DEVICE_STATE; + } + + if (this->isJack) { + CsAudioArg arg; + RtlZeroMemory(&arg, sizeof(CsAudioArg)); + arg.argSz = sizeof(CsAudioArg); + arg.endpointType = GetCSAudioEndpoint(deviceType); + arg.endpointRequest = CSAudioEndpointStop; + ExNotifyCallback(this->CSAudioAPICallback, &arg, &CsAudioArg2); + } + + switch (deviceType) { + case eOutputDevice: + i2s_update32(I2S_DMACR, I2S_DMACR_TDE_MASK, I2S_DMACR_TDE(0)); + i2s_update32(I2S_XFER, I2S_XFER_TXS_MASK, I2S_XFER_TXS_STOP); + break; + case eInputDevice: + i2s_update32(I2S_DMACR, I2S_DMACR_RDE_MASK, I2S_DMACR_RDE(0)); + i2s_update32(I2S_XFER, I2S_XFER_RXS_MASK, I2S_XFER_RXS_STOP); + break; + default: + return STATUS_INVALID_PARAMETER; + } + + PVOID dmaContext = m_DMAInterface.InterfaceHeader.Context; + HANDLE dmaThread = i2sStream->dmaThread; + + this->m_DMAInterface.StopDMA(dmaContext, dmaThread); + this->m_DMAInterface.FreeChannel(dmaContext, dmaThread); + + UINT32 clr = 0; + + switch (deviceType) { + case eOutputDevice: + clr = I2S_CLR_TXC; + break; + case eInputDevice: + clr = I2S_CLR_RXC; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + i2s_update32(I2S_CLR, clr, clr); + + for (int i = 0; i < 10; i++) { + UINT32 reg = i2s_read32(I2S_CLR); + if ((reg & clr) == 0){ + break; + } + LARGE_INTEGER Interval; + Interval.QuadPart = -100; + KeDelayExecutionThread(KernelMode, FALSE, &Interval); + } + + i2s_update32(I2S_CLR, clr, 0); + + i2sStream->dmaThread = NULL; + i2sStream->bufferBytes = 0; + i2sStream->isActive = FALSE; +#endif + return STATUS_SUCCESS; +} + +NTSTATUS CCsAudioRk3xHW::rk3x_current_position(eDeviceType deviceType, UINT32 *linkPos, UINT64 *linearPos) { +#if USERKHW + struct rk_stream* i2sStream = rk_get_stream(deviceType); + if (!i2sStream) { + return STATUS_INVALID_PARAMETER; + } + + if (!i2sStream->isActive) { + return STATUS_SUCCESS; + } + + if (!i2sStream->dmaThread) { + return STATUS_INVALID_DEVICE_STATE; + } + + PVOID dmaContext = this->m_DMAInterface.InterfaceHeader.Context; + UINT32 sourceAddr; + UINT32 dstAddr; + + this->m_DMAInterface.GetThreadRegisters( + dmaContext, + i2sStream->dmaThread, + NULL, + &sourceAddr, + &dstAddr + ); + + UINT32 positionOffset; + if (i2sStream->recording) { + positionOffset = dstAddr - i2sStream->bufferBaseAddress.LowPart; + } + else { + positionOffset = sourceAddr - i2sStream->bufferBaseAddress.LowPart; + } + + if (linkPos) + *linkPos = positionOffset; + if (linearPos) + *linearPos = positionOffset; +#endif + return STATUS_SUCCESS; +} + +//============================================================================= +BOOL +CCsAudioRk3xHW::bGetDevSpecific() +/*++ + +Routine Description: + + Gets the HW (!) Device Specific info + +Arguments: + + N/A + +Return Value: + + True or False (in this example). + +--*/ +{ + return m_bDevSpecific; +} // bGetDevSpecific + +//============================================================================= +void +CCsAudioRk3xHW::bSetDevSpecific +( + _In_ BOOL bDevSpecific +) +/*++ + +Routine Description: + + Sets the HW (!) Device Specific info + +Arguments: + + fDevSpecific - true or false for this example. + +Return Value: + + void + +--*/ +{ + m_bDevSpecific = bDevSpecific; +} // bSetDevSpecific + +//============================================================================= +INT +CCsAudioRk3xHW::iGetDevSpecific() +/*++ + +Routine Description: + + Gets the HW (!) Device Specific info + +Arguments: + + N/A + +Return Value: + + int (in this example). + +--*/ +{ + return m_iDevSpecific; +} // iGetDevSpecific + +//============================================================================= +void +CCsAudioRk3xHW::iSetDevSpecific +( + _In_ INT iDevSpecific +) +/*++ + +Routine Description: + + Sets the HW (!) Device Specific info + +Arguments: + + fDevSpecific - true or false for this example. + +Return Value: + + void + +--*/ +{ + m_iDevSpecific = iDevSpecific; +} // iSetDevSpecific + +//============================================================================= +UINT +CCsAudioRk3xHW::uiGetDevSpecific() +/*++ + +Routine Description: + + Gets the HW (!) Device Specific info + +Arguments: + + N/A + +Return Value: + + UINT (in this example). + +--*/ +{ + return m_uiDevSpecific; +} // uiGetDevSpecific + +//============================================================================= +void +CCsAudioRk3xHW::uiSetDevSpecific +( + _In_ UINT uiDevSpecific +) +/*++ + +Routine Description: + + Sets the HW (!) Device Specific info + +Arguments: + + uiDevSpecific - int for this example. + +Return Value: + + void + +--*/ +{ + m_uiDevSpecific = uiDevSpecific; +} // uiSetDevSpecific + +//============================================================================= +ULONG +CCsAudioRk3xHW::GetMixerMux() +/*++ + +Routine Description: + + Return the current mux selection + +Arguments: + +Return Value: + + ULONG + +--*/ +{ + return m_ulMux; +} // GetMixerMux + +//============================================================================= +LONG +CCsAudioRk3xHW::GetMixerPeakMeter +( + _In_ ULONG ulNode, + _In_ ULONG ulChannel +) +/*++ + +Routine Description: + + Gets the HW (!) peak meter for Simple Audio Sample. + +Arguments: + + ulNode - topology node id + + ulChannel - which channel are we reading? + +Return Value: + + LONG - sample peak meter level + +--*/ +{ + UNREFERENCED_PARAMETER(ulChannel); + + if (ulNode < MAX_TOPOLOGY_NODES) + { + return m_PeakMeterControls[ulNode]; + } + + return 0; +} // GetMixerVolume + +//============================================================================= +#pragma code_seg("PAGE") +void +CCsAudioRk3xHW::MixerReset() +/*++ + +Routine Description: + + Resets the mixer registers. + +Arguments: + +Return Value: + + void + +--*/ +{ + PAGED_CODE(); + + for (ULONG i=0; i + +union baseaddr { + PVOID Base; + UINT8* baseptr; +}; + +typedef struct _PCI_BAR { + union baseaddr Base; + PHYSICAL_ADDRESS PhysAddr; + ULONG Len; +} PCI_BAR, * PPCI_BAR; + +struct rk_stream { + UINT32 bufferBytes; + BOOLEAN isActive; + + PHYSICAL_ADDRESS bufferBaseAddress; + BOOLEAN recording; + HANDLE dmaThread; +}; + +#include "adsp.h" + +#define JACK_TPLG "i2s-jack" +#define HDMI_TPLG "hdmi" +#define DP_TPLG "dp" + +#endif + +//============================================================================= +// Defines +//============================================================================= +// BUGBUG we should dynamically allocate this... +#define MAX_TOPOLOGY_NODES 20 + +//============================================================================= +// Classes +//============================================================================= +/////////////////////////////////////////////////////////////////////////////// +// CCsAudioRk3xHW +// This class represents virtual Simple Audio Sample HW. An array representing volume +// registers and mute registers. + +class CCsAudioRk3xHW +{ +public: + int CsAudioArg2; + void CSAudioAPICalled(CsAudioArg arg); + +private: + PCALLBACK_OBJECT CSAudioAPICallback; + PVOID CSAudioAPICallbackObj; + + NTSTATUS CSAudioAPIInit(); + NTSTATUS CSAudioAPIDeinit(); + CSAudioEndpointType GetCSAudioEndpoint(eDeviceType deviceType); + eDeviceType GetDeviceType(CSAudioEndpointType endpointType); + +protected: + LONG m_PeakMeterControls[MAX_TOPOLOGY_NODES]; + ULONG m_ulMux; // Mux selection + BOOL m_bDevSpecific; + INT m_iDevSpecific; + UINT m_uiDevSpecific; +#if USERKHW + WDFDEVICE m_wdfDevice; + RKDSP_BUS_INTERFACE m_rkdspInterface; + PCI_BAR m_MMIO; + PL330DMA_INTERFACE_STANDARD m_DMAInterface; + +public: + RK_TPLG rkTPLG; + BOOLEAN isJack; + +protected: + struct rk_stream outputStream; + struct rk_stream inputStream; + + UINT32 i2s_read32(UINT32 reg); + void i2s_write32(UINT32 reg, UINT32 val); + void i2s_update32(UINT32 reg, UINT32 mask, UINT32 val); + + NTSTATUS connectDMA(); +#endif + +public: + CCsAudioRk3xHW(_In_ PRKDSP_BUS_INTERFACE AdspInterface, _In_ WDFDEVICE wdfDevice); + ~CCsAudioRk3xHW(); + + bool ResourcesValidated(); + + NTSTATUS rk3x_init(); + NTSTATUS rk3x_deinit(); + + BOOLEAN rk3x_irq(); + + struct rk_stream* rk_get_stream(eDeviceType deviceType); + + NTSTATUS rk3x_program_dma(eDeviceType deviceType, PMDL mdl, IPortWaveRTStream* stream, UINT32 byteCount); + NTSTATUS rk3x_play(eDeviceType deviceType); + NTSTATUS rk3x_stop(eDeviceType deviceType); + NTSTATUS rk3x_current_position(eDeviceType deviceType, UINT32* linkPos, UINT64* linearPos); + + void MixerReset(); + BOOL bGetDevSpecific(); + void bSetDevSpecific + ( + _In_ BOOL bDevSpecific + ); + INT iGetDevSpecific(); + void iSetDevSpecific + ( + _In_ INT iDevSpecific + ); + UINT uiGetDevSpecific(); + void uiSetDevSpecific + ( + _In_ UINT uiDevSpecific + ); + ULONG GetMixerMux(); + void SetMixerMux + ( + _In_ ULONG ulNode + ); + + LONG GetMixerPeakMeter + ( + _In_ ULONG ulNode, + _In_ ULONG ulChannel + ); + +protected: +private: +}; +typedef CCsAudioRk3xHW *PCCsAudioRk3xHW; + +#endif // _CSAUDIORK3X_HW_H_ diff --git a/drivers/audio/csaudiork3x/Source/Utilities/kshelper.cpp b/drivers/audio/csaudiork3x/Source/Utilities/kshelper.cpp new file mode 100644 index 0000000..0798a6d --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/kshelper.cpp @@ -0,0 +1,646 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + kshelper.cpp + +Abstract: + + Helper functions for simple audio sample +--*/ + +#include "definitions.h" + +//4127: conditional expression is constant +#pragma warning (disable : 4127) + +//----------------------------------------------------------------------------- +#pragma code_seg("PAGE") +PWAVEFORMATEX +GetWaveFormatEx +( + _In_ PKSDATAFORMAT pDataFormat +) +/*++ + +Routine Description: + + Returns the waveformatex for known formats. + +Arguments: + + pDataFormat - data format. + +Return Value: + + waveformatex in DataFormat. + NULL for unknown data formats. + +--*/ +{ + PAGED_CODE(); + + PWAVEFORMATEX pWfx = NULL; + + // If this is a known dataformat extract the waveformat info. + // + if + ( + pDataFormat && + ( IsEqualGUIDAligned(pDataFormat->MajorFormat, + KSDATAFORMAT_TYPE_AUDIO) && + ( IsEqualGUIDAligned(pDataFormat->Specifier, + KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) || + IsEqualGUIDAligned(pDataFormat->Specifier, + KSDATAFORMAT_SPECIFIER_DSOUND) ) ) + ) + { + pWfx = PWAVEFORMATEX(pDataFormat + 1); + + if (IsEqualGUIDAligned(pDataFormat->Specifier, + KSDATAFORMAT_SPECIFIER_DSOUND)) + { + PKSDSOUND_BUFFERDESC pwfxds; + + pwfxds = PKSDSOUND_BUFFERDESC(pDataFormat + 1); + pWfx = &pwfxds->WaveFormatEx; + } + } + + return pWfx; +} // GetWaveFormatEx + +//----------------------------------------------------------------------------- +#pragma code_seg("PAGE") +NTSTATUS +ValidatePropertyParams +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG cbValueSize, + _In_ ULONG cbInstanceSize /* = 0 */ +) +/*++ + +Routine Description: + + Validates property parameters. + +Arguments: + + PropertyRequest - + cbValueSize - + cbInstanceSize - + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + + if (PropertyRequest && cbValueSize) + { + // If the caller is asking for ValueSize. + // + if (0 == PropertyRequest->ValueSize) + { + PropertyRequest->ValueSize = cbValueSize; + ntStatus = STATUS_BUFFER_OVERFLOW; + } + // If the caller passed an invalid ValueSize. + // + else if (PropertyRequest->ValueSize < cbValueSize) + { + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + else if (PropertyRequest->InstanceSize < cbInstanceSize) + { + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + // If all parameters are OK. + // + else if (PropertyRequest->ValueSize >= cbValueSize) + { + if (PropertyRequest->Value) + { + ntStatus = STATUS_SUCCESS; + // + // Caller should set ValueSize, if the property + // call is successful. + // + } + } + } + else + { + ntStatus = STATUS_INVALID_PARAMETER; + } + + // Clear the ValueSize if unsuccessful. + // + if (PropertyRequest && + STATUS_SUCCESS != ntStatus && + STATUS_BUFFER_OVERFLOW != ntStatus) + { + PropertyRequest->ValueSize = 0; + } + + return ntStatus; +} // ValidatePropertyParams + +//----------------------------------------------------------------------------- +#pragma code_seg("PAGE") +NTSTATUS +CsAudioRk3xPropertyDispatch +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + Handles and dispatches a CSAUDIORK3X_PROPERTY_ITEM. + + Use this as the property handler only if the property item is a + CSAUDIORK3X_PROPERTY_ITEM. +--*/ +{ + PAGED_CODE(); + + CSAUDIORK3X_PROPERTY_ITEM* item = (CSAUDIORK3X_PROPERTY_ITEM*)PropertyRequest->PropertyItem; + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + if (item->SupportHandler != nullptr) + { + return item->SupportHandler(PropertyRequest); + } + else + { + return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->Flags, VT_ILLEGAL); + } + } + + // Verify instance data size + if (PropertyRequest->InstanceSize < item->MinProperty) + { + return STATUS_INVALID_PARAMETER; + } + + ULONG cbMinSize = item->MinData; + + // Verify value size + if (PropertyRequest->ValueSize == 0) + { + PropertyRequest->ValueSize = cbMinSize; + return STATUS_BUFFER_OVERFLOW; + } + if (PropertyRequest->ValueSize < cbMinSize) + { + PropertyRequest->ValueSize = 0; + return STATUS_BUFFER_TOO_SMALL; + } + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + if (item->GetHandler != nullptr) + { + return item->GetHandler(PropertyRequest); + } + else + { + return STATUS_NOT_SUPPORTED; + } + } + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) + { + if (item->SetHandler != nullptr) + { + return item->SetHandler(PropertyRequest); + } + else + { + return STATUS_NOT_SUPPORTED; + } + } + + return STATUS_INVALID_DEVICE_REQUEST; +} + +//----------------------------------------------------------------------------- +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_BasicSupport +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG Flags, + _In_ DWORD PropTypeSetId +) +/*++ + +Routine Description: + + Default basic support handler. Basic processing depends on the size of data. + For ULONG it only returns Flags. For KSPROPERTY_DESCRIPTION, the structure + is filled. + +Arguments: + + PropertyRequest - + + Flags - Support flags. + + PropTypeSetId - PropTypeSetId + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + ASSERT(Flags & KSPROPERTY_TYPE_BASICSUPPORT); + + NTSTATUS ntStatus = STATUS_INVALID_PARAMETER; + + 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 = Flags; + PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION); + if (VT_ILLEGAL != PropTypeSetId) + { + PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; + PropDesc->PropTypeSet.Id = PropTypeSetId; + } + else + { + PropDesc->PropTypeSet.Set = GUID_NULL; + PropDesc->PropTypeSet.Id = 0; + } + PropDesc->PropTypeSet.Flags = 0; + PropDesc->MembersListCount = 0; + PropDesc->Reserved = 0; + + 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)) = Flags; + + PropertyRequest->ValueSize = sizeof(ULONG); + ntStatus = STATUS_SUCCESS; + } + else + { + PropertyRequest->ValueSize = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} // PropertyHandler_BasicSupport + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_BasicSupportVolume +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG MaxChannels +) +/*++ + +Routine Description: + + Handles BasicSupport for Volume nodes. + +Arguments: + + PropertyRequest - property request structure. + + MaxChannels - # of supported channels. + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG cbFullProperty = + sizeof(KSPROPERTY_DESCRIPTION) + + sizeof(KSPROPERTY_MEMBERSHEADER) + + sizeof(KSPROPERTY_STEPPING_LONG) * MaxChannels; + + ASSERT(MaxChannels > 0); + + if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION))) + { + PKSPROPERTY_DESCRIPTION PropDesc = + PKSPROPERTY_DESCRIPTION(PropertyRequest->Value); + + PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL; + PropDesc->DescriptionSize = cbFullProperty; + PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; + PropDesc->PropTypeSet.Id = VT_I4; + PropDesc->PropTypeSet.Flags = 0; + PropDesc->MembersListCount = 1; + PropDesc->Reserved = 0; + + // if return buffer can also hold a range description, return it too + if(PropertyRequest->ValueSize >= cbFullProperty) + { + // fill in the members header + PKSPROPERTY_MEMBERSHEADER Members = + PKSPROPERTY_MEMBERSHEADER(PropDesc + 1); + + Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES; + Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG); + Members->MembersCount = MaxChannels; + Members->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL; + + // fill in the stepped range + PKSPROPERTY_STEPPING_LONG Range = + PKSPROPERTY_STEPPING_LONG(Members + 1); + + for (ULONG i=0; iValueSize = cbFullProperty; + } + else + { + PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION); + } + } + else if(PropertyRequest->ValueSize >= sizeof(ULONG)) + { + // if return buffer can hold a ULONG, return the access flags + PULONG AccessFlags = PULONG(PropertyRequest->Value); + + PropertyRequest->ValueSize = sizeof(ULONG); + *AccessFlags = KSPROPERTY_TYPE_ALL; + } + else + { + PropertyRequest->ValueSize = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} // PropertyHandlerBasicSupportVolume + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_BasicSupportPeakMeter2 +( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG MaxChannels +) +/*++ + +Routine Description: + + Handles BasicSupport for peak meter nodes. + +Arguments: + + PropertyRequest - property request structure. + + MaxChannels - # of supported channels. + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG cbFullProperty = + sizeof(KSPROPERTY_DESCRIPTION) + + sizeof(KSPROPERTY_MEMBERSHEADER) + + sizeof(KSPROPERTY_STEPPING_LONG) * MaxChannels; + + ASSERT(MaxChannels > 0); + + if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION))) + { + PKSPROPERTY_DESCRIPTION PropDesc = + PKSPROPERTY_DESCRIPTION(PropertyRequest->Value); + + PropDesc->AccessFlags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT; + PropDesc->DescriptionSize = cbFullProperty; + PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; + PropDesc->PropTypeSet.Id = VT_I4; + PropDesc->PropTypeSet.Flags = 0; + PropDesc->MembersListCount = 1; + PropDesc->Reserved = 0; + + // if return buffer can also hold a range description, return it too + if(PropertyRequest->ValueSize >= cbFullProperty) + { + // fill in the members header + PKSPROPERTY_MEMBERSHEADER Members = + PKSPROPERTY_MEMBERSHEADER(PropDesc + 1); + + Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES; + Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG); + Members->MembersCount = MaxChannels; + Members->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL; + + // fill in the stepped range + PKSPROPERTY_STEPPING_LONG Range = + PKSPROPERTY_STEPPING_LONG(Members + 1); + + for (ULONG i=0; iValueSize = cbFullProperty; + } + else + { + PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION); + } + } + else if(PropertyRequest->ValueSize >= sizeof(ULONG)) + { + // if return buffer can hold a ULONG, return the access flags + PULONG AccessFlags = PULONG(PropertyRequest->Value); + + PropertyRequest->ValueSize = sizeof(ULONG); + *AccessFlags = KSPROPERTY_TYPE_ALL; + } + else + { + PropertyRequest->ValueSize = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} // PropertyHandlerBasicSupportVolume + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_CpuResources +( + _In_ PPCPROPERTY_REQUEST PropertyRequest +) +/*++ + +Routine Description: + + Processes KSPROPERTY_AUDIO_CPURESOURCES + +Arguments: + + PropertyRequest - property request structure. + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + DPF_ENTER(("[%s]",__FUNCTION__)); + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(ULONG)); + if (NT_SUCCESS(ntStatus)) + { + *(PULONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU; + PropertyRequest->ValueSize = sizeof(ULONG); + } + } + else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ntStatus = + PropertyHandler_BasicSupport + ( + PropertyRequest, + KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, + VT_UI4 + ); + } + + return ntStatus; +} // PropertyHandlerCpuResources + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PropertyHandler_PeakMeter2 +( + _In_ PADAPTERCOMMON AdapterCommon, + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ ULONG MaxChannels +) +/*++ + +Routine Description: + + Property handler for KSPROPERTY_AUDIO_PEAKMETER2 + +Arguments: + + AdapterCommon - interface to the common adapter object. + + PropertyRequest - property request structure. + + MaxChannels - # of supported channels. + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + DPF_ENTER(("[%s]",__FUNCTION__)); + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + ULONG ulChannel; + PLONG plSample; + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ntStatus = PropertyHandler_BasicSupportPeakMeter2( + PropertyRequest, + MaxChannels); + } + else + { + ntStatus = + ValidatePropertyParams + ( + PropertyRequest, + sizeof(LONG), // sample value is a LONG + sizeof(ULONG) // instance is the channel number + ); + if (NT_SUCCESS(ntStatus)) + { + ulChannel = * (PULONG (PropertyRequest->Instance)); + plSample = PLONG (PropertyRequest->Value); + + if (ulChannel >= MaxChannels && + ulChannel != ALL_CHANNELS_ID) + { + ntStatus = STATUS_INVALID_PARAMETER; + } + else if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + *plSample = + PEAKMETER_NORMALIZE_IN_RANGE( + AdapterCommon->MixerPeakMeterRead + ( + PropertyRequest->Node, + ulChannel == ALL_CHANNELS_ID ? 0 : ulChannel + )); + + PropertyRequest->ValueSize = sizeof(ULONG); + } + } + + if (!NT_SUCCESS(ntStatus)) + { + DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus)); + } + } + + return ntStatus; +} // PropertyHandlerVolume + diff --git a/drivers/audio/csaudiork3x/Source/Utilities/rk3x.h b/drivers/audio/csaudiork3x/Source/Utilities/rk3x.h new file mode 100644 index 0000000..dc1a751 --- /dev/null +++ b/drivers/audio/csaudiork3x/Source/Utilities/rk3x.h @@ -0,0 +1,413 @@ +#ifndef _ROCKCHIP_I2S_TDM_H +#define _ROCKCHIP_I2S_TDM_H + +#define FIFO_SIZE 1 + +#define BIT(i) (1 << i) + +/* + * TXCR + * transmit operation control register + */ +#define I2S_TXCR_PATH_SHIFT(x) (23 + (x) * 2) +#define I2S_TXCR_PATH_MASK(x) (0x3 << I2S_TXCR_PATH_SHIFT(x)) +#define I2S_TXCR_PATH(x, v) ((v) << I2S_TXCR_PATH_SHIFT(x)) +#define I2S_TXCR_RCNT_SHIFT 17 +#define I2S_TXCR_RCNT_MASK (0x3f << I2S_TXCR_RCNT_SHIFT) +#define I2S_TXCR_CSR_SHIFT 15 +#define I2S_TXCR_CSR(x) ((x) << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CSR_MASK (3 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_HWT BIT(14) +#define I2S_TXCR_SJM_SHIFT 12 +#define I2S_TXCR_SJM_R (0 << I2S_TXCR_SJM_SHIFT) +#define I2S_TXCR_SJM_L (1 << I2S_TXCR_SJM_SHIFT) +#define I2S_TXCR_FBM_SHIFT 11 +#define I2S_TXCR_FBM_MSB (0 << I2S_TXCR_FBM_SHIFT) +#define I2S_TXCR_FBM_LSB (1 << I2S_TXCR_FBM_SHIFT) +#define I2S_TXCR_IBM_SHIFT 9 +#define I2S_TXCR_IBM_NORMAL (0 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_LSJM (1 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_RSJM (2 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_MASK (3 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_PBM_SHIFT 7 +#define I2S_TXCR_PBM_MODE(x) ((x) << I2S_TXCR_PBM_SHIFT) +#define I2S_TXCR_PBM_MASK (3 << I2S_TXCR_PBM_SHIFT) +#define I2S_TXCR_TFS_SHIFT 5 +#define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_TDM_PCM (2 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_TDM_I2S (3 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_MASK (3 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_VDW_SHIFT 0 +#define I2S_TXCR_VDW(x) (((x) - 1) << I2S_TXCR_VDW_SHIFT) +#define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT) + + /* + * RXCR + * receive operation control register + */ +#define I2S_RXCR_PATH_SHIFT(x) (17 + (x) * 2) +#define I2S_RXCR_PATH_MASK(x) (0x3 << I2S_RXCR_PATH_SHIFT(x)) +#define I2S_RXCR_PATH(x, v) ((v) << I2S_RXCR_PATH_SHIFT(x)) +#define I2S_RXCR_CSR_SHIFT 15 +#define I2S_RXCR_CSR(x) ((x) << I2S_RXCR_CSR_SHIFT) +#define I2S_RXCR_CSR_MASK (3 << I2S_RXCR_CSR_SHIFT) +#define I2S_RXCR_HWT BIT(14) +#define I2S_RXCR_SJM_SHIFT 12 +#define I2S_RXCR_SJM_R (0 << I2S_RXCR_SJM_SHIFT) +#define I2S_RXCR_SJM_L (1 << I2S_RXCR_SJM_SHIFT) +#define I2S_RXCR_FBM_SHIFT 11 +#define I2S_RXCR_FBM_MSB (0 << I2S_RXCR_FBM_SHIFT) +#define I2S_RXCR_FBM_LSB (1 << I2S_RXCR_FBM_SHIFT) +#define I2S_RXCR_IBM_SHIFT 9 +#define I2S_RXCR_IBM_NORMAL (0 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_LSJM (1 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_RSJM (2 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_MASK (3 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_PBM_SHIFT 7 +#define I2S_RXCR_PBM_MODE(x) ((x) << I2S_RXCR_PBM_SHIFT) +#define I2S_RXCR_PBM_MASK (3 << I2S_RXCR_PBM_SHIFT) +#define I2S_RXCR_TFS_SHIFT 5 +#define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_TDM_PCM (2 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_TDM_I2S (3 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_MASK (3 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_VDW_SHIFT 0 +#define I2S_RXCR_VDW(x) (((x) - 1) << I2S_RXCR_VDW_SHIFT) +#define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT) + + /* + * CKR + * clock generation register + */ +#define I2S_CKR_TRCM_SHIFT 28 +#define I2S_CKR_TRCM(x) ((x) << I2S_CKR_TRCM_SHIFT) +#define I2S_CKR_TRCM_TXRX (0 << I2S_CKR_TRCM_SHIFT) +#define I2S_CKR_TRCM_TXONLY (1 << I2S_CKR_TRCM_SHIFT) +#define I2S_CKR_TRCM_RXONLY (2 << I2S_CKR_TRCM_SHIFT) +#define I2S_CKR_TRCM_MASK (3 << I2S_CKR_TRCM_SHIFT) +#define I2S_CKR_MSS_SHIFT 27 +#define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_MSS_SLAVE (1 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_MSS_MASK (1 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_CKP_SHIFT 26 +#define I2S_CKR_CKP_NORMAL (0 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_CKP_INVERTED (1 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_CKP_MASK (1 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_RLP_SHIFT 25 +#define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT) +#define I2S_CKR_RLP_INVERTED (1 << I2S_CKR_RLP_SHIFT) +#define I2S_CKR_RLP_MASK (1 << I2S_CKR_RLP_SHIFT) +#define I2S_CKR_TLP_SHIFT 24 +#define I2S_CKR_TLP_NORMAL (0 << I2S_CKR_TLP_SHIFT) +#define I2S_CKR_TLP_INVERTED (1 << I2S_CKR_TLP_SHIFT) +#define I2S_CKR_TLP_MASK (1 << I2S_CKR_TLP_SHIFT) +#define I2S_CKR_MDIV_SHIFT 16 +#define I2S_CKR_MDIV(x) (((x) - 1) << I2S_CKR_MDIV_SHIFT) +#define I2S_CKR_MDIV_MASK (0xff << I2S_CKR_MDIV_SHIFT) +#define I2S_CKR_RSD_SHIFT 8 +#define I2S_CKR_RSD(x) (((x) - 1) << I2S_CKR_RSD_SHIFT) +#define I2S_CKR_RSD_MASK (0xff << I2S_CKR_RSD_SHIFT) +#define I2S_CKR_TSD_SHIFT 0 +#define I2S_CKR_TSD(x) (((x) - 1) << I2S_CKR_TSD_SHIFT) +#define I2S_CKR_TSD_MASK (0xff << I2S_CKR_TSD_SHIFT) + + /* + * FIFOLR + * FIFO level register + */ +#define I2S_FIFOLR_RFL_SHIFT 24 +#define I2S_FIFOLR_RFL_MASK (0x3f << I2S_FIFOLR_RFL_SHIFT) +#define I2S_FIFOLR_TFL3_SHIFT 18 +#define I2S_FIFOLR_TFL3_MASK (0x3f << I2S_FIFOLR_TFL3_SHIFT) +#define I2S_FIFOLR_TFL2_SHIFT 12 +#define I2S_FIFOLR_TFL2_MASK (0x3f << I2S_FIFOLR_TFL2_SHIFT) +#define I2S_FIFOLR_TFL1_SHIFT 6 +#define I2S_FIFOLR_TFL1_MASK (0x3f << I2S_FIFOLR_TFL1_SHIFT) +#define I2S_FIFOLR_TFL0_SHIFT 0 +#define I2S_FIFOLR_TFL0_MASK (0x3f << I2S_FIFOLR_TFL0_SHIFT) + + /* + * DMACR + * DMA control register + */ +#define I2S_DMACR_RDE_SHIFT 24 +#define I2S_DMACR_RDE_DISABLE (0 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDE_ENABLE (1 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDE_MASK (1 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDE(x) ((x) << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDL_SHIFT 16 +#define I2S_DMACR_RDL(x) (((x) - 1) << I2S_DMACR_RDL_SHIFT) +#define I2S_DMACR_RDL_MASK (0x1f << I2S_DMACR_RDL_SHIFT) +#define I2S_DMACR_TDE_SHIFT 8 +#define I2S_DMACR_TDE_DISABLE (0 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDE_ENABLE (1 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDE_MASK (1 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDE(x) ((x) << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDL_SHIFT 0 +#define I2S_DMACR_TDL(x) ((x) << I2S_DMACR_TDL_SHIFT) +#define I2S_DMACR_TDL_MASK (0x1f << I2S_DMACR_TDL_SHIFT) + + /* + * INTCR + * interrupt control register + */ +#define I2S_INTCR_RFT_SHIFT 20 +#define I2S_INTCR_RFT(x) (((x) - 1) << I2S_INTCR_RFT_SHIFT) +#define I2S_INTCR_RXOIC BIT(18) +#define I2S_INTCR_RXOIE_SHIFT 17 +#define I2S_INTCR_RXOIE_MASK (1 << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXOIE(x) ((x) << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXFIE_SHIFT 16 +#define I2S_INTCR_RXFIE_DISABLE (0 << I2S_INTCR_RXFIE_SHIFT) +#define I2S_INTCR_RXFIE_ENABLE (1 << I2S_INTCR_RXFIE_SHIFT) +#define I2S_INTCR_TFT_SHIFT 4 +#define I2S_INTCR_TFT(x) (((x) - 1) << I2S_INTCR_TFT_SHIFT) +#define I2S_INTCR_TFT_MASK (0x1f << I2S_INTCR_TFT_SHIFT) +#define I2S_INTCR_TXUIC BIT(2) +#define I2S_INTCR_TXUIE_SHIFT 1 +#define I2S_INTCR_TXUIE_MASK (1 << I2S_INTCR_TXUIE_SHIFT) +#define I2S_INTCR_TXUIE(x) ((x) << I2S_INTCR_TXUIE_SHIFT) + + /* + * INTSR + * interrupt status register + */ +#define I2S_INTSR_TXEIE_SHIFT 0 +#define I2S_INTSR_TXEIE_DISABLE (0 << I2S_INTSR_TXEIE_SHIFT) +#define I2S_INTSR_TXEIE_ENABLE (1 << I2S_INTSR_TXEIE_SHIFT) +#define I2S_INTSR_RXOI_SHIFT 17 +#define I2S_INTSR_RXOI_INA (0 << I2S_INTSR_RXOI_SHIFT) +#define I2S_INTSR_RXOI_ACT (1 << I2S_INTSR_RXOI_SHIFT) +#define I2S_INTSR_RXFI_SHIFT 16 +#define I2S_INTSR_RXFI_INA (0 << I2S_INTSR_RXFI_SHIFT) +#define I2S_INTSR_RXFI_ACT (1 << I2S_INTSR_RXFI_SHIFT) +#define I2S_INTSR_TXUI_SHIFT 1 +#define I2S_INTSR_TXUI_INA (0 << I2S_INTSR_TXUI_SHIFT) +#define I2S_INTSR_TXUI_ACT (1 << I2S_INTSR_TXUI_SHIFT) +#define I2S_INTSR_TXEI_SHIFT 0 +#define I2S_INTSR_TXEI_INA (0 << I2S_INTSR_TXEI_SHIFT) +#define I2S_INTSR_TXEI_ACT (1 << I2S_INTSR_TXEI_SHIFT) + + /* + * XFER + * Transfer start register + */ + /* + * lp mode2 swap: + * i2s sdi0_l <- i2s sdo0_l + * i2s sdi0_r <- codec sdo_r + * + * lp mode2: + * i2s sdi0_l <- codec sdo_l + * i2s sdi0_r <- i2s sdo0_r + * + * lp mode1: + * i2s sdi0_l <- codec sdo_l + * i2s sdi0_r <- codec sdo_r + * i2s sdi1_l <- i2s sdo0_l + * i2s sdi1_r <- i2s sdo0_r + * + */ +#define I2S_XFER_LP_MODE_MASK GENMASK(4, 2) +#define I2S_XFER_LP_MODE_2_SWAP (BIT(4) | BIT(3)) +#define I2S_XFER_LP_MODE_2 BIT(3) +#define I2S_XFER_LP_MODE_1 BIT(2) +#define I2S_XFER_LP_MODE_DIS 0 +#define I2S_XFER_RXS_SHIFT 1 +#define I2S_XFER_RXS_STOP (0 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_RXS_START (1 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_RXS_MASK (1 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_RXS(x) ((x) << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_TXS_SHIFT 0 +#define I2S_XFER_TXS_STOP (0 << I2S_XFER_TXS_SHIFT) +#define I2S_XFER_TXS_START (1 << I2S_XFER_TXS_SHIFT) +#define I2S_XFER_TXS_MASK (1 << I2S_XFER_TXS_SHIFT) +#define I2S_XFER_TXS(x) ((x) << I2S_XFER_TXS_SHIFT) + + /* + * CLR + * clear SCLK domain logic register + */ +#define I2S_CLR_RXC BIT(1) +#define I2S_CLR_TXC BIT(0) + + /* + * TXDR + * Transimt FIFO data register, write only. + */ +#define I2S_TXDR_MASK (0xff) + + /* + * RXDR + * Receive FIFO data register, write only. + */ +#define I2S_RXDR_MASK (0xff) + + /* + * TDM_CTRL + * TDM ctrl register + */ +#define TDM_FSYNC_WIDTH_SEL1_MSK GENMASK(20, 18) +#define TDM_FSYNC_WIDTH_SEL1(x) (((x) - 1) << 18) +#define TDM_FSYNC_WIDTH_SEL0_MSK BIT(17) +#define TDM_FSYNC_WIDTH_HALF_FRAME 0 +#define TDM_FSYNC_WIDTH_ONE_FRAME BIT(17) +#define TDM_SHIFT_CTRL_MSK GENMASK(16, 14) +#define TDM_SHIFT_CTRL(x) ((x) << 14) +#define TDM_SLOT_BIT_WIDTH_MSK GENMASK(13, 9) +#define TDM_SLOT_BIT_WIDTH(x) (((x) - 1) << 9) +#define TDM_FRAME_WIDTH_MSK GENMASK(8, 0) +#define TDM_FRAME_WIDTH(x) (((x) - 1) << 0) + + /* + * CLKDIV + * Mclk div register + */ +#define I2S_CLKDIV_TXM_SHIFT 0 +#define I2S_CLKDIV_TXM(x) (((x) - 1) << I2S_CLKDIV_TXM_SHIFT) +#define I2S_CLKDIV_TXM_MASK (0xff << I2S_CLKDIV_TXM_SHIFT) +#define I2S_CLKDIV_RXM_SHIFT 8 +#define I2S_CLKDIV_RXM(x) (((x) - 1) << I2S_CLKDIV_RXM_SHIFT) +#define I2S_CLKDIV_RXM_MASK (0xff << I2S_CLKDIV_RXM_SHIFT) + + /* Clock divider id */ +enum { + ROCKCHIP_DIV_MCLK = 0, + ROCKCHIP_DIV_BCLK, +}; + +/* channel select */ +#define I2S_CSR_SHIFT 15 +#define I2S_CHN_2 (0 << I2S_CSR_SHIFT) +#define I2S_CHN_4 (1 << I2S_CSR_SHIFT) +#define I2S_CHN_6 (2 << I2S_CSR_SHIFT) +#define I2S_CHN_8 (3 << I2S_CSR_SHIFT) + +/* io direction cfg register */ +#define I2S_IO_DIRECTION_MASK (7) +#define I2S_IO_8CH_OUT_2CH_IN (7) +#define I2S_IO_6CH_OUT_4CH_IN (3) +#define I2S_IO_4CH_OUT_6CH_IN (1) +#define I2S_IO_2CH_OUT_8CH_IN (0) + +/* I2S REGS */ +#define I2S_TXCR (0x0000) +#define I2S_RXCR (0x0004) +#define I2S_CKR (0x0008) +#define I2S_TXFIFOLR (0x000c) +#define I2S_DMACR (0x0010) +#define I2S_INTCR (0x0014) +#define I2S_INTSR (0x0018) +#define I2S_XFER (0x001c) +#define I2S_CLR (0x0020) +#define I2S_TXDR (0x0024) +#define I2S_RXDR (0x0028) +#define I2S_RXFIFOLR (0x002c) +#define I2S_TDM_TXCR (0x0030) +#define I2S_TDM_RXCR (0x0034) +#define I2S_CLKDIV (0x0038) + +#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) + +/* PX30 GRF CONFIGS*/ +#define PX30_I2S0_CLK_IN_SRC_FROM_TX HIWORD_UPDATE(1, 13, 12) +#define PX30_I2S0_CLK_IN_SRC_FROM_RX HIWORD_UPDATE(2, 13, 12) +#define PX30_I2S0_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(1, 5, 5) +#define PX30_I2S0_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(0, 5, 5) + +#define PX30_I2S0_CLK_TXONLY \ + (PX30_I2S0_MCLK_OUT_SRC_FROM_TX | PX30_I2S0_CLK_IN_SRC_FROM_TX) + +#define PX30_I2S0_CLK_RXONLY \ + (PX30_I2S0_MCLK_OUT_SRC_FROM_RX | PX30_I2S0_CLK_IN_SRC_FROM_RX) + +/* RK1808 GRF CONFIGS*/ +#define RK1808_I2S0_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(1, 2, 2) +#define RK1808_I2S0_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(0, 2, 2) +#define RK1808_I2S0_CLK_IN_SRC_FROM_TX HIWORD_UPDATE(1, 1, 0) +#define RK1808_I2S0_CLK_IN_SRC_FROM_RX HIWORD_UPDATE(2, 1, 0) + +#define RK1808_I2S0_CLK_TXONLY \ + (RK1808_I2S0_MCLK_OUT_SRC_FROM_TX | RK1808_I2S0_CLK_IN_SRC_FROM_TX) + +#define RK1808_I2S0_CLK_RXONLY \ + (RK1808_I2S0_MCLK_OUT_SRC_FROM_RX | RK1808_I2S0_CLK_IN_SRC_FROM_RX) + +/* RK3308 GRF CONFIGS*/ +#define RK3308_I2S0_8CH_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(1, 10, 10) +#define RK3308_I2S0_8CH_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(0, 10, 10) +#define RK3308_I2S0_8CH_CLK_IN_RX_SRC_FROM_TX HIWORD_UPDATE(1, 9, 9) +#define RK3308_I2S0_8CH_CLK_IN_RX_SRC_FROM_RX HIWORD_UPDATE(0, 9, 9) +#define RK3308_I2S0_8CH_CLK_IN_TX_SRC_FROM_RX HIWORD_UPDATE(1, 8, 8) +#define RK3308_I2S0_8CH_CLK_IN_TX_SRC_FROM_TX HIWORD_UPDATE(0, 8, 8) +#define RK3308_I2S1_8CH_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(1, 2, 2) +#define RK3308_I2S1_8CH_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(0, 2, 2) +#define RK3308_I2S1_8CH_CLK_IN_RX_SRC_FROM_TX HIWORD_UPDATE(1, 1, 1) +#define RK3308_I2S1_8CH_CLK_IN_RX_SRC_FROM_RX HIWORD_UPDATE(0, 1, 1) +#define RK3308_I2S1_8CH_CLK_IN_TX_SRC_FROM_RX HIWORD_UPDATE(1, 0, 0) +#define RK3308_I2S1_8CH_CLK_IN_TX_SRC_FROM_TX HIWORD_UPDATE(0, 0, 0) + +#define RK3308_I2S0_CLK_TXONLY \ + (RK3308_I2S0_8CH_MCLK_OUT_SRC_FROM_TX | \ + RK3308_I2S0_8CH_CLK_IN_RX_SRC_FROM_TX | \ + RK3308_I2S0_8CH_CLK_IN_TX_SRC_FROM_TX) + +#define RK3308_I2S0_CLK_RXONLY \ + (RK3308_I2S0_8CH_MCLK_OUT_SRC_FROM_RX | \ + RK3308_I2S0_8CH_CLK_IN_RX_SRC_FROM_RX | \ + RK3308_I2S0_8CH_CLK_IN_TX_SRC_FROM_RX) + +#define RK3308_I2S1_CLK_TXONLY \ + (RK3308_I2S1_8CH_MCLK_OUT_SRC_FROM_TX | \ + RK3308_I2S1_8CH_CLK_IN_RX_SRC_FROM_TX | \ + RK3308_I2S1_8CH_CLK_IN_TX_SRC_FROM_TX) + +#define RK3308_I2S1_CLK_RXONLY \ + (RK3308_I2S1_8CH_MCLK_OUT_SRC_FROM_RX | \ + RK3308_I2S1_8CH_CLK_IN_RX_SRC_FROM_RX | \ + RK3308_I2S1_8CH_CLK_IN_TX_SRC_FROM_RX) + +/* RK3568 GRF CONFIGS*/ +#define RK3568_I2S1_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(1, 5, 5) +#define RK3568_I2S1_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(0, 5, 5) + +#define RK3568_I2S1_CLK_TXONLY \ + RK3568_I2S1_MCLK_OUT_SRC_FROM_TX + +#define RK3568_I2S1_CLK_RXONLY \ + RK3568_I2S1_MCLK_OUT_SRC_FROM_RX + +#define RK3568_I2S3_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(1, 15, 15) +#define RK3568_I2S3_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(0, 15, 15) +#define RK3568_I2S3_SCLK_SRC_FROM_TX HIWORD_UPDATE(1, 7, 7) +#define RK3568_I2S3_SCLK_SRC_FROM_RX HIWORD_UPDATE(0, 7, 7) +#define RK3568_I2S3_LRCK_SRC_FROM_TX HIWORD_UPDATE(1, 6, 6) +#define RK3568_I2S3_LRCK_SRC_FROM_RX HIWORD_UPDATE(0, 6, 6) + +#define RK3568_I2S3_MCLK_TXONLY \ + RK3568_I2S3_MCLK_OUT_SRC_FROM_TX + +#define RK3568_I2S3_CLK_TXONLY \ + (RK3568_I2S3_SCLK_SRC_FROM_TX | \ + RK3568_I2S3_LRCK_SRC_FROM_TX) + +#define RK3568_I2S3_MCLK_RXONLY \ + RK3568_I2S3_MCLK_OUT_SRC_FROM_RX + +#define RK3568_I2S3_CLK_RXONLY \ + (RK3568_I2S3_SCLK_SRC_FROM_RX | \ + RK3568_I2S3_LRCK_SRC_FROM_RX) + +/* RV1126 GRF CONFIGS*/ +#define RV1126_I2S0_MCLK_OUT_SRC_FROM_TX HIWORD_UPDATE(0, 9, 9) +#define RV1126_I2S0_MCLK_OUT_SRC_FROM_RX HIWORD_UPDATE(1, 9, 9) + +#define RV1126_I2S0_CLK_TXONLY \ + RV1126_I2S0_MCLK_OUT_SRC_FROM_TX + +#define RV1126_I2S0_CLK_RXONLY \ + RV1126_I2S0_MCLK_OUT_SRC_FROM_RX + +#endif /* _ROCKCHIP_I2S_TDM_H */ \ No newline at end of file diff --git a/drivers/dma/pl330dma/driver.h b/drivers/dma/pl330dma/driver.h index 2e72d0e..94036c5 100644 --- a/drivers/dma/pl330dma/driver.h +++ b/drivers/dma/pl330dma/driver.h @@ -17,6 +17,7 @@ #include "bitops.h" #include "pl330.h" +#include // // String definitions @@ -30,99 +31,6 @@ #define SYMBOLIC_NAME_PREFIX L"\\DosDevices\\%hs" -typedef -void -(*PDMA_NOTIFICATION_CALLBACK)( - PVOID context - ); - -typedef -HANDLE -(*PGET_HANDLE)( - IN PVOID Context, - IN int Idx - ); - -typedef -BOOLEAN -(*PFREE_HANDLE)( - IN PVOID Context, - IN HANDLE Handle - ); - -typedef -VOID -(*PSTOP_DMA)( - IN PVOID Context, - IN HANDLE Handle - ); - -typedef -VOID -(*PGET_THREAD_REGISTERS)( - IN PVOID Context, - IN HANDLE Handle, - OUT UINT32* cpc, - OUT UINT32* sa, - OUT UINT32* da - ); - -typedef -NTSTATUS -(*PSUBMIT_AUDIO_DMA) ( - IN PVOID Context, - IN HANDLE Handle, - IN BOOLEAN fromDevice, - IN UINT32 srcAddr, - IN UINT32 dstAddr, - IN UINT32 len, - IN UINT32 periodLen - ); - -typedef -NTSTATUS -(*PSUBMIT_DMA) ( - IN PVOID Context, - IN HANDLE Handle, - IN BOOLEAN fromDevice, - IN PMDL pMDL, - IN UINT32 dstAddr - ); - -typedef -NTSTATUS -(*PREGISTER_NOTIFICATION_CALLBACK)( - IN PVOID Context, - IN HANDLE Handle, - IN PDEVICE_OBJECT Fdo, - IN PDMA_NOTIFICATION_CALLBACK NotificationCallback, - IN PVOID CallbackContext - ); - -typedef -NTSTATUS -(*PUNREGISTER_NOTIFICATION_CALLBACK)( - IN PVOID Context, - IN HANDLE Handle, - IN PDMA_NOTIFICATION_CALLBACK NotificationCallback, - IN PVOID CallbackContext - ); - -DEFINE_GUID(GUID_PL330DMA_INTERFACE_STANDARD, - 0xdb4b9e2c, 0x7fc6, 0x11ee, 0x95, 0x37, 0x00, 0x15, 0x5d, 0x45, 0x35, 0x74); - -typedef struct _PL330DMA_INTERFACE_STANDARD { - INTERFACE InterfaceHeader; - PGET_HANDLE GetChannel; - PFREE_HANDLE FreeChannel; - PSTOP_DMA StopDMA; - PGET_THREAD_REGISTERS GetThreadRegisters; - PSUBMIT_AUDIO_DMA SubmitAudioDMA; - PSUBMIT_DMA SubmitDMA; //reserved for future use - PREGISTER_NOTIFICATION_CALLBACK RegisterNotificationCallback; - PUNREGISTER_NOTIFICATION_CALLBACK UnregisterNotificationCallback; -} PL330DMA_INTERFACE_STANDARD, * PPL330DMA_INTERFACE_STANDARD; - typedef struct _PL330DMA_CONFIG { #define DMAC_MODE_NS (1 << 0) UINT32 Mode; diff --git a/drivers/dma/pl330dma/pl330.vcxproj b/drivers/dma/pl330dma/pl330.vcxproj index 5781655..267af96 100644 --- a/drivers/dma/pl330dma/pl330.vcxproj +++ b/drivers/dma/pl330dma/pl330.vcxproj @@ -57,7 +57,7 @@ trace.h true false - $(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR);%(AdditionalIncludeDirectories) + ..\..\include;%(AdditionalIncludeDirectories) 1.0.0 @@ -75,7 +75,7 @@ trace.h true false - $(SPB_INC_PATH)\$(SPB_VERSION_MAJOR).$(SPB_VERSION_MINOR);%(AdditionalIncludeDirectories) + ..\..\include;%(AdditionalIncludeDirectories) 1.0.0 diff --git a/drivers/dma/pl330dma/pl330.vcxproj.Filters b/drivers/dma/pl330dma/pl330.vcxproj.Filters index 28d4ec7..4308396 100644 --- a/drivers/dma/pl330dma/pl330.vcxproj.Filters +++ b/drivers/dma/pl330dma/pl330.vcxproj.Filters @@ -30,6 +30,12 @@ Source Files + + Source Files + + + Source Files + @@ -46,5 +52,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/drivers/include/pl330dma.h b/drivers/include/pl330dma.h new file mode 100644 index 0000000..02fbe0e --- /dev/null +++ b/drivers/include/pl330dma.h @@ -0,0 +1,96 @@ +#ifndef _PL330DMA_INTERFACE_H +#define _PL330DMA_INTERFACE_H + +typedef +void +(*PDMA_NOTIFICATION_CALLBACK)( + PVOID context + ); + +typedef +HANDLE +(*PGET_HANDLE)( + IN PVOID Context, + IN int Idx + ); + +typedef +BOOLEAN +(*PFREE_HANDLE)( + IN PVOID Context, + IN HANDLE Handle + ); + +typedef +VOID +(*PSTOP_DMA)( + IN PVOID Context, + IN HANDLE Handle + ); + +typedef +VOID +(*PGET_THREAD_REGISTERS)( + IN PVOID Context, + IN HANDLE Handle, + OUT UINT32* cpc, + OUT UINT32* sa, + OUT UINT32* da + ); + +typedef +NTSTATUS +(*PSUBMIT_AUDIO_DMA) ( + IN PVOID Context, + IN HANDLE Handle, + IN BOOLEAN fromDevice, + IN UINT32 srcAddr, + IN UINT32 dstAddr, + IN UINT32 len, + IN UINT32 periodLen + ); + +typedef +NTSTATUS +(*PSUBMIT_DMA) ( + IN PVOID Context, + IN HANDLE Handle, + IN BOOLEAN fromDevice, + IN PMDL pMDL, + IN UINT32 dstAddr + ); + +typedef +NTSTATUS +(*PREGISTER_NOTIFICATION_CALLBACK)( + IN PVOID Context, + IN HANDLE Handle, + IN PDEVICE_OBJECT Fdo, + IN PDMA_NOTIFICATION_CALLBACK NotificationCallback, + IN PVOID CallbackContext + ); + +typedef +NTSTATUS +(*PUNREGISTER_NOTIFICATION_CALLBACK)( + IN PVOID Context, + IN HANDLE Handle, + IN PDMA_NOTIFICATION_CALLBACK NotificationCallback, + IN PVOID CallbackContext + ); + +DEFINE_GUID(GUID_PL330DMA_INTERFACE_STANDARD, + 0xdb4b9e2c, 0x7fc6, 0x11ee, 0x95, 0x37, 0x00, 0x15, 0x5d, 0x45, 0x35, 0x74); + +typedef struct _PL330DMA_INTERFACE_STANDARD { + INTERFACE InterfaceHeader; + PGET_HANDLE GetChannel; + PFREE_HANDLE FreeChannel; + PSTOP_DMA StopDMA; + PGET_THREAD_REGISTERS GetThreadRegisters; + PSUBMIT_AUDIO_DMA SubmitAudioDMA; + PSUBMIT_DMA SubmitDMA; //reserved for future use + PREGISTER_NOTIFICATION_CALLBACK RegisterNotificationCallback; + PUNREGISTER_NOTIFICATION_CALLBACK UnregisterNotificationCallback; +} PL330DMA_INTERFACE_STANDARD, * PPL330DMA_INTERFACE_STANDARD; +#endif \ No newline at end of file