├── .gitattributes ├── sklhdaudbus ├── hdac_stream.h ├── sof-tplg.h ├── nhlt.h ├── resource.h ├── hdac_controller.h ├── sklhdaudbus.rc ├── trace.h ├── sklhdaudbus.cpp ├── buspdo.h ├── driver.h ├── sklhdaudbus.vcxproj.filters ├── adsp.h ├── sklhdaudbus.inf ├── regfuncs.h ├── fdo.h ├── sof-tplg.cpp ├── hdac_stream.cpp ├── sklhdaudbus.vcxproj ├── nhlt.cpp ├── hda_registers.h ├── sgpc.cpp ├── adsp.cpp ├── hdac_controller.cpp ├── hda_verbs.h ├── buspdo.cpp ├── hdaudio.cpp └── fdo.cpp ├── LICENSE.txt ├── README.md ├── sklhdaudbus.sln ├── .gitignore └── sklhdaudbus Package └── sklhdaudbus Package.vcxproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /sklhdaudbus/hdac_stream.h: -------------------------------------------------------------------------------- 1 | UINT16 hdac_format(PHDAC_STREAM stream); 2 | 3 | void hdac_stream_start(PHDAC_STREAM stream); 4 | void hdac_stream_stop(PHDAC_STREAM stream); 5 | void hdac_stream_reset(PHDAC_STREAM stream); 6 | void hdac_stream_setup(PHDAC_STREAM stream); -------------------------------------------------------------------------------- /sklhdaudbus/sof-tplg.h: -------------------------------------------------------------------------------- 1 | #define SOFTPLG_MAGIC '$SOF' 2 | 3 | typedef struct _SOF_TPLG { 4 | UINT32 magic; 5 | UINT32 length; 6 | char speaker_tplg[32]; 7 | char hp_tplg[32]; 8 | char dmic_tplg[32]; 9 | } SOF_TPLG, *PSOF_TPLG; 10 | 11 | NTSTATUS GetSOFTplg(WDFDEVICE FxDevice, SOF_TPLG *sofTplg); -------------------------------------------------------------------------------- /sklhdaudbus/nhlt.h: -------------------------------------------------------------------------------- 1 | enum NHLTQueryRevision { 2 | NHLTRev1 = 1 3 | }; 4 | 5 | enum NHLTQuery { 6 | NHLTSupportQuery = 0, 7 | NHLTMemoryAddress 8 | }; 9 | 10 | NTSTATUS NHLTCheckSupported(_In_ WDFDEVICE FxDevice); 11 | NTSTATUS NHLTQueryTableAddress(_In_ WDFDEVICE FxDevice, UINT64* nhltAddr, UINT64* nhltSz); -------------------------------------------------------------------------------- /sklhdaudbus/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by sklhdaudbus.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2023 CoolStar 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /sklhdaudbus/hdac_controller.h: -------------------------------------------------------------------------------- 1 | #if !defined(_HDA_CONTROLLER_H_) 2 | #define _HDA_CONTROLLER_H_ 3 | 4 | //New 5 | NTSTATUS GetHDACapabilities(PFDO_CONTEXT fdoCtx); 6 | NTSTATUS StartHDAController(PFDO_CONTEXT fdoCtx); 7 | NTSTATUS StopHDAController(PFDO_CONTEXT fdoCtx); 8 | NTSTATUS SendHDACmds(PFDO_CONTEXT fdoCtx, ULONG count, PHDAUDIO_CODEC_TRANSFER CodecTransfer); 9 | NTSTATUS RunSingleHDACmd(PFDO_CONTEXT fdoCtx, ULONG val, ULONG* res); 10 | 11 | //Old 12 | BOOLEAN hda_interrupt(WDFINTERRUPT Interrupt, ULONG MessageID); 13 | void hda_dpc(WDFINTERRUPT Interrupt, WDFOBJECT AssociatedObject); 14 | 15 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HD Audio Bus Driver for Intel Skylake and newer 2 | 3 | * Exposes HD Audio devices 4 | * Compatible with VMWare, QEMU, and Intel Skylake / Kaby Lake / Apollo Lake / Gemini Lake / Comet Lake / Tiger Lake / Jasper Lake / Alder Lake 5 | * Compatible with Windows default codec driver (QEMU / VMWare) 6 | * Compatible with Intel Display Audio driver (Intel Lakes, and Intel Haswell / Broadwell) 7 | * Compatible with Realtek ALC283 driver (Intel Haswell / Broadwell) 8 | * Support accessing AudioDSP on Intel platforms 9 | * Compatible with csaudiosstavs and csaudiointcsof 10 | * Working Sleep / Wake 11 | * Compatible with Windows 10 / 11 64-bit -------------------------------------------------------------------------------- /sklhdaudbus/sklhdaudbus.rc: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation All Rights Reserved 4 | 5 | Module Name: 6 | 7 | sklhdaudbus.rc 8 | 9 | Abstract: 10 | 11 | --*/ 12 | 13 | #include 14 | 15 | #define VER_FILETYPE VFT_DRV 16 | #define VER_FILESUBTYPE VFT2_DRV_SYSTEM 17 | #define VER_FILEDESCRIPTION_STR "CoolStar HD Audio" 18 | #define VER_INTERNALNAME_STR "sklhdaudbus.sys" 19 | #define VER_ORIGINALFILENAME_STR "sklhdaudbus.sys" 20 | 21 | #define VER_LEGALCOPYRIGHT_YEARS "2023" 22 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." 23 | 24 | #define VER_FILEVERSION 1,0,0,0 25 | #define VER_PRODUCTVERSION_STR "1.0.0.0" 26 | #define VER_PRODUCTVERSION 1,0,0,0 27 | #define LVER_PRODUCTVERSION_STR L"1.0.0.0" 28 | 29 | #define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) 30 | #ifdef DEBUG 31 | #define VER_FILEFLAGS (VS_FF_DEBUG) 32 | #else 33 | #define VER_FILEFLAGS (0) 34 | #endif 35 | 36 | #define VER_FILEOS VOS_NT_WINDOWS32 37 | 38 | #define VER_COMPANYNAME_STR "CoolStar" 39 | #define VER_PRODUCTNAME_STR "CoolStar HD Audio" 40 | 41 | #include "common.ver" -------------------------------------------------------------------------------- /sklhdaudbus/trace.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef _TRACE_H_ 4 | #define _TRACE_H_ 5 | 6 | extern "C" 7 | { 8 | // 9 | // Tracing Definitions: 10 | // 11 | // Control GUID: 12 | // {73e3b785-f5fb-423e-94a9-56627fea9053} 13 | // 14 | 15 | #define WPP_CONTROL_GUIDS \ 16 | WPP_DEFINE_CONTROL_GUID( \ 17 | SpbTestToolTraceGuid, \ 18 | (73e3b785,f5fb,423e,94a9,56627fea9053), \ 19 | WPP_DEFINE_BIT(TRACE_FLAG_WDFLOADING) \ 20 | WPP_DEFINE_BIT(TRACE_FLAG_SPBAPI) \ 21 | WPP_DEFINE_BIT(TRACE_FLAG_OTHER) \ 22 | ) 23 | } 24 | 25 | #define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags) 26 | #define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level) 27 | 28 | #define Trace CyapaPrint 29 | #define FuncEntry 30 | #define FuncExit 31 | #define WPP_INIT_TRACING 32 | #define WPP_CLEANUP 33 | #define TRACE_FLAG_SPBAPI 0 34 | #define TRACE_FLAG_WDFLOADING 0 35 | 36 | // begin_wpp config 37 | // FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 38 | // FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 39 | // USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> entry"); 40 | // USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <--"); 41 | // end_wpp 42 | 43 | #endif _TRACE_H_ 44 | -------------------------------------------------------------------------------- /sklhdaudbus/sklhdaudbus.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | NTSTATUS 4 | SklHdAudBusEvtDeviceAdd( 5 | _In_ WDFDRIVER Driver, 6 | _Inout_ PWDFDEVICE_INIT DeviceInit 7 | ) 8 | { 9 | UNREFERENCED_PARAMETER(Driver); 10 | NTSTATUS status; 11 | 12 | // 13 | // Initialize all the properties specific to the device. 14 | // Framework has default values for the one that are not 15 | // set explicitly here. So please read the doc and make sure 16 | // you are okay with the defaults. 17 | // 18 | WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); 19 | 20 | status = Fdo_Create(DeviceInit); 21 | return status; 22 | } 23 | 24 | extern "C" NTSTATUS 25 | DriverEntry( 26 | __in PDRIVER_OBJECT DriverObject, 27 | __in PUNICODE_STRING RegistryPath 28 | ) 29 | { 30 | WDF_DRIVER_CONFIG config; 31 | NTSTATUS status; 32 | WDFDRIVER wdfDriver; 33 | 34 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 35 | "Driver Entry\n"); 36 | 37 | // 38 | // Default to NonPagedPoolNx for non paged pool allocations where supported. 39 | // 40 | 41 | ExInitializeDriverRuntime(DrvRtPoolNxOptIn); 42 | 43 | WDF_DRIVER_CONFIG_INIT(&config, SklHdAudBusEvtDeviceAdd); 44 | 45 | status = WdfDriverCreate(DriverObject, 46 | RegistryPath, 47 | WDF_NO_OBJECT_ATTRIBUTES, 48 | &config, 49 | &wdfDriver 50 | ); 51 | if (!NT_SUCCESS(status)) 52 | { 53 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 54 | "WdfDriverCreate failed %x\n", status); 55 | } 56 | 57 | return status; 58 | } 59 | -------------------------------------------------------------------------------- /sklhdaudbus/buspdo.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SKLHDAUDBUS_BUSPDO_H_) 2 | #define _SKLHDAUDBUS_BUSPDO_H_ 3 | 4 | #define MAX_INSTANCE_ID_LEN 80 5 | 6 | typedef struct _CODEC_UNSOLIT_CALLBACK { 7 | BOOLEAN inUse; 8 | PVOID Context; 9 | PHDAUDIO_UNSOLICITED_RESPONSE_CALLBACK Routine; 10 | } CODEC_UNSOLIT_CALLBACK, *PCODEC_UNSOLICIT_CALLBACK; 11 | 12 | typedef struct _CODEC_IDS { 13 | UINT32 CodecAddress; 14 | BOOL IsGraphicsCodec; 15 | 16 | UINT8 FunctionGroupStartNode; 17 | 18 | UINT16 CtlrDevId; 19 | UINT16 CtlrVenId; 20 | 21 | BOOL IsDSP; 22 | 23 | UINT16 FuncId; 24 | UINT16 VenId; 25 | UINT16 DevId; 26 | UINT32 SubsysId; 27 | UINT16 RevId; 28 | } CODEC_IDS, * PCODEC_IDS; 29 | 30 | typedef struct _PDO_IDENTIFICATION_DESCRIPTION 31 | { 32 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Header; // should contain this header 33 | 34 | PFDO_CONTEXT FdoContext; 35 | 36 | CODEC_IDS CodecIds; 37 | 38 | } PDO_IDENTIFICATION_DESCRIPTION, * PPDO_IDENTIFICATION_DESCRIPTION; 39 | 40 | #define MAX_UNSOLICIT_CALLBACKS 64 // limit is 64 for hdaudbus (See: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/hdaudio/nc-hdaudio-pregister_event_callback) 41 | #define SUBTAG_MASK 0x3F 42 | #define TAG_ADDR_SHIFT 6 43 | 44 | // 45 | // This is PDO device-extension. 46 | // 47 | typedef struct _PDO_DEVICE_DATA 48 | { 49 | PFDO_CONTEXT FdoContext; 50 | 51 | CODEC_IDS CodecIds; 52 | 53 | CODEC_UNSOLIT_CALLBACK unsolitCallbacks[MAX_UNSOLICIT_CALLBACKS]; 54 | 55 | } PDO_DEVICE_DATA, * PPDO_DEVICE_DATA; 56 | 57 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_DATA, PdoGetData) 58 | 59 | extern "C" { 60 | 61 | NTSTATUS 62 | Bus_EvtChildListIdentificationDescriptionDuplicate( 63 | WDFCHILDLIST DeviceList, 64 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER SourceIdentificationDescription, 65 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER DestinationIdentificationDescription 66 | ); 67 | 68 | BOOLEAN 69 | Bus_EvtChildListIdentificationDescriptionCompare( 70 | WDFCHILDLIST DeviceList, 71 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER FirstIdentificationDescription, 72 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER SecondIdentificationDescription 73 | ); 74 | 75 | VOID 76 | Bus_EvtChildListIdentificationDescriptionCleanup( 77 | _In_ WDFCHILDLIST DeviceList, 78 | _Inout_ PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription 79 | ); 80 | 81 | NTSTATUS 82 | Bus_EvtDeviceListCreatePdo( 83 | WDFCHILDLIST DeviceList, 84 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, 85 | PWDFDEVICE_INIT ChildInit 86 | ); 87 | 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /sklhdaudbus/driver.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SKLHDAUDBUS_H_) 2 | #define _SKLHDAUDBUS_H_ 3 | 4 | #define POOL_ZERO_DOWN_LEVEL_SUPPORT 5 | 6 | #pragma warning(disable:4200) // suppress nameless struct/union warning 7 | #pragma warning(disable:4201) // suppress nameless struct/union warning 8 | #pragma warning(disable:4214) // suppress bit field types other than int warning 9 | #include 10 | #include 11 | 12 | //SGPC (Win10 1809+ support) 13 | extern "C" { 14 | #define __CPLUSPLUS 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | } 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "hda_registers.h" 33 | #include "fdo.h" 34 | #include "buspdo.h" 35 | #include "hdac_controller.h" 36 | #include "hdac_stream.h" 37 | #include "hda_verbs.h" 38 | 39 | #define DRIVERNAME "sklhdaudbus.sys: " 40 | #define SKLHDAUDBUS_POOL_TAG 'SADH' 41 | 42 | #define VEN_INTEL 0x8086 43 | #define VEN_VMWARE 0x15AD 44 | 45 | #include "regfuncs.h" 46 | 47 | HDAUDIO_BUS_INTERFACE HDA_BusInterface(PVOID Context); 48 | HDAUDIO_BUS_INTERFACE_V2 HDA_BusInterfaceV2(PVOID Context); 49 | HDAUDIO_BUS_INTERFACE_V3 HDA_BusInterfaceV3(PVOID Context); 50 | 51 | #define IS_BXT(ven, dev) (ven == VEN_INTEL && dev == 0x5a98) 52 | 53 | static inline void mdelay(LONG msec) { 54 | LARGE_INTEGER Interval; 55 | Interval.QuadPart = -10 * 1000 * (LONGLONG)msec; 56 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 57 | } 58 | 59 | static inline void udelay(LONG usec) { 60 | LARGE_INTEGER Interval; 61 | Interval.QuadPart = -10 * (LONGLONG)usec; 62 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 63 | } 64 | 65 | // 66 | // Helper macros 67 | // 68 | 69 | #define DEBUG_LEVEL_ERROR 1 70 | #define DEBUG_LEVEL_INFO 2 71 | #define DEBUG_LEVEL_VERBOSE 3 72 | 73 | #define DBG_INIT 1 74 | #define DBG_PNP 2 75 | #define DBG_IOCTL 4 76 | 77 | static ULONG SklHdAudBusDebugLevel = 100; 78 | static ULONG SklHdAudBusDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 79 | 80 | #if 0 81 | #define SklHdAudBusPrint(dbglevel, dbgcatagory, fmt, ...) { \ 82 | if (SklHdAudBusDebugLevel >= dbglevel && \ 83 | (SklHdAudBusDebugCatagories && dbgcatagory)) \ 84 | { \ 85 | DbgPrint(DRIVERNAME); \ 86 | DbgPrint(fmt, __VA_ARGS__); \ 87 | } \ 88 | } 89 | #else 90 | #define SklHdAudBusPrint(dbglevel, fmt, ...) { \ 91 | } 92 | #endif 93 | #endif -------------------------------------------------------------------------------- /sklhdaudbus/sklhdaudbus.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {4d2da254-d169-4d8e-a302-5e9e489bdbb1} 9 | *.c 10 | 11 | 12 | {02a39469-356c-43ce-b243-807bdac88792} 13 | *.h 14 | 15 | 16 | 17 | 18 | Source 19 | 20 | 21 | Source 22 | 23 | 24 | Source 25 | 26 | 27 | Source 28 | 29 | 30 | Source 31 | 32 | 33 | Source 34 | 35 | 36 | Source 37 | 38 | 39 | Source 40 | 41 | 42 | Source 43 | 44 | 45 | Source 46 | 47 | 48 | 49 | 50 | Headers 51 | 52 | 53 | Headers 54 | 55 | 56 | Headers 57 | 58 | 59 | Headers 60 | 61 | 62 | Headers 63 | 64 | 65 | Headers 66 | 67 | 68 | Headers 69 | 70 | 71 | Headers 72 | 73 | 74 | Headers 75 | 76 | 77 | Headers 78 | 79 | 80 | Headers 81 | 82 | 83 | Source 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /sklhdaudbus.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sklhdaudbus", "sklhdaudbus\sklhdaudbus.vcxproj", "{B3E71397-9BE4-492B-AAED-4D056E59CB1F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sklhdaudbus Package", "sklhdaudbus Package\sklhdaudbus Package.vcxproj", "{EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F} = {B3E71397-9BE4-492B-AAED-4D056E59CB1F} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Release|Win32 = Release|Win32 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.Build.0 = Debug|Win32 23 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.Deploy.0 = Debug|Win32 24 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.ActiveCfg = Debug|x64 25 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.Build.0 = Debug|x64 26 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.Deploy.0 = Debug|x64 27 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.ActiveCfg = Release|Win32 28 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.Build.0 = Release|Win32 29 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.Deploy.0 = Release|Win32 30 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.ActiveCfg = Release|x64 31 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.Build.0 = Release|x64 32 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.Deploy.0 = Release|x64 33 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.ActiveCfg = Debug|Win32 34 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.Build.0 = Debug|Win32 35 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.Deploy.0 = Debug|Win32 36 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.ActiveCfg = Debug|x64 37 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.Build.0 = Debug|x64 38 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.Deploy.0 = Debug|x64 39 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.ActiveCfg = Release|Win32 40 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.Build.0 = Release|Win32 41 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.Deploy.0 = Release|Win32 42 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.ActiveCfg = Release|x64 43 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.Build.0 = Release|x64 44 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.Deploy.0 = Release|x64 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(ExtensibilityGlobals) = postSolution 50 | SolutionGuid = {86D249D6-FF1E-41F4-AA9B-3813428D6C1A} 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /sklhdaudbus/adsp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ADSP_INTERFACE 2 | #define __ADSP_INTERFACE 3 | #include 4 | 5 | // 6 | // The ADSP_BUS_INTERFACE interface GUID 7 | // 8 | // {752A2CAE-3455-4D18-A184-8B34B22632CE} 9 | DEFINE_GUID(GUID_ADSP_BUS_INTERFACE, 10 | 0x752a2cae, 0x3455, 0x4d18, 0xa1, 0x84, 0x8b, 0x34, 0xb2, 0x26, 0x32, 0xce); 11 | 12 | typedef struct _NHLT_INFO { 13 | PVOID nhlt; 14 | UINT64 nhltSz; 15 | } NHLT_INFO, * PNHLT_INFO; 16 | 17 | typedef _Must_inspect_result_ NTSTATUS(*PGET_ADSP_RESOURCES) (_In_ PVOID _context, _Out_ _PCI_BAR* hdaBar, _Out_ _PCI_BAR* adspBar, PVOID* ppcap, PNHLT_INFO nhltInfo, _Out_ BUS_INTERFACE_STANDARD* pciConfig); 18 | typedef _Must_inspect_result_ NTSTATUS(*PDSP_SET_POWER_STATE) (_In_ PVOID _context, _In_ DEVICE_POWER_STATE newPowerState); 19 | typedef _Must_inspect_result_ BOOL(*PADSP_INTERRUPT_CALLBACK)(PVOID context); 20 | typedef _Must_inspect_result_ NTSTATUS(*PREGISTER_ADSP_INTERRUPT) (_In_ PVOID _context, _In_ PADSP_INTERRUPT_CALLBACK callback, _In_ PVOID callbackContext); 21 | typedef _Must_inspect_result_ NTSTATUS(*PUNREGISTER_ADSP_INTERRUPT) (_In_ PVOID _context); 22 | typedef _Must_inspect_result_ NTSTATUS(*PGET_STREAM)(_In_ PVOID _context, HDAUDIO_STREAM_FORMAT StreamFormat, PHANDLE Handle, _Out_ UINT8* streamTag); 23 | typedef _Must_inspect_result_ NTSTATUS(*PFREE_STREAM)(_In_ PVOID _context, _In_ HANDLE Handle); 24 | typedef _Must_inspect_result_ NTSTATUS(*PDSP_PREPARE_STREAM)(_In_ PVOID _context, _In_ HANDLE Handle, _In_ unsigned int ByteSize, _In_ int frags, _Out_ PVOID* bdlBuf); 25 | typedef _Must_inspect_result_ NTSTATUS(*PDSP_CLEANUP_STREAM)(_In_ PVOID _context, _In_ HANDLE Handle); 26 | typedef _Must_inspect_result_ UINT32(*PDSP_STREAM_POSITION)(_In_ PVOID _context, _In_ HANDLE Handle); 27 | typedef void (*PDSP_START_STOP_STREAM)(_In_ PVOID _context, _In_ HANDLE Handle, BOOL startStop); 28 | typedef void (*PDSP_ENABLE_SPIB)(_In_ PVOID _context, _In_ HANDLE Handle, UINT32 value); 29 | typedef void (*PDSP_DISABLE_SPIB)(_In_ PVOID _context, _In_ HANDLE Handle); 30 | 31 | typedef struct _ADSP_BUS_INTERFACE 32 | { 33 | // 34 | // First we define the standard INTERFACE structure ... 35 | // 36 | USHORT Size; 37 | USHORT Version; 38 | PVOID Context; 39 | PINTERFACE_REFERENCE InterfaceReference; 40 | PINTERFACE_DEREFERENCE InterfaceDereference; 41 | 42 | // 43 | // Then we expand the structure with the ADSP_BUS_INTERFACE stuff. 44 | 45 | UINT16 CtlrDevId; 46 | PGET_ADSP_RESOURCES GetResources; 47 | PDSP_SET_POWER_STATE SetDSPPowerState; 48 | PREGISTER_ADSP_INTERRUPT RegisterInterrupt; 49 | PUNREGISTER_ADSP_INTERRUPT UnregisterInterrupt; 50 | PGET_STREAM GetRenderStream; 51 | PGET_STREAM GetCaptureStream; 52 | PFREE_STREAM FreeStream; 53 | PDSP_PREPARE_STREAM PrepareDSP; 54 | PDSP_CLEANUP_STREAM CleanupDSP; 55 | PDSP_START_STOP_STREAM TriggerDSP; 56 | PDSP_STREAM_POSITION StreamPosition; 57 | 58 | PDSP_ENABLE_SPIB DSPEnableSPIB; 59 | PDSP_DISABLE_SPIB DSPDisableSPIB; 60 | } ADSP_BUS_INTERFACE, * PADSP_BUS_INTERFACE; 61 | 62 | #ifndef ADSP_DECL 63 | ADSP_BUS_INTERFACE ADSP_BusInterface(PVOID Context); 64 | #endif 65 | #endif -------------------------------------------------------------------------------- /sklhdaudbus/sklhdaudbus.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ;Copyright (c) CoolStar. All rights reserved. 4 | ; 5 | ;Module Name: 6 | ; sklhdaudbus.inf 7 | ; 8 | ;Abstract: 9 | ; INF file for installing the SKL HD Aud Bus Driver 10 | ; 11 | ; 12 | ;--*/ 13 | 14 | [Version] 15 | Signature = "$WINDOWS NT$" 16 | Class = System 17 | ClassGuid = {4d36e97d-e325-11ce-bfc1-08002be10318} 18 | Provider = CoolStar 19 | DriverVer = 8/15/2022,1.0.0 20 | CatalogFile = sklhdaudbus.cat 21 | PnpLockdown = 1 22 | 23 | [DestinationDirs] 24 | DefaultDestDir = 12 25 | 26 | ; ================= Class section ===================== 27 | 28 | [SourceDisksNames] 29 | 1 = %DiskId1%,,,"" 30 | 31 | [SourceDisksFiles] 32 | sklhdaudbus.sys = 1,, 33 | 34 | [SignatureAttributes] 35 | sklhdaudbus.sys=SignatureAttributes.DRM 36 | 37 | [SignatureAttributes.DRM] 38 | DRMLevel=1300 39 | 40 | [SignatureAttributes.PETrust] 41 | PETrust=true 42 | 43 | ;***************************************** 44 | ; SklHDAudBus Install Section 45 | ;***************************************** 46 | 47 | [Manufacturer] 48 | %StdMfg%=Standard,NT$ARCH$ 49 | 50 | ; Decorated model section take precedence over undecorated 51 | ; ones on XP and later. 52 | [Standard.NT$ARCH$] 53 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_9D70&CC_0401 ;Intel Skylake 54 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_9D71&CC_0401 ;Intel Kaby Lake 55 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_5A98&CC_0401 ;Intel Apollo Lake 56 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_3198&CC_0401 ;Intel Gemini Lake 57 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_02C8&CC_0401 ;Intel Comet Lake 58 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_4DC8&CC_0401 ;Intel Jasper Lake 59 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_A0C8&CC_0401 ;Intel Tiger Lake 60 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51C8&CC_0401 ;Intel Alder Lake-P 61 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51CC&CC_0401 ;Intel Alder Lake-M 62 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51CD&CC_0401 ;Intel Alder Lake-P 63 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_54C8&CC_0401 ;Intel Alder Lake-N 64 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51CA&CC_0401 ;Intel Raptor Lake-P 65 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51CB&CC_0401 ;Intel Raptor Lake-P 66 | %SklHDAudBus.DeviceDesc%=SklHDAudBus_Device, PCI\VEN_8086&DEV_51CE&CC_0401 ;Intel Raptor Lake-M 67 | 68 | [SklHDAudBus_Device.NT] 69 | CopyFiles=Drivers_Dir 70 | 71 | [SklHDAudBus_Device.NT.HW] 72 | AddReg=SklHDAudBus_AddReg 73 | 74 | [Drivers_Dir] 75 | sklhdaudbus.sys 76 | 77 | [SklHDAudBus_AddReg] 78 | ; Set to 1 to connect the first interrupt resource found, 0 to leave disconnected 79 | HKR,Settings,"ConnectInterrupt",0x00010001,0 80 | 81 | ;-------------- Service installation 82 | [SklHDAudBus_Device.NT.Services] 83 | AddService = SklHDAudBus,%SPSVCINST_ASSOCSERVICE%, SklHDAudBus_Service_Inst 84 | 85 | ; -------------- SklHDAudBus driver install sections 86 | [SklHDAudBus_Service_Inst] 87 | DisplayName = %SklHDAudBus.SVCDESC% 88 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 89 | StartType = 3 ; SERVICE_DEMAND_START 90 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 91 | ServiceBinary = %12%\sklhdaudbus.sys 92 | LoadOrderGroup = Base 93 | 94 | [Strings] 95 | SPSVCINST_ASSOCSERVICE= 0x00000002 96 | StdMfg = "CoolStar" 97 | DiskId1 = "CoolStar HD Audio Installation Disk #1" 98 | SklHDAudBus.DeviceDesc = "CoolStar HD Audio" 99 | SklHDAudBus.SVCDESC = "CoolStar HD Audio Service" 100 | -------------------------------------------------------------------------------- /sklhdaudbus/regfuncs.h: -------------------------------------------------------------------------------- 1 | static inline UINT8 read8(PVOID addr) { 2 | UINT8 ret = *(UINT8*)addr; 3 | return ret; 4 | } 5 | 6 | static inline void write8(PVOID addr, UINT8 data) { 7 | *(UINT8*)addr = data; 8 | } 9 | 10 | static inline UINT16 read16(PVOID addr) { 11 | UINT16 ret = *(UINT16*)addr; 12 | return ret; 13 | } 14 | 15 | static inline void write16(PVOID addr, UINT16 data) { 16 | *(UINT16*)addr = data; 17 | } 18 | 19 | static inline UINT32 read32(PVOID addr) { 20 | UINT32 ret = *(UINT32*)addr; 21 | return ret; 22 | } 23 | 24 | static inline void write32(PVOID addr, UINT32 data) { 25 | *(UINT32*)addr = data; 26 | } 27 | 28 | static inline void pci_read_cfg_byte(PBUS_INTERFACE_STANDARD pciInterface, UINT reg, BYTE* data) { 29 | if (!data) { 30 | return; 31 | } 32 | pciInterface->GetBusData(pciInterface->Context, PCI_WHICHSPACE_CONFIG, data, reg, sizeof(BYTE)); 33 | } 34 | 35 | static inline void pci_read_cfg_dword(PBUS_INTERFACE_STANDARD pciInterface, UINT reg, UINT32* data) { 36 | if (!data) { 37 | return; 38 | } 39 | pciInterface->GetBusData(pciInterface->Context, PCI_WHICHSPACE_CONFIG, data, reg, sizeof(UINT32)); 40 | } 41 | 42 | static inline void pci_write_cfg_byte(PBUS_INTERFACE_STANDARD pciInterface, UINT reg, BYTE data) { 43 | pciInterface->SetBusData(pciInterface->Context, PCI_WHICHSPACE_CONFIG, &data, reg, sizeof(BYTE)); 44 | } 45 | 46 | static inline void pci_write_cfg_dword(PBUS_INTERFACE_STANDARD pciInterface, UINT reg, UINT32 data) { 47 | pciInterface->GetBusData(pciInterface->Context, PCI_WHICHSPACE_CONFIG, &data, reg, sizeof(UINT32)); 48 | } 49 | 50 | static inline void update_pci_byte(PBUS_INTERFACE_STANDARD pciInterface, UINT reg, BYTE mask, BYTE val) { 51 | BYTE data; 52 | pci_read_cfg_byte(pciInterface, reg, &data); 53 | data &= ~mask; 54 | data |= (val & mask); 55 | pci_write_cfg_byte(pciInterface, reg, data); 56 | } 57 | 58 | #define HDA_RATE(base, mult, div) \ 59 | (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ 60 | (((div) - 1) << AC_FMT_DIV_SHIFT)) 61 | 62 | #define hda_read8(ctx, reg) read8((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg) 63 | #define hda_write8(ctx, reg, data) write8((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg, data) 64 | #define hda_update8(ctx, reg, mask, val) hda_write8(ctx, reg, (hda_read8(ctx, reg) & ~(mask)) | (val)) 65 | #define hda_read16(ctx, reg) read16((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg) 66 | #define hda_write16(ctx, reg, data) write16((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg, data) 67 | #define hda_update16(ctx, reg, mask, val) hda_write16(ctx, reg, (hda_read16(ctx, reg) & ~(mask)) | (val)) 68 | #define hda_read32(ctx, reg) read32((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg) 69 | #define hda_write32(ctx, reg, data) write32((ctx)->m_BAR0.Base.baseptr + HDA_REG_##reg, data) 70 | #define hda_update32(ctx, reg, mask, val) hda_write32(ctx, reg, (hda_read32(ctx, reg) & ~(mask)) | (val)) 71 | 72 | #define stream_read8(ctx, reg) read8((ctx)->sdAddr + HDA_REG_##reg) 73 | #define stream_write8(ctx, reg, data) write8((ctx)->sdAddr + HDA_REG_##reg, data) 74 | #define stream_update8(ctx, reg, mask, val) stream_write8(ctx, reg, (stream_read8(ctx, reg) & ~(mask)) | (val)) 75 | #define stream_read16(ctx, reg) read16((ctx)->sdAddr + HDA_REG_##reg) 76 | #define stream_write16(ctx, reg, data) write16((ctx)->sdAddr + HDA_REG_##reg, data) 77 | #define stream_update16(ctx, reg, mask, val) stream_write16(ctx, reg, (stream_read16(ctx, reg) & ~(mask)) | (val)) 78 | #define stream_read32(ctx, reg) read32((ctx)->sdAddr + HDA_REG_##reg) 79 | #define stream_write32(ctx, reg, data) write32((ctx)->sdAddr + HDA_REG_##reg, data) 80 | #define stream_update32(ctx, reg, mask, val) stream_write32(ctx, reg, (stream_read32(ctx, reg) & ~(mask)) | (val)) 81 | 82 | /* update register macro */ 83 | #define hdac_update32(addr, reg, mask, val) \ 84 | write32(addr + reg, ((read32(addr + reg) & ~(mask)) | (val))) 85 | 86 | #define hdac_update16(addr, reg, mask, val) \ 87 | write16(addr + reg,((read16(addr + reg) & ~(mask)) | (val))) -------------------------------------------------------------------------------- /sklhdaudbus/fdo.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SKLHDAUDBUS_FDO_H_) 2 | #define _SKLHDAUDBUS_FDO_H_ 3 | 4 | union baseaddr { 5 | PVOID Base; 6 | UINT8* baseptr; 7 | }; 8 | 9 | typedef struct _PCI_BAR { 10 | union baseaddr Base; 11 | ULONG Len; 12 | } PCI_BAR, * PPCI_BAR; 13 | 14 | #include "adsp.h" 15 | 16 | #define HDA_UNSOL_QUEUE_SIZE 64 17 | #define MAX_NOTIF_EVENTS 16 18 | #define HDA_MAX_CODECS 16 /* limit by controller side */ 19 | 20 | struct _FDO_CONTEXT; 21 | struct _PDO_DEVICE_DATA; 22 | 23 | typedef struct _HDAC_STREAM_CALLBACK { 24 | BOOLEAN InUse; 25 | PDEVICE_OBJECT Fdo; 26 | PHDAUDIO_DMA_NOTIFICATION_CALLBACK NotificationCallback; 27 | PVOID CallbackContext; 28 | } HDAC_STREAM_CALLBACK, *PHDAC_STREAM_CALLBACK; 29 | 30 | typedef struct _HDAC_BDLENTRY { 31 | UINT32 lowAddr; 32 | UINT32 highAddr; 33 | UINT32 len; 34 | UINT32 ioc; 35 | } HDAC_BDLENTRY, *PHDAC_BDLENTRY; 36 | 37 | typedef struct _HDAC_STREAM { 38 | struct _FDO_CONTEXT* FdoContext; 39 | struct _PDO_DEVICE_DATA* PdoContext; 40 | 41 | PMDL mdlBuf; 42 | UINT32* posbuf; 43 | 44 | HDAC_BDLENTRY* bdl; 45 | 46 | BOOLEAN stripe; 47 | 48 | UINT32 bufSz; 49 | UINT32 periodBytes; 50 | UINT32 fifoSize; 51 | UINT16 numBlocks; 52 | 53 | UINT8* sdAddr; 54 | UINT32 int_sta_mask; 55 | 56 | UINT8* spib_addr; //spbcap 57 | 58 | UINT8 streamTag; 59 | UINT8 idx; 60 | 61 | HDAUDIO_STREAM_FORMAT streamFormat; 62 | 63 | PKEVENT registeredEvents[MAX_NOTIF_EVENTS]; 64 | HDAC_STREAM_CALLBACK registeredCallbacks[MAX_NOTIF_EVENTS]; 65 | 66 | BOOLEAN running; 67 | BOOLEAN irqReceived; 68 | } HDAC_STREAM, *PHDAC_STREAM; 69 | 70 | typedef struct _HDAC_RIRB { 71 | UINT32 response; 72 | UINT32 response_ex; 73 | } HDAC_RIRB, *PHDAC_RIRB; 74 | 75 | typedef struct _HDAC_CODEC_XFER { 76 | PHDAUDIO_CODEC_TRANSFER xfer[HDA_MAX_CORB_ENTRIES]; 77 | } HDAC_CODEC_XFER, *PHDAC_CODEC_XFER; 78 | 79 | typedef struct _HDAC_RB { 80 | union { 81 | UINT32* buf; 82 | PHDAC_RIRB rirbbuf; 83 | }; 84 | PHYSICAL_ADDRESS addr; 85 | UINT16 rp, wp; 86 | LONG cmds[HDA_MAX_CODECS]; 87 | KEVENT xferEvent[HDA_MAX_CODECS]; 88 | HDAC_CODEC_XFER xfer[HDA_MAX_CODECS]; 89 | } HDAC_RB, *PHDAC_RB; 90 | 91 | typedef struct _GRAPHICSWORKITEM_CONTEXT { 92 | struct _FDO_CONTEXT* FdoContext; 93 | UNICODE_STRING GPUDeviceSymlink; 94 | } GRAPHICSWORKITEM_CONTEXT, *PGRAPHICSWORKITEM_CONTEXT; 95 | 96 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(GRAPHICSWORKITEM_CONTEXT, GraphicsWorkitem_GetContext) 97 | 98 | typedef struct _GRAPHICSIOTARGET_CONTEXT { 99 | struct _FDO_CONTEXT* FdoContext; 100 | DXGK_GRAPHICSPOWER_REGISTER_OUTPUT graphicsPowerRegisterOutput; 101 | } GRAPHICSIOTARGET_CONTEXT, *PGRAPHICSIOTARGET_CONTEXT; 102 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(GRAPHICSIOTARGET_CONTEXT, GraphicsIoTarget_GetContext) 103 | 104 | typedef struct _FDO_CONTEXT 105 | { 106 | WDFDEVICE WdfDevice; 107 | 108 | UINT16 venId; 109 | UINT16 devId; 110 | UINT8 revId; 111 | 112 | PCI_BAR m_BAR0; //required 113 | PCI_BAR m_BAR4; //Intel AudioDSP 114 | BUS_INTERFACE_STANDARD BusInterface; //PCI Bus Interface 115 | WDFINTERRUPT Interrupt; 116 | 117 | //Graphics Notifications 118 | PVOID GraphicsNotificationHandle; 119 | WDFWAITLOCK GraphicsDevicesCollectionWaitLock; 120 | WDFCOLLECTION GraphicsDevicesCollection; 121 | ULONG GraphicsCodecAddress; 122 | BOOLEAN UseSGPCCodec; 123 | 124 | UINT8 *mlcap; 125 | UINT8 *ppcap; 126 | UINT8 *spbcap; 127 | 128 | BOOLEAN ControllerEnabled; 129 | 130 | BOOLEAN is64BitOK; 131 | UINT16 hwVersion; 132 | 133 | UINT32 captureIndexOff; 134 | UINT32 playbackIndexOff; 135 | UINT32 captureStreams; 136 | UINT32 playbackStreams; 137 | UINT32 numStreams; 138 | 139 | PHDAC_STREAM streams; 140 | struct _PDO_DEVICE_DATA* codecs[HDA_MAX_CODECS]; 141 | 142 | PADSP_INTERRUPT_CALLBACK dspInterruptCallback; 143 | PVOID dspInterruptContext; 144 | PVOID nhlt; 145 | UINT64 nhltSz; 146 | PVOID sofTplg; 147 | UINT64 sofTplgSz; 148 | 149 | //unsolicited events 150 | HDAC_RIRB unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; 151 | UINT unsol_rp, unsol_wp; 152 | BOOL processUnsol; 153 | 154 | //bit flags of detected codecs 155 | UINT16 codecMask; 156 | USHORT numCodecs; 157 | 158 | HDAC_RB corb; 159 | HDAC_RB rirb; 160 | 161 | UINT8 *rb; //CORB and RIRB buffers 162 | PVOID posbuf; 163 | } FDO_CONTEXT, * PFDO_CONTEXT; 164 | 165 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_CONTEXT, Fdo_GetContext) 166 | 167 | NTSTATUS 168 | Fdo_Create( 169 | _Inout_ PWDFDEVICE_INIT DeviceInit 170 | ); 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /sklhdaudbus/sof-tplg.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include 3 | #include "sof-tplg.h" 4 | 5 | DEFINE_GUID(GUID_ACPI_DSD, 6 | 0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01); 7 | 8 | void copyDSDParam(PACPI_METHOD_ARGUMENT dsdParameterData, char** buf) { 9 | RtlZeroMemory(buf, 32); 10 | RtlCopyMemory(buf, dsdParameterData->Data, min(dsdParameterData->DataLength, 32)); 11 | } 12 | 13 | NTSTATUS 14 | GetSOFTplg( 15 | _In_ WDFDEVICE FxDevice, 16 | SOF_TPLG* sofTplg 17 | ) 18 | { 19 | if (!sofTplg) { 20 | return STATUS_INVALID_PARAMETER; 21 | } 22 | 23 | NTSTATUS status = STATUS_ACPI_NOT_INITIALIZED; 24 | ACPI_EVAL_INPUT_BUFFER_EX inputBuffer; 25 | RtlZeroMemory(&inputBuffer, sizeof(inputBuffer)); 26 | 27 | inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE_EX; 28 | status = RtlStringCchPrintfA( 29 | inputBuffer.MethodName, 30 | sizeof(inputBuffer.MethodName), 31 | "_DSD" 32 | ); 33 | if (!NT_SUCCESS(status)) { 34 | return status; 35 | } 36 | 37 | ACPI_EVAL_OUTPUT_BUFFER outputSizeBuffer = { 0 }; 38 | 39 | WDF_MEMORY_DESCRIPTOR outputSizeMemDesc; 40 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputSizeMemDesc, &outputSizeBuffer, (ULONG)sizeof(outputSizeBuffer)); 41 | 42 | WDF_MEMORY_DESCRIPTOR inputMemDesc; 43 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputMemDesc, &inputBuffer, (ULONG)sizeof(inputBuffer)); 44 | 45 | // Send the request along 46 | status = WdfIoTargetSendInternalIoctlSynchronously( 47 | WdfDeviceGetIoTarget(FxDevice), 48 | NULL, 49 | IOCTL_ACPI_EVAL_METHOD_EX, 50 | &inputMemDesc, 51 | &outputSizeMemDesc, 52 | NULL, 53 | NULL 54 | ); 55 | 56 | if (status != STATUS_BUFFER_OVERFLOW) { 57 | // Method might not exist? 58 | return status; 59 | } 60 | 61 | WDFMEMORY outputMemory; 62 | PACPI_EVAL_OUTPUT_BUFFER outputBuffer; 63 | size_t outputArgumentBufferSize = outputSizeBuffer.Length; 64 | size_t outputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + outputArgumentBufferSize; 65 | 66 | WDF_OBJECT_ATTRIBUTES attributes; 67 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 68 | attributes.ParentObject = FxDevice; 69 | 70 | status = WdfMemoryCreate(&attributes, 71 | NonPagedPoolNx, 72 | 0, 73 | outputBufferSize, 74 | &outputMemory, 75 | (PVOID*)&outputBuffer); 76 | if (!NT_SUCCESS(status)) { 77 | return status; 78 | } 79 | 80 | RtlZeroMemory(outputBuffer, outputBufferSize); 81 | 82 | WDF_MEMORY_DESCRIPTOR outputMemDesc; 83 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&outputMemDesc, outputMemory, NULL); 84 | 85 | status = WdfIoTargetSendInternalIoctlSynchronously( 86 | WdfDeviceGetIoTarget(FxDevice), 87 | NULL, 88 | IOCTL_ACPI_EVAL_METHOD_EX, 89 | &inputMemDesc, 90 | &outputMemDesc, 91 | NULL, 92 | NULL 93 | ); 94 | if (!NT_SUCCESS(status)) { 95 | goto Exit; 96 | } 97 | 98 | if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) { 99 | goto Exit; 100 | } 101 | 102 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 103 | "Evaluted %s successfully\n", inputBuffer.MethodName); 104 | 105 | if (outputBuffer->Count % 2) { 106 | status = STATUS_ACPI_INVALID_DATA; 107 | goto Exit; 108 | } 109 | 110 | status = STATUS_NOT_FOUND; 111 | 112 | RtlZeroMemory(sofTplg, sizeof(*sofTplg)); 113 | sofTplg->magic = SOFTPLG_MAGIC; 114 | sofTplg->length = sizeof(*sofTplg); 115 | 116 | PACPI_METHOD_ARGUMENT currArgument = &outputBuffer->Argument[0]; 117 | for (ULONG i = 0; i < outputBuffer->Count; i += 2) { 118 | PACPI_METHOD_ARGUMENT guidArg = currArgument; 119 | currArgument = ACPI_METHOD_NEXT_ARGUMENT(currArgument); 120 | PACPI_METHOD_ARGUMENT packageArg = currArgument; 121 | currArgument = ACPI_METHOD_NEXT_ARGUMENT(currArgument); 122 | 123 | if (guidArg->Type != ACPI_METHOD_ARGUMENT_BUFFER || 124 | guidArg->DataLength != 16 || 125 | packageArg->Type != ACPI_METHOD_ARGUMENT_PACKAGE) { 126 | break; 127 | } 128 | 129 | if (memcmp(guidArg->Data, &GUID_ACPI_DSD, guidArg->DataLength) != 0) { 130 | continue; 131 | } 132 | 133 | status = STATUS_SUCCESS; 134 | 135 | FOR_EACH_ACPI_METHOD_ARGUMENT(dsdParameter, (PACPI_METHOD_ARGUMENT)packageArg->Data, (PACPI_METHOD_ARGUMENT)(packageArg->Data + packageArg->DataLength)) { 136 | PACPI_METHOD_ARGUMENT dsdParameterName = (PACPI_METHOD_ARGUMENT)dsdParameter->Data; 137 | PACPI_METHOD_ARGUMENT dsdParameterData = ACPI_METHOD_NEXT_ARGUMENT(dsdParameterName); 138 | 139 | if (strncmp((const char*)&dsdParameterName->Data[0], "speaker-tplg", dsdParameterName->DataLength) == 0) { 140 | copyDSDParam(dsdParameterData, (char **)&sofTplg->speaker_tplg); 141 | } 142 | else if (strncmp((const char*)&dsdParameterName->Data[0], "hp-tplg", dsdParameterName->DataLength) == 0) { 143 | copyDSDParam(dsdParameterData, (char**)&sofTplg->hp_tplg); 144 | } 145 | else if (strncmp((const char*)&dsdParameterName->Data[0], "mic-tplg", dsdParameterName->DataLength) == 0) { 146 | copyDSDParam(dsdParameterData, (char**)&sofTplg->dmic_tplg); 147 | } 148 | } 149 | } 150 | 151 | Exit: 152 | if (outputMemory != WDF_NO_HANDLE) { 153 | WdfObjectDelete(outputMemory); 154 | } 155 | return status; 156 | } -------------------------------------------------------------------------------- /sklhdaudbus/hdac_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | void hdac_stream_start(PHDAC_STREAM stream) { 4 | hda_read32(stream->FdoContext, WALLCLK); 5 | 6 | /* enable SIE */ 7 | hda_update32(stream->FdoContext, INTCTL, 1 << stream->idx, 1 << stream->idx); 8 | 9 | /* set stripe control */ 10 | if (stream->stripe) { 11 | UINT8 stripe_ctl = 1; 12 | stream_update8(stream, SD_CTL_3B, SD_CTL_STRIPE_MASK, 13 | stripe_ctl); 14 | } 15 | 16 | /* set DMA start and interrupt mask */ 17 | stream_update8(stream, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); 18 | stream->running = TRUE; 19 | } 20 | 21 | void hdac_stream_clear(PHDAC_STREAM stream) { 22 | stream_update8(stream, SD_CTL, SD_CTL_DMA_START | SD_INT_MASK, 0); 23 | stream_write8(stream, SD_STS, SD_INT_MASK); /* to be sure */ 24 | if (stream->stripe) 25 | stream_update8(stream, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); 26 | 27 | stream->running = FALSE; 28 | } 29 | 30 | void hdac_stream_stop(PHDAC_STREAM stream) { 31 | hdac_stream_clear(stream); 32 | 33 | /* disable SIE */ 34 | hda_update32(stream->FdoContext, INTCTL, 1 << stream->idx, 0); 35 | } 36 | 37 | void hdac_stream_reset(PHDAC_STREAM stream) { 38 | hdac_stream_clear(stream); 39 | 40 | UINT8 dma_run_state; 41 | dma_run_state = stream_read8(stream, SD_CTL) & SD_CTL_DMA_START; 42 | 43 | stream_update8(stream, SD_CTL, 0, SD_CTL_STREAM_RESET); 44 | udelay(3); 45 | int timeout = 300; 46 | 47 | UCHAR val; 48 | do { 49 | val = stream_read8(stream, SD_CTL) & SD_CTL_STREAM_RESET; 50 | if (val) 51 | break; 52 | } while (--timeout); 53 | 54 | val &= ~SD_CTL_STREAM_RESET; 55 | stream_write8(stream, SD_CTL, val); 56 | udelay(3); 57 | 58 | timeout = 300; 59 | /* waiting for hardware to report that the stream is out of reset */ 60 | do { 61 | val = stream_read8(stream, SD_CTL) & SD_CTL_STREAM_RESET; 62 | if (!val) 63 | break; 64 | } while (--timeout); 65 | 66 | if (stream->posbuf) 67 | *stream->posbuf = 0; 68 | } 69 | 70 | UINT16 hdac_format(PHDAC_STREAM stream) { 71 | UINT16 format = 0; 72 | 73 | switch (stream->streamFormat.SampleRate) { 74 | case 8000: 75 | format = HDA_RATE(48, 1, 6); 76 | break; 77 | case 9600: 78 | format = HDA_RATE(48, 1, 5); 79 | break; 80 | case 11025: 81 | format = HDA_RATE(44, 1, 4); 82 | break; 83 | case 16000: 84 | format = HDA_RATE(48, 1, 3); 85 | break; 86 | case 22050: 87 | format = HDA_RATE(44, 1, 2); 88 | break; 89 | case 32000: 90 | format = HDA_RATE(48, 2, 3); 91 | break; 92 | case 44100: 93 | format = HDA_RATE(44, 1, 1); 94 | break; 95 | case 48000: 96 | format = HDA_RATE(48, 1, 1); 97 | break; 98 | case 88200: 99 | format = HDA_RATE(44, 2, 1); 100 | break; 101 | case 96000: 102 | format = HDA_RATE(48, 2, 1); 103 | break; 104 | case 176400: 105 | format = HDA_RATE(44, 4, 1); 106 | break; 107 | case 192000: 108 | format = HDA_RATE(48, 4, 1); 109 | break; 110 | } 111 | 112 | { 113 | UINT16 channels = stream->streamFormat.NumberOfChannels; 114 | if (channels == 0 || channels > 8) 115 | return 0; 116 | format |= channels - 1; 117 | 118 | switch (stream->streamFormat.ContainerSize) { 119 | case 8: 120 | format |= AC_FMT_BITS_8; 121 | break; 122 | case 16: 123 | format |= AC_FMT_BITS_16; 124 | break; 125 | case 20: 126 | format |= AC_FMT_BITS_20; 127 | break; 128 | case 24: 129 | format |= AC_FMT_BITS_24; 130 | break; 131 | case 32: 132 | format |= AC_FMT_BITS_32; 133 | break; 134 | } 135 | } 136 | return format; 137 | } 138 | 139 | void hdac_stream_setup(PHDAC_STREAM stream) { 140 | /* make sure the run bit is zero for SD */ 141 | hdac_stream_clear(stream); 142 | 143 | UINT val; 144 | /* program the stream_tag */ 145 | val = stream_read32(stream, SD_CTL); 146 | val = (val & ~SD_CTL_STREAM_TAG_MASK) | 147 | (stream->streamTag << SD_CTL_STREAM_TAG_SHIFT); 148 | stream_write32(stream, SD_CTL, val); 149 | 150 | /* program the length of samples in cyclic buffer */ 151 | stream_write32(stream, SD_CBL, stream->bufSz); 152 | 153 | /* program the stream format */ 154 | /* this value needs to be the same as the one programmed */ 155 | UINT16 format = hdac_format(stream); 156 | stream_write16(stream, SD_FORMAT, format); 157 | 158 | /* program the stream LVI (last valid index) of the BDL */ 159 | stream_write16(stream, SD_LVI, stream->numBlocks - 1); 160 | 161 | /* program the BDL address */ 162 | /* lower BDL address */ 163 | PHYSICAL_ADDRESS bdlAddr = MmGetPhysicalAddress(stream->bdl); 164 | stream_write32(stream, SD_BDLPL, bdlAddr.LowPart); 165 | /* upper BDL address */ 166 | stream_write32(stream, SD_BDLPU, bdlAddr.HighPart); 167 | 168 | //Enable position buffer 169 | if (!(hda_read32(stream->FdoContext, DPLBASE) & HDA_DPLBASE_ENABLE)){ 170 | PHYSICAL_ADDRESS posbufAddr = MmGetPhysicalAddress(stream->FdoContext->posbuf); 171 | hda_write32(stream->FdoContext, DPLBASE, posbufAddr.LowPart | HDA_DPLBASE_ENABLE); 172 | } 173 | 174 | /* set the interrupt enable bits in the descriptor control register */ 175 | stream_update32(stream, SD_CTL, 0, SD_INT_MASK); 176 | 177 | stream->fifoSize = 0; 178 | stream->fifoSize = stream_read16(stream, SD_FIFOSIZE) + 1; 179 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /sklhdaudbus Package/sklhdaudbus Package.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B} 23 | {4605da2c-74a5-4865-98e1-152ef136825f} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | sklhdaudbus_Package 29 | $(LatestTargetPlatformVersion) 30 | sklhdaudbus Package 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Utility 38 | Package 39 | true 40 | 41 | 42 | Windows10 43 | false 44 | WindowsKernelModeDriver10.0 45 | Utility 46 | Package 47 | true 48 | 49 | 50 | Windows10 51 | true 52 | WindowsKernelModeDriver10.0 53 | Utility 54 | Package 55 | true 56 | 57 | 58 | Windows10 59 | false 60 | WindowsKernelModeDriver10.0 61 | Utility 62 | Package 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | DbgengKernelDebugger 75 | False 76 | True 77 | 78 | 79 | 80 | False 81 | False 82 | True 83 | 84 | 133563 85 | 86 | 87 | DbgengKernelDebugger 88 | False 89 | True 90 | 91 | 92 | 93 | False 94 | False 95 | True 96 | 97 | 133563 98 | 99 | 100 | DbgengKernelDebugger 101 | False 102 | True 103 | 104 | 105 | 106 | False 107 | False 108 | True 109 | 110 | 133563 111 | 112 | 113 | DbgengKernelDebugger 114 | False 115 | True 116 | 117 | 118 | 119 | False 120 | False 121 | True 122 | 123 | 133563 124 | 125 | 126 | 127 | SHA256 128 | 129 | 130 | 131 | 132 | SHA256 133 | 134 | 135 | 136 | 137 | SHA256 138 | 139 | 140 | 141 | 142 | SHA256 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | {b3e71397-9be4-492b-aaed-4d056e59cb1f} 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /sklhdaudbus/sklhdaudbus.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F} 23 | {1bc93793-694f-48fe-9372-81e2b05556fd} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | sklhdaudbus 29 | $(LatestTargetPlatformVersion) 30 | sklhdaudbus 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Driver 38 | KMDF 39 | 40 | 41 | Windows10 42 | false 43 | WindowsKernelModeDriver10.0 44 | Driver 45 | KMDF 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | 54 | 55 | Windows10 56 | false 57 | WindowsKernelModeDriver10.0 58 | Driver 59 | KMDF 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | DbgengKernelDebugger 71 | 72 | 73 | DbgengKernelDebugger 74 | 75 | 76 | DbgengKernelDebugger 77 | 78 | 79 | DbgengKernelDebugger 80 | 81 | 82 | 83 | true 84 | trace.h 85 | true 86 | false 87 | 88 | 89 | 1.0.0 90 | 91 | 92 | SHA256 93 | 94 | 95 | 96 | 97 | true 98 | trace.h 99 | true 100 | false 101 | 102 | 103 | 1.0.0 104 | 105 | 106 | SHA256 107 | 108 | 109 | 110 | 111 | true 112 | trace.h 113 | true 114 | false 115 | 116 | 117 | 1.0.0 118 | 119 | 120 | SHA256 121 | 122 | 123 | 124 | 125 | true 126 | trace.h 127 | true 128 | false 129 | 130 | 131 | 1.0.0 132 | 133 | 134 | SHA256 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /sklhdaudbus/nhlt.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "nhlt.h" 3 | #include 4 | 5 | DEFINE_GUID(GUID_SST_NHLT, 6 | 0xA69F886E, 0x6CEB, 0x4594, 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); 7 | 8 | NTSTATUS 9 | NHLTQuery( 10 | _In_ WDFDEVICE FxDevice, 11 | _In_ ULONG Arg1, 12 | _In_ ULONG Arg2, 13 | _Out_ WDFMEMORY* outputBufferMemoryArg 14 | ) { 15 | ULONG_PTR bytesReturned; 16 | NTSTATUS status = STATUS_ACPI_NOT_INITIALIZED; 17 | WDFMEMORY inputBufferMemory = NULL; 18 | PACPI_EVAL_INPUT_BUFFER_COMPLEX_EX inputBuffer = NULL; 19 | PACPI_METHOD_ARGUMENT inputArgument = NULL; 20 | ACPI_EVAL_OUTPUT_BUFFER outputHeader; 21 | WDFMEMORY outputBufferMemory = NULL; 22 | WDF_MEMORY_DESCRIPTOR inputBufferMemoryDescriptor; 23 | WDF_MEMORY_DESCRIPTOR outputBufferMemoryDescriptor; 24 | 25 | ULONG inputBufferSize = 26 | (ULONG)( 27 | FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX_EX, Argument) + 28 | ACPI_METHOD_ARGUMENT_LENGTH(sizeof(GUID)) + 29 | ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + 30 | ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + 31 | ACPI_METHOD_ARGUMENT_LENGTH(0) 32 | ); 33 | 34 | status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, 35 | PagedPool, 36 | SKLHDAUDBUS_POOL_TAG, 37 | inputBufferSize, 38 | &inputBufferMemory, 39 | (PVOID*)&inputBuffer); 40 | if (!NT_SUCCESS(status)) { 41 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Failed to create input buffer\n"); 42 | goto end; 43 | } 44 | RtlZeroMemory(inputBuffer, inputBufferSize); 45 | 46 | inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE_V1_EX; 47 | status = RtlStringCchPrintfA( 48 | inputBuffer->MethodName, 49 | sizeof(inputBuffer->MethodName), 50 | "_DSM" 51 | ); 52 | if (!NT_SUCCESS(status)) { 53 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Failed to write method name\n"); 54 | goto end; 55 | } 56 | 57 | inputBuffer->Size = inputBufferSize; 58 | inputBuffer->ArgumentCount = 4; 59 | inputArgument = inputBuffer->Argument; 60 | 61 | //arg 0 62 | ACPI_METHOD_SET_ARGUMENT_BUFFER(inputArgument, 63 | &GUID_SST_NHLT, 64 | sizeof(GUID_SST_NHLT)); 65 | 66 | inputArgument = ACPI_METHOD_NEXT_ARGUMENT(inputArgument); 67 | ACPI_METHOD_SET_ARGUMENT_INTEGER(inputArgument, Arg1); 68 | 69 | inputArgument = ACPI_METHOD_NEXT_ARGUMENT(inputArgument); 70 | ACPI_METHOD_SET_ARGUMENT_INTEGER(inputArgument, Arg2); 71 | 72 | inputArgument = ACPI_METHOD_NEXT_ARGUMENT(inputArgument); 73 | RtlZeroMemory(inputArgument, sizeof(*inputArgument)); 74 | inputArgument->Type = ACPI_METHOD_ARGUMENT_PACKAGE_EX; 75 | inputArgument->DataLength = 0; 76 | 77 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputBufferMemoryDescriptor, 78 | inputBufferMemory, 79 | 0); 80 | RtlZeroMemory(&outputHeader, sizeof(outputHeader)); 81 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputBufferMemoryDescriptor, 82 | &outputHeader, 83 | sizeof(outputHeader)); 84 | 85 | status = WdfIoTargetSendIoctlSynchronously(WdfDeviceGetIoTarget(FxDevice), 86 | NULL, 87 | IOCTL_ACPI_EVAL_METHOD_EX, 88 | &inputBufferMemoryDescriptor, 89 | &outputBufferMemoryDescriptor, 90 | NULL, 91 | &bytesReturned); 92 | 93 | if (status == STATUS_BUFFER_OVERFLOW) { 94 | status = STATUS_SUCCESS; 95 | } 96 | else if (!NT_SUCCESS(status)) { 97 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Failed first ioctl\n"); 98 | goto end; 99 | } 100 | 101 | status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, 102 | PagedPool, 103 | SKLHDAUDBUS_POOL_TAG, 104 | outputHeader.Length, 105 | &outputBufferMemory, 106 | (PVOID*)NULL); 107 | if (!NT_SUCCESS(status)) { 108 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Failed to create output buffer\n"); 109 | goto end; 110 | } 111 | 112 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&outputBufferMemoryDescriptor, 113 | outputBufferMemory, 114 | 0); 115 | status = WdfIoTargetSendIoctlSynchronously(WdfDeviceGetIoTarget(FxDevice), 116 | NULL, 117 | IOCTL_ACPI_EVAL_METHOD_EX, 118 | &inputBufferMemoryDescriptor, 119 | &outputBufferMemoryDescriptor, 120 | NULL, 121 | &bytesReturned); 122 | 123 | if (!NT_SUCCESS(status)) { 124 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Failed to do 2nd ioctl\n"); 125 | goto end; 126 | } 127 | 128 | end: 129 | if (inputBufferMemory != NULL) { 130 | WdfObjectDelete(inputBufferMemory); 131 | inputBufferMemory = NULL; 132 | } 133 | 134 | if (!NT_SUCCESS(status)) { 135 | if (outputBufferMemory != NULL) { 136 | WdfObjectDelete(outputBufferMemory); 137 | outputBufferMemory = NULL; 138 | } 139 | } 140 | else { 141 | *outputBufferMemoryArg = outputBufferMemory; 142 | } 143 | return status; 144 | } 145 | 146 | NTSTATUS NHLTCheckSupported(_In_ WDFDEVICE FxDevice) { 147 | WDFMEMORY outputBufferMemory; 148 | NTSTATUS status = NHLTQuery(FxDevice, NHLTRev1, NHLTSupportQuery, &outputBufferMemory); 149 | if (!NT_SUCCESS(status)) { 150 | return status; 151 | } 152 | if (!outputBufferMemory) { 153 | return STATUS_NO_MEMORY; 154 | } 155 | 156 | PACPI_EVAL_OUTPUT_BUFFER outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)WdfMemoryGetBuffer(outputBufferMemory, NULL); 157 | if (outputBuffer->Count < 1) { 158 | status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER; 159 | goto end; 160 | } 161 | PACPI_METHOD_ARGUMENT argument = outputBuffer->Argument; 162 | 163 | UCHAR supportedQueries = argument->Data[0]; 164 | 165 | if ((supportedQueries & 0x3) == 0) { 166 | status = STATUS_NOT_SUPPORTED; 167 | } 168 | 169 | end: 170 | if (outputBufferMemory != NULL) { 171 | WdfObjectDelete(outputBufferMemory); 172 | outputBufferMemory = NULL; 173 | } 174 | return status; 175 | } 176 | 177 | void parseACPI(UINT8* res, UINT32 offset, UINT32 sz, UINT64* nhltAddr, UINT64* nhltSz); 178 | 179 | NTSTATUS NHLTQueryTableAddress(_In_ WDFDEVICE FxDevice, UINT64 *nhltAddr, UINT64 *nhltSz) { 180 | WDFMEMORY outputBufferMemory; 181 | NTSTATUS status = NHLTQuery(FxDevice, NHLTRev1, NHLTMemoryAddress, &outputBufferMemory); 182 | if (!NT_SUCCESS(status)) { 183 | return status; 184 | } 185 | if (!outputBufferMemory) { 186 | return STATUS_NO_MEMORY; 187 | } 188 | 189 | PACPI_EVAL_OUTPUT_BUFFER outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)WdfMemoryGetBuffer(outputBufferMemory, NULL); 190 | if (outputBuffer->Count < 1) { 191 | return STATUS_INVALID_DEVICE_OBJECT_PARAMETER; 192 | goto end; 193 | } 194 | 195 | PACPI_METHOD_ARGUMENT argument = outputBuffer->Argument; 196 | 197 | UINT8* res = argument->Data; 198 | UINT32 sz = argument->DataLength; 199 | 200 | *nhltAddr = 0; 201 | *nhltSz = 0; 202 | parseACPI(res, 0, sz, nhltAddr, nhltSz); 203 | 204 | if (nhltAddr == 0 || nhltSz == 0) { 205 | status = STATUS_UNSUCCESSFUL; 206 | } 207 | 208 | end: 209 | if (outputBufferMemory != NULL) { 210 | WdfObjectDelete(outputBufferMemory); 211 | outputBufferMemory = NULL; 212 | } 213 | return status; 214 | } 215 | 216 | //Begin ACPI parser 217 | 218 | #define ACPI_RESOURCE_NAME_ADDRESS64 0x8A 219 | 220 | /* 221 | * LARGE descriptors 222 | */ 223 | #define AML_RESOURCE_LARGE_HEADER_COMMON \ 224 | UINT8 DescriptorType;\ 225 | UINT16 ResourceLength; 226 | 227 | #define AML_RESOURCE_ADDRESS_COMMON \ 228 | UINT8 ResourceType; \ 229 | UINT8 Flags; \ 230 | UINT8 SpecificFlags; 231 | 232 | #include 233 | typedef struct aml_resource_address64 234 | { 235 | AML_RESOURCE_LARGE_HEADER_COMMON 236 | AML_RESOURCE_ADDRESS_COMMON 237 | UINT64 Granularity; 238 | UINT64 Minimum; 239 | UINT64 Maximum; 240 | UINT64 TranslationOffset; 241 | UINT64 AddressLength; 242 | } AML_RESOURCE_ADDRESS64; 243 | #include 244 | 245 | void parseACPIMemory64(UINT8* res, UINT32 offset, UINT32 sz, UINT64 *nhltAddr, UINT64 *nhltSz) { 246 | if (offset + 3 > sz) 247 | return; 248 | 249 | UINT8 opcode = res[offset]; 250 | if (opcode != ACPI_RESOURCE_NAME_ADDRESS64) 251 | return; 252 | 253 | AML_RESOURCE_ADDRESS64* address64 = (AML_RESOURCE_ADDRESS64*)(res + offset); 254 | 255 | *nhltAddr = address64->Minimum; 256 | *nhltSz = address64->AddressLength; 257 | } 258 | 259 | void parseACPI(UINT8* res, UINT32 offset, UINT32 sz, UINT64* nhltAddr, UINT64* nhltSz) { 260 | if (offset + 3 > sz) 261 | return; 262 | 263 | UINT8 opcode = res[offset]; 264 | 265 | UINT16 len; 266 | memcpy(&len, res + offset + 1, sizeof(UINT16)); 267 | 268 | if (opcode == ACPI_RESOURCE_NAME_ADDRESS64) 269 | parseACPIMemory64(res, offset, sz, nhltAddr, nhltSz); 270 | 271 | offset += (len + 3); 272 | parseACPI(res, offset, sz, nhltAddr, nhltSz); 273 | } -------------------------------------------------------------------------------- /sklhdaudbus/hda_registers.h: -------------------------------------------------------------------------------- 1 | #define HDA_REG_GCAP 0x00 2 | #define HDA_GCAP_64OK (1 << 0) /* 64bit address support */ 3 | #define HDA_GCAP_NSDO (3 << 1) /* # of serial data out signals */ 4 | #define HDA_GCAP_BSS (31 << 3) /* # of bidirectional streams */ 5 | #define HDA_GCAP_ISS (15 << 8) /* # of input streams */ 6 | #define HDA_GCAP_OSS (15 << 12) /* # of output streams */ 7 | #define HDA_REG_VMIN 0x02 8 | #define HDA_REG_VMAJ 0x03 9 | #define HDA_REG_OUTPAY 0x04 10 | #define HDA_REG_INPAY 0x06 11 | #define HDA_REG_GCTL 0x08 12 | #define HDA_GCTL_RESET (1 << 0) /* controller reset */ 13 | #define HDA_GCTL_FCNTRL (1 << 1) /* flush control */ 14 | #define HDA_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ 15 | #define HDA_REG_WAKEEN 0x0c 16 | #define HDA_REG_STATESTS 0x0e 17 | #define HDA_REG_GSTS 0x10 18 | #define HDA_GSTS_FSTS (1 << 1) /* flush status */ 19 | #define HDA_REG_GCAP2 0x12 20 | #define HDA_REG_LLCH 0x14 21 | #define HDA_REG_OUTSTRMPAY 0x18 22 | #define HDA_REG_INSTRMPAY 0x1A 23 | #define HDA_REG_INTCTL 0x20 24 | #define HDA_REG_INTSTS 0x24 25 | #define HDA_REG_WALLCLK 0x30 /* 24Mhz source */ 26 | #define HDA_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ 27 | #define HDA_REG_SSYNC 0x38 28 | #define HDA_REG_CORBLBASE 0x40 29 | #define HDA_REG_CORBUBASE 0x44 30 | #define HDA_REG_CORBWP 0x48 31 | #define HDA_REG_CORBRP 0x4a 32 | #define HDA_CORBRP_RST (1 << 15) /* read pointer reset */ 33 | #define HDA_REG_CORBCTL 0x4c 34 | #define HDA_CORBCTL_RUN (1 << 1) /* enable DMA */ 35 | #define HDA_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ 36 | #define HDA_REG_CORBSTS 0x4d 37 | #define HDA_CORBSTS_CMEI (1 << 0) /* memory error indication */ 38 | #define HDA_REG_CORBSIZE 0x4e 39 | 40 | #define HDA_REG_RIRBLBASE 0x50 41 | #define HDA_REG_RIRBUBASE 0x54 42 | #define HDA_REG_RIRBWP 0x58 43 | #define HDA_RIRBWP_RST (1 << 15) /* write pointer reset */ 44 | #define HDA_REG_RINTCNT 0x5a 45 | #define HDA_REG_RIRBCTL 0x5c 46 | #define HDA_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ 47 | #define HDA_RBCTL_DMA_EN (1 << 1) /* enable DMA */ 48 | #define HDA_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ 49 | #define HDA_REG_RIRBSTS 0x5d 50 | #define HDA_RBSTS_IRQ (1 << 0) /* response irq */ 51 | #define HDA_RBSTS_OVERRUN (1 << 2) /* overrun irq */ 52 | #define HDA_REG_RIRBSIZE 0x5e 53 | 54 | #define HDA_REG_IC 0x60 55 | #define HDA_REG_IR 0x64 56 | #define HDA_REG_IRS 0x68 57 | #define HDA_IRS_VALID (1<<1) 58 | #define HDA_IRS_BUSY (1<<0) 59 | 60 | #define HDA_REG_DPLBASE 0x70 61 | #define HDA_REG_DPUBASE 0x74 62 | #define HDA_DPLBASE_ENABLE 0x1 /* Enable position buffer */ 63 | 64 | /* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ 65 | enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; 66 | 67 | /* stream register offsets from stream base */ 68 | #define HDA_REG_SD_CTL 0x00 69 | #define HDA_REG_SD_CTL_3B 0x02 /* 3rd byte of SD_CTL register */ 70 | #define HDA_REG_SD_STS 0x03 71 | #define HDA_REG_SD_LPIB 0x04 72 | #define HDA_REG_SD_CBL 0x08 73 | #define HDA_REG_SD_LVI 0x0c 74 | #define HDA_REG_SD_FIFOW 0x0e 75 | #define HDA_REG_SD_FIFOSIZE 0x10 76 | #define HDA_REG_SD_FORMAT 0x12 77 | #define HDA_REG_SD_FIFOL 0x14 78 | #define HDA_REG_SD_BDLPL 0x18 79 | #define HDA_REG_SD_BDLPU 0x1c 80 | 81 | /* GTS registers */ 82 | #define HDA_REG_LLCH 0x14 83 | 84 | #define HDA_REG_GTS_BASE 0x520 85 | 86 | #define HDA_REG_GTSCC (HDA_REG_GTS_BASE + 0x00) 87 | #define HDA_REG_WALFCC (HDA_REG_GTS_BASE + 0x04) 88 | #define HDA_REG_TSCCL (HDA_REG_GTS_BASE + 0x08) 89 | #define HDA_REG_TSCCU (HDA_REG_GTS_BASE + 0x0C) 90 | #define HDA_REG_LLPFOC (HDA_REG_GTS_BASE + 0x14) 91 | #define HDA_REG_LLPCL (HDA_REG_GTS_BASE + 0x18) 92 | #define HDA_REG_LLPCU (HDA_REG_GTS_BASE + 0x1C) 93 | 94 | /* Haswell/Broadwell display HD-A controller Extended Mode registers */ 95 | #define HDA_REG_HSW_EM4 0x100c 96 | #define HDA_REG_HSW_EM5 0x1010 97 | 98 | /* Skylake/Broxton vendor-specific registers */ 99 | #define HDA_REG_VS_EM1 0x1000 100 | #define HDA_REG_VS_INRC 0x1004 101 | #define HDA_REG_VS_OUTRC 0x1008 102 | #define HDA_REG_VS_FIFOTRK 0x100C 103 | #define HDA_REG_VS_FIFOTRK2 0x1010 104 | #define HDA_REG_VS_EM2 0x1030 105 | #define HDA_REG_VS_EM3L 0x1038 106 | #define HDA_REG_VS_EM3U 0x103C 107 | #define HDA_REG_VS_EM4L 0x1040 108 | #define HDA_REG_VS_EM4U 0x1044 109 | #define HDA_REG_VS_LTRP 0x1048 110 | #define HDA_REG_VS_D0I3C 0x104A 111 | #define HDA_REG_VS_PCE 0x104B 112 | #define HDA_REG_VS_L2MAGC 0x1050 113 | #define HDA_REG_VS_L2LAHPT 0x1054 114 | #define HDA_REG_VS_SDXDPIB_XBASE 0x1084 115 | #define HDA_REG_VS_SDXDPIB_XINTERVAL 0x20 116 | #define HDA_REG_VS_SDXEFIFOS_XBASE 0x1094 117 | #define HDA_REG_VS_SDXEFIFOS_XINTERVAL 0x20 118 | 119 | /* PCI space */ 120 | #define HDA_PCIREG_TCSEL 0x44 121 | 122 | /* 123 | * other constants 124 | */ 125 | 126 | /* max number of fragments - we may use more if allocating more pages for BDL */ 127 | #define BDL_SIZE 4096 128 | #define HDA_MAX_BDL_ENTRIES (BDL_SIZE / 16) 129 | /* 130 | * max buffer size - artificial 4MB limit per stream to avoid big allocations 131 | * In theory it can be really big, but as it is per stream on systems with many streams memory could 132 | * be quickly saturated if userspace requests maximum buffer size for each of them. 133 | */ 134 | #define HDA_MAX_BUF_SIZE (4*1024*1024) 135 | 136 | /* RIRB int mask: overrun[2], response[0] */ 137 | #define RIRB_INT_RESPONSE 0x01 138 | #define RIRB_INT_OVERRUN 0x04 139 | #define RIRB_INT_MASK 0x05 140 | 141 | /* STATESTS int mask: S3,SD2,SD1,SD0 */ 142 | #define STATESTS_INT_MASK ((1 << HDA_MAX_CODECS) - 1) 143 | 144 | /* SD_CTL bits */ 145 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ 146 | #define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ 147 | #define SD_CTL_STRIPE (3 << 16) /* stripe control */ 148 | #define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ 149 | #define SD_CTL_DIR (1 << 19) /* bi-directional stream */ 150 | #define SD_CTL_STREAM_TAG_MASK (0xf << 20) 151 | #define SD_CTL_STREAM_TAG_SHIFT 20 152 | 153 | /* SD_CTL and SD_STS */ 154 | #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ 155 | #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ 156 | #define SD_INT_COMPLETE 0x04 /* completion interrupt */ 157 | #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ 158 | SD_INT_COMPLETE) 159 | #define SD_CTL_STRIPE_MASK 0x3 /* stripe control mask */ 160 | 161 | /* SD_STS */ 162 | #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ 163 | 164 | /* INTCTL and INTSTS */ 165 | #define HDA_INT_ALL_STREAM 0xff /* all stream interrupts */ 166 | #define HDA_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ 167 | #define HDA_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ 168 | 169 | /* below are so far hardcoded - should read registers in future */ 170 | #define HDA_MAX_CORB_ENTRIES 256 171 | #define HDA_MAX_RIRB_ENTRIES 256 172 | 173 | /* Capability header Structure */ 174 | #define HDA_REG_CAP_HDR 0x0 175 | #define HDA_CAP_HDR_VER_OFF 28 176 | #define HDA_CAP_HDR_VER_MASK (0xF << HDA_CAP_HDR_VER_OFF) 177 | #define HDA_CAP_HDR_ID_OFF 16 178 | #define HDA_CAP_HDR_ID_MASK (0xFFF << HDA_CAP_HDR_ID_OFF) 179 | #define HDA_CAP_HDR_NXT_PTR_MASK 0xFFFF 180 | 181 | /* registers of Software Position Based FIFO Capability Structure */ 182 | #define HDA_SPB_CAP_ID 0x4 183 | #define HDA_REG_SPB_BASE_ADDR 0x700 184 | #define HDA_REG_SPB_SPBFCH 0x00 185 | #define HDA_REG_SPB_SPBFCCTL 0x04 186 | /* Base used to calculate the iterating register offset */ 187 | #define HDA_SPB_BASE 0x08 188 | /* Interval used to calculate the iterating register offset */ 189 | #define HDA_SPB_INTERVAL 0x08 190 | /* SPIB base */ 191 | #define HDA_SPB_SPIB 0x00 192 | /* SPIB MAXFIFO base*/ 193 | #define HDA_SPB_MAXFIFO 0x04 194 | 195 | /* registers of Global Time Synchronization Capability Structure */ 196 | #define HDA_GTS_CAP_ID 0x1 197 | #define HDA_REG_GTS_GTSCH 0x00 198 | #define HDA_REG_GTS_GTSCD 0x04 199 | #define HDA_REG_GTS_GTSCTLAC 0x0C 200 | #define HDA_GTS_BASE 0x20 201 | #define HDA_GTS_INTERVAL 0x20 202 | 203 | /* registers for Processing Pipe Capability Structure */ 204 | #define HDA_PP_CAP_ID 0x3 205 | #define HDA_REG_PP_PPCH 0x10 206 | #define HDA_REG_PP_PPCTL 0x04 207 | #define HDA_PPCTL_PIE (1<<31) 208 | #define HDA_PPCTL_GPROCEN (1<<30) 209 | /* _X_ = dma engine # and cannot * exceed 29 (per spec max 30 dma engines) */ 210 | #define HDA_PPCTL_PROCEN(_X_) (1<<(_X_)) 211 | 212 | #define HDA_REG_PP_PPSTS 0x08 213 | 214 | #define HDA_PPHC_BASE 0x10 215 | #define HDA_PPHC_INTERVAL 0x10 216 | 217 | #define HDA_REG_PPHCLLPL 0x0 218 | #define HDA_REG_PPHCLLPU 0x4 219 | #define HDA_REG_PPHCLDPL 0x8 220 | #define HDA_REG_PPHCLDPU 0xC 221 | 222 | #define HDA_PPLC_BASE 0x10 223 | #define HDA_PPLC_MULTI 0x10 224 | #define HDA_PPLC_INTERVAL 0x10 225 | 226 | #define HDA_REG_PPLCCTL 0x0 227 | #define HDA_PPLCCTL_STRM_BITS 4 228 | #define HDA_PPLCCTL_STRM_SHIFT 20 229 | #define HDA_REG_MASK(bit_num, offset) \ 230 | (((1 << (bit_num)) - 1) << (offset)) 231 | #define HDA_PPLCCTL_STRM_MASK \ 232 | HDA_REG_MASK(HDA_PPLCCTL_STRM_BITS, HDA_PPLCCTL_STRM_SHIFT) 233 | #define HDA_PPLCCTL_RUN (1<<1) 234 | #define HDA_PPLCCTL_STRST (1<<0) 235 | 236 | #define HDA_REG_PPLCFMT 0x4 237 | #define HDA_REG_PPLCLLPL 0x8 238 | #define HDA_REG_PPLCLLPU 0xC 239 | 240 | /* registers for Multiple Links Capability Structure */ 241 | #define HDA_ML_CAP_ID 0x2 242 | #define HDA_REG_ML_MLCH 0x00 243 | #define HDA_REG_ML_MLCD 0x04 244 | #define HDA_ML_BASE 0x40 245 | #define HDA_ML_INTERVAL 0x40 246 | 247 | #define HDA_REG_ML_LCAP 0x00 248 | #define HDA_REG_ML_LCTL 0x04 249 | #define HDA_REG_ML_LOSIDV 0x08 250 | #define HDA_REG_ML_LSDIID 0x0C 251 | #define HDA_REG_ML_LPSOO 0x10 252 | #define HDA_REG_ML_LPSIO 0x12 253 | #define HDA_REG_ML_LWALFC 0x18 254 | #define HDA_REG_ML_LOUTPAY 0x20 255 | #define HDA_REG_ML_LINPAY 0x30 256 | 257 | /* bit0 is reserved, with BIT(1) mapping to stream1 */ 258 | #define ML_LOSIDV_STREAM_MASK 0xFFFE 259 | 260 | #define ML_LCTL_SCF_MASK 0xF 261 | #define HDA_MLCTL_SPA (0x1 << 16) 262 | #define HDA_MLCTL_CPA (0x1 << 23) 263 | #define HDA_MLCTL_SPA_SHIFT 16 264 | #define HDA_MLCTL_CPA_SHIFT 23 265 | 266 | /* registers for DMA Resume Capability Structure */ 267 | #define HDA_DRSM_CAP_ID 0x5 268 | #define HDA_REG_DRSM_CTL 0x4 269 | /* Base used to calculate the iterating register offset */ 270 | #define HDA_DRSM_BASE 0x08 271 | /* Interval used to calculate the iterating register offset */ 272 | #define HDA_DRSM_INTERVAL 0x08 273 | 274 | /* Global time synchronization registers */ 275 | #define GTSCC_TSCCD_MASK 0x80000000 276 | #define GTSCC_TSCCD_SHIFT BIT(31) 277 | #define GTSCC_TSCCI_MASK 0x20 278 | #define GTSCC_CDMAS_DMA_DIR_SHIFT 4 279 | 280 | #define WALFCC_CIF_MASK 0x1FF 281 | #define WALFCC_FN_SHIFT 9 282 | #define HDA_CLK_CYCLES_PER_FRAME 512 283 | 284 | /* 285 | * An error occurs near frame "rollover". The clocks in frame value indicates 286 | * whether this error may have occurred. Here we use the value of 10. Please 287 | * see the errata for the right number [<10] 288 | */ 289 | #define HDA_MAX_CYCLE_VALUE 499 290 | #define HDA_MAX_CYCLE_OFFSET 10 291 | #define HDA_MAX_CYCLE_READ_RETRY 10 292 | 293 | #define TSCCU_CCU_SHIFT 32 294 | #define LLPC_CCU_SHIFT 32 295 | 296 | /* Defines for Intel SCH HDA snoop control */ 297 | #define INTEL_HDA_CGCTL 0x48 298 | #define INTEL_HDA_CGCTL_MISCBDCGE (0x1 << 6) 299 | #define INTEL_SCH_HDA_DEVC 0x78 300 | #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) 301 | 302 | #define HDA_VS_EM2_DUM (1 << 23) -------------------------------------------------------------------------------- /sklhdaudbus/sgpc.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | NTSTATUS HDAGraphics_EvtIoTargetQueryRemove( 4 | WDFIOTARGET ioTarget 5 | ) { 6 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 7 | "Device Removal Notification\n"); 8 | 9 | WdfIoTargetCloseForQueryRemove(ioTarget); 10 | return STATUS_SUCCESS; 11 | } 12 | 13 | void HDAGraphics_EvtIoTargetRemoveCanceled( 14 | WDFIOTARGET ioTarget 15 | ) { 16 | WDF_IO_TARGET_OPEN_PARAMS openParams; 17 | NTSTATUS status; 18 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 19 | "Device Removal Cancel\n"); 20 | 21 | WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(&openParams); 22 | 23 | status = WdfIoTargetOpen(ioTarget, &openParams); 24 | 25 | if (!NT_SUCCESS(status)) { 26 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 27 | "WdfIoTargetOpen failed 0x%x\n", status); 28 | WdfObjectDelete(ioTarget); 29 | return; 30 | } 31 | } 32 | 33 | void HDAGraphics_EvtIoTargetRemoveComplete( 34 | WDFIOTARGET ioTarget 35 | ) { 36 | PFDO_CONTEXT fdoCtx; 37 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 38 | "Device Removal Complete\n"); 39 | 40 | PGRAPHICSIOTARGET_CONTEXT ioTargetContext; 41 | ioTargetContext = GraphicsIoTarget_GetContext(ioTarget); 42 | 43 | fdoCtx = ioTargetContext->FdoContext; 44 | 45 | WdfWaitLockAcquire(fdoCtx->GraphicsDevicesCollectionWaitLock, NULL); 46 | WdfCollectionRemove(fdoCtx->GraphicsDevicesCollection, ioTarget); 47 | WdfWaitLockRelease(fdoCtx->GraphicsDevicesCollectionWaitLock); 48 | 49 | WdfObjectDelete(ioTarget); 50 | } 51 | 52 | void HDAGraphicsPowerNotificationCallback( 53 | PVOID GraphicsDeviceHandle, 54 | DEVICE_POWER_STATE NewGrfxPowerState, 55 | BOOLEAN PreNotification, 56 | PVOID PrivateHandle 57 | ) { 58 | PFDO_CONTEXT fdoCtx = (PFDO_CONTEXT)PrivateHandle; 59 | UNREFERENCED_PARAMETER(GraphicsDeviceHandle); 60 | UNREFERENCED_PARAMETER(NewGrfxPowerState); 61 | UNREFERENCED_PARAMETER(PreNotification); 62 | UNREFERENCED_PARAMETER(fdoCtx); 63 | //No-Op 64 | } 65 | 66 | void HDAGraphicsPowerRemovalNotificationCallback( 67 | PVOID GraphicsDeviceHandle, 68 | PVOID PrivateHandle 69 | ) { 70 | PFDO_CONTEXT fdoCtx = (PFDO_CONTEXT)PrivateHandle; 71 | UNREFERENCED_PARAMETER(GraphicsDeviceHandle); 72 | UNREFERENCED_PARAMETER(fdoCtx); 73 | //No-Op 74 | } 75 | 76 | void 77 | Fdo_EnumerateCodec( 78 | PFDO_CONTEXT fdoCtx, 79 | UINT8 addr 80 | ); 81 | 82 | void EjectGraphicsCodec(PFDO_CONTEXT fdoCtx) { 83 | if (!fdoCtx->UseSGPCCodec) { 84 | return; 85 | } 86 | 87 | if (!fdoCtx->codecs[fdoCtx->GraphicsCodecAddress]) 88 | return; 89 | 90 | PDO_IDENTIFICATION_DESCRIPTION description;// 91 | // Initialize the description with the information about the detected codec. 92 | // 93 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT( 94 | &description.Header, 95 | sizeof(description) 96 | ); 97 | 98 | description.FdoContext = fdoCtx; 99 | RtlCopyMemory(&description.CodecIds, &fdoCtx->codecs[fdoCtx->GraphicsCodecAddress]->CodecIds, sizeof(description.CodecIds)); 100 | 101 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 102 | "Ejecting Gfx Codec\n"); 103 | 104 | WdfInterruptAcquireLock(fdoCtx->Interrupt); 105 | 106 | WdfChildListUpdateChildDescriptionAsMissing(WdfFdoGetDefaultChildList(fdoCtx->WdfDevice), &description.Header); 107 | fdoCtx->codecs[fdoCtx->GraphicsCodecAddress]->FdoContext = NULL; 108 | 109 | WdfInterruptReleaseLock(fdoCtx->Interrupt); 110 | 111 | } 112 | 113 | void EnumerateGraphicsCodec(PFDO_CONTEXT fdoCtx) { 114 | if (!fdoCtx->UseSGPCCodec) { 115 | return; 116 | } 117 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 118 | "Enumerating Gfx Codec\n"); 119 | Fdo_EnumerateCodec(fdoCtx, (UINT8)fdoCtx->GraphicsCodecAddress); 120 | } 121 | 122 | void HDAGraphicsPowerFStateNotificationCallback( 123 | PVOID GraphicsDeviceHandle, 124 | ULONG ComponentIndex, 125 | UINT NewFState, 126 | BOOLEAN PreNotification, 127 | PVOID PrivateHandle 128 | ) { 129 | PFDO_CONTEXT fdoCtx = (PFDO_CONTEXT)PrivateHandle; 130 | UNREFERENCED_PARAMETER(GraphicsDeviceHandle); 131 | UNREFERENCED_PARAMETER(ComponentIndex); 132 | if (NewFState) { 133 | if (PreNotification) { 134 | EjectGraphicsCodec(fdoCtx); 135 | } 136 | else { 137 | 138 | } 139 | } 140 | else { 141 | if (PreNotification) { 142 | 143 | } 144 | else { 145 | EnumerateGraphicsCodec(fdoCtx); 146 | } 147 | } 148 | } 149 | 150 | void HDAGraphicsPowerInitialComponentStateCallback( //https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/nc-d3dkmthk-pdxgk_initial_component_state 151 | PVOID GraphicsDeviceHandle, 152 | PVOID PrivateHandle, 153 | ULONG ComponentIndex, 154 | BOOLEAN IsBlockingType, 155 | UINT InitialFState, 156 | GUID ComponentGuid, 157 | UINT PowerComponentMappingFlag 158 | ) { 159 | UNREFERENCED_PARAMETER(GraphicsDeviceHandle); 160 | UNREFERENCED_PARAMETER(ComponentIndex); 161 | UNREFERENCED_PARAMETER(IsBlockingType); 162 | UNREFERENCED_PARAMETER(ComponentGuid); 163 | PFDO_CONTEXT fdoCtx = (PFDO_CONTEXT)PrivateHandle; 164 | if (PowerComponentMappingFlag) { 165 | } 166 | else { 167 | if (InitialFState) { 168 | } else { 169 | EnumerateGraphicsCodec(fdoCtx); 170 | } 171 | } 172 | } 173 | 174 | void HDAGraphicsPowerInterfaceAdd(WDFWORKITEM WorkItem) { 175 | PGRAPHICSWORKITEM_CONTEXT workItemContext = GraphicsWorkitem_GetContext(WorkItem); 176 | PFDO_CONTEXT fdoCtx = workItemContext->FdoContext; 177 | PUNICODE_STRING graphicsDeviceSymlink = &workItemContext->GPUDeviceSymlink; 178 | 179 | WDF_OBJECT_ATTRIBUTES attributes; 180 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, GRAPHICSIOTARGET_CONTEXT); 181 | 182 | WDFIOTARGET ioTarget; 183 | WDF_IO_TARGET_OPEN_PARAMS openParams; 184 | PGRAPHICSIOTARGET_CONTEXT ioTargetContext; 185 | 186 | NTSTATUS status = WdfIoTargetCreate(fdoCtx->WdfDevice, &attributes, &ioTarget); 187 | if (!NT_SUCCESS(status)) { 188 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 189 | "WdfIoTargetCreate failed 0x%x\n", status); 190 | goto exit; 191 | } 192 | 193 | ioTargetContext = GraphicsIoTarget_GetContext(ioTarget); 194 | ioTargetContext->FdoContext = fdoCtx; 195 | 196 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 197 | &openParams, 198 | graphicsDeviceSymlink, 199 | STANDARD_RIGHTS_ALL); 200 | openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ; 201 | openParams.EvtIoTargetQueryRemove = HDAGraphics_EvtIoTargetQueryRemove; 202 | openParams.EvtIoTargetRemoveCanceled = HDAGraphics_EvtIoTargetRemoveCanceled; 203 | openParams.EvtIoTargetRemoveComplete = HDAGraphics_EvtIoTargetRemoveComplete; 204 | 205 | status = WdfIoTargetOpen(ioTarget, &openParams); 206 | 207 | if (!NT_SUCCESS(status)) { 208 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 209 | "WdfIoTargetOpen failed with status 0x%x\n", status); 210 | WdfObjectDelete(ioTarget); 211 | goto exit; 212 | } 213 | 214 | WdfWaitLockAcquire(fdoCtx->GraphicsDevicesCollectionWaitLock, NULL); 215 | WdfCollectionAdd(fdoCtx->GraphicsDevicesCollection, ioTarget); 216 | WdfWaitLockRelease(fdoCtx->GraphicsDevicesCollectionWaitLock); 217 | 218 | DXGK_GRAPHICSPOWER_REGISTER_INPUT graphicsPowerRegisterInput; 219 | graphicsPowerRegisterInput = { 0 }; 220 | graphicsPowerRegisterInput.Version = DXGK_GRAPHICSPOWER_VERSION; 221 | graphicsPowerRegisterInput.PrivateHandle = fdoCtx; 222 | graphicsPowerRegisterInput.PowerNotificationCb = HDAGraphicsPowerNotificationCallback; 223 | graphicsPowerRegisterInput.RemovalNotificationCb = HDAGraphicsPowerRemovalNotificationCallback; 224 | graphicsPowerRegisterInput.FStateNotificationCb = HDAGraphicsPowerFStateNotificationCallback; 225 | graphicsPowerRegisterInput.InitialComponentStateCb = HDAGraphicsPowerInitialComponentStateCallback; 226 | 227 | WDF_MEMORY_DESCRIPTOR inputDescriptor; 228 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, &graphicsPowerRegisterInput, sizeof(graphicsPowerRegisterInput)); 229 | 230 | WDF_MEMORY_DESCRIPTOR outputDescriptor; 231 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, &ioTargetContext->graphicsPowerRegisterOutput, sizeof(ioTargetContext->graphicsPowerRegisterOutput)); 232 | 233 | status = WdfIoTargetSendInternalIoctlSynchronously(ioTarget, 234 | WDF_NO_HANDLE, 235 | IOCTL_INTERNAL_GRAPHICSPOWER_REGISTER, 236 | &inputDescriptor, &outputDescriptor, NULL, NULL); 237 | if (!NT_SUCCESS(status)) { 238 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 239 | "IOCTL_INTERNAL_GRAPHICSPOWER_REGISTER failed with status 0x%x\n", status); 240 | goto exit; 241 | } 242 | 243 | exit: 244 | WdfObjectDelete(WorkItem); 245 | } 246 | 247 | NTSTATUS 248 | HDAGraphicsPowerInterfaceCallback( 249 | PVOID NotificationStruct, 250 | PVOID Context 251 | ) { 252 | NTSTATUS status = STATUS_SUCCESS; 253 | PFDO_CONTEXT fdoCtx = (PFDO_CONTEXT)Context; 254 | PDEVICE_INTERFACE_CHANGE_NOTIFICATION devNotificationStruct = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStruct; 255 | 256 | if (!IsEqualGUID(devNotificationStruct->InterfaceClassGuid, GUID_DEVINTERFACE_GRAPHICSPOWER)) { 257 | return STATUS_NOT_SUPPORTED; 258 | } 259 | 260 | if (IsEqualGUID(devNotificationStruct->Event, GUID_DEVICE_INTERFACE_ARRIVAL)) { 261 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 262 | "Graphics Arrival Notification!\n"); 263 | 264 | status = RtlUnicodeStringValidate(devNotificationStruct->SymbolicLinkName); 265 | if (!NT_SUCCESS(status)) { 266 | return status; 267 | } 268 | 269 | WDF_WORKITEM_CONFIG workItemConfig; 270 | WDF_WORKITEM_CONFIG_INIT(&workItemConfig, HDAGraphicsPowerInterfaceAdd); 271 | 272 | WDF_OBJECT_ATTRIBUTES attributes; 273 | WDFWORKITEM workItem; 274 | 275 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 276 | WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE( 277 | &attributes, 278 | GRAPHICSWORKITEM_CONTEXT 279 | ); 280 | attributes.ParentObject = fdoCtx->WdfDevice; 281 | 282 | WdfWorkItemCreate(&workItemConfig, &attributes, &workItem); 283 | 284 | PGRAPHICSWORKITEM_CONTEXT workItemContext = GraphicsWorkitem_GetContext(workItem); 285 | workItemContext->FdoContext = fdoCtx; 286 | workItemContext->GPUDeviceSymlink = *devNotificationStruct->SymbolicLinkName; 287 | 288 | WdfWorkItemEnqueue(workItem); 289 | } 290 | 291 | return status; 292 | } 293 | 294 | void CheckHDAGraphicsRegistryKeys(PFDO_CONTEXT fdoCtx) { 295 | NTSTATUS status; 296 | WDFKEY driverKey; 297 | status = WdfDeviceOpenRegistryKey(fdoCtx->WdfDevice, PLUGPLAY_REGKEY_DRIVER, READ_CONTROL, NULL, &driverKey); 298 | if (!NT_SUCCESS(status)) { 299 | return; 300 | } 301 | 302 | WDFKEY settingsKey; 303 | DECLARE_CONST_UNICODE_STRING(DriverSettings, L"Settings"); 304 | DECLARE_CONST_UNICODE_STRING(GfxSharedCodecAddress, L"GfxSharedCodecAddress"); 305 | status = WdfRegistryOpenKey(driverKey, &DriverSettings, READ_CONTROL, NULL, &settingsKey); 306 | if (!NT_SUCCESS(status)) { 307 | goto closeDriverKey; 308 | } 309 | 310 | ULONG GfxCodecAddr; 311 | status = WdfRegistryQueryULong(settingsKey, &GfxSharedCodecAddress, &GfxCodecAddr); 312 | if (NT_SUCCESS(status)) { 313 | fdoCtx->UseSGPCCodec = TRUE; 314 | fdoCtx->GraphicsCodecAddress = GfxCodecAddr; 315 | } 316 | 317 | WdfRegistryClose(settingsKey); 318 | 319 | closeDriverKey: 320 | WdfRegistryClose(driverKey); 321 | } -------------------------------------------------------------------------------- /sklhdaudbus/adsp.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #define ADSP_DECL 1 3 | #include "adsp.h" 4 | 5 | NTSTATUS ADSPGetResources(_In_ PVOID _context, _PCI_BAR* hdaBar, _PCI_BAR* adspBar, PVOID *ppcap, PNHLT_INFO nhltInfo, BUS_INTERFACE_STANDARD* pciConfig) { 6 | if (!_context) 7 | return STATUS_NO_SUCH_DEVICE; 8 | 9 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 10 | if (!devData->FdoContext) { 11 | return STATUS_NO_SUCH_DEVICE; 12 | } 13 | 14 | if (hdaBar) { 15 | *hdaBar = devData->FdoContext->m_BAR0; 16 | } 17 | 18 | if (adspBar) { 19 | *adspBar = devData->FdoContext->m_BAR4; 20 | } 21 | 22 | if (ppcap) { 23 | *ppcap = devData->FdoContext->ppcap; 24 | } 25 | 26 | if (nhltInfo) { 27 | if (devData->FdoContext->nhlt) { 28 | nhltInfo->nhlt = devData->FdoContext->nhlt; 29 | nhltInfo->nhltSz = devData->FdoContext->nhltSz; 30 | } 31 | else if (devData->FdoContext->sofTplg) { 32 | nhltInfo->nhlt = devData->FdoContext->sofTplg; 33 | nhltInfo->nhltSz = devData->FdoContext->sofTplgSz; 34 | } 35 | } 36 | 37 | if (pciConfig) { 38 | *pciConfig = devData->FdoContext->BusInterface; 39 | } 40 | 41 | return STATUS_SUCCESS; 42 | } 43 | 44 | NTSTATUS ADSPSetPowerState(_In_ PVOID _context, _In_ DEVICE_POWER_STATE powerState) { 45 | if (!_context) 46 | return STATUS_NO_SUCH_DEVICE; 47 | 48 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 49 | if (!devData->FdoContext) { 50 | return STATUS_NO_SUCH_DEVICE; 51 | } 52 | 53 | NTSTATUS status = STATUS_SUCCESS; 54 | if (powerState == PowerDeviceD3) { 55 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 56 | } else if (powerState == PowerDeviceD0) { 57 | status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 58 | } 59 | return status; 60 | } 61 | 62 | NTSTATUS ADSPRegisterInterrupt(_In_ PVOID _context, _In_ PADSP_INTERRUPT_CALLBACK callback, _In_ PVOID callbackContext) { 63 | if (!_context) 64 | return STATUS_NO_SUCH_DEVICE; 65 | 66 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 67 | if (!devData->FdoContext) { 68 | return STATUS_NO_SUCH_DEVICE; 69 | } 70 | 71 | devData->FdoContext->dspInterruptCallback = callback; 72 | devData->FdoContext->dspInterruptContext = callbackContext; 73 | return STATUS_SUCCESS; 74 | } 75 | 76 | NTSTATUS ADSPUnregisterInterrupt(_In_ PVOID _context) { 77 | if (!_context) 78 | return STATUS_NO_SUCH_DEVICE; 79 | 80 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 81 | if (!devData->FdoContext) { 82 | return STATUS_NO_SUCH_DEVICE; 83 | } 84 | 85 | devData->FdoContext->dspInterruptCallback = NULL; 86 | devData->FdoContext->dspInterruptContext = NULL; 87 | return STATUS_SUCCESS; 88 | } 89 | 90 | NTSTATUS ADSPGetRenderStream(_In_ PVOID _context, HDAUDIO_STREAM_FORMAT StreamFormat, PHANDLE Handle, _Out_ UINT8* streamTag) { 91 | if (!_context) 92 | return STATUS_NO_SUCH_DEVICE; 93 | 94 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 95 | if (!devData->FdoContext) { 96 | return STATUS_NO_SUCH_DEVICE; 97 | } 98 | 99 | PFDO_CONTEXT fdoContext = devData->FdoContext; 100 | 101 | NTSTATUS status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 102 | if (!NT_SUCCESS(status)) { 103 | return status; 104 | } 105 | 106 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 107 | for (UINT32 i = 0; i < fdoContext->playbackStreams; i++) { 108 | int tag = fdoContext->playbackIndexOff + i; 109 | PHDAC_STREAM stream = &fdoContext->streams[tag]; 110 | if (stream->PdoContext != NULL) { 111 | continue; 112 | } 113 | 114 | stream->stripe = FALSE; 115 | stream->PdoContext = devData; 116 | stream->running = FALSE; 117 | stream->streamFormat = StreamFormat; 118 | 119 | int mask = HDA_PPCTL_PROCEN(stream->idx); 120 | UINT32 val = 0; 121 | val = read16(fdoContext->ppcap + HDA_REG_PP_PPCTL) & mask; 122 | 123 | if (!val) { 124 | hdac_update32(fdoContext->ppcap, HDA_REG_PP_PPCTL, mask, mask); 125 | } 126 | 127 | if (Handle) 128 | *Handle = (HANDLE)stream; 129 | if (streamTag) 130 | *streamTag = stream->streamTag; 131 | 132 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 133 | return STATUS_SUCCESS; 134 | } 135 | 136 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 137 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 138 | return STATUS_INSUFFICIENT_RESOURCES; 139 | } 140 | 141 | NTSTATUS ADSPGetCaptureStream(_In_ PVOID _context, HDAUDIO_STREAM_FORMAT StreamFormat, PHANDLE Handle, _Out_ UINT8* streamTag) { 142 | if (!_context) 143 | return STATUS_NO_SUCH_DEVICE; 144 | 145 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 146 | if (!devData->FdoContext) { 147 | return STATUS_NO_SUCH_DEVICE; 148 | } 149 | 150 | PFDO_CONTEXT fdoContext = devData->FdoContext; 151 | 152 | NTSTATUS status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 153 | if (!NT_SUCCESS(status)) { 154 | return status; 155 | } 156 | 157 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 158 | for (UINT32 i = 0; i < fdoContext->captureStreams; i++) { 159 | int tag = fdoContext->captureIndexOff + i; 160 | PHDAC_STREAM stream = &fdoContext->streams[tag]; 161 | if (stream->PdoContext != NULL) { 162 | continue; 163 | } 164 | 165 | stream->stripe = FALSE; 166 | stream->PdoContext = devData; 167 | stream->running = FALSE; 168 | stream->streamFormat = StreamFormat; 169 | 170 | int mask = HDA_PPCTL_PROCEN(stream->idx); 171 | UINT32 val = 0; 172 | val = read16(fdoContext->ppcap + HDA_REG_PP_PPCTL) & mask; 173 | 174 | if (!val) { 175 | hdac_update32(fdoContext->ppcap, HDA_REG_PP_PPCTL, mask, mask); 176 | } 177 | 178 | if (Handle) 179 | *Handle = (HANDLE)stream; 180 | if (streamTag) 181 | *streamTag = stream->streamTag; 182 | 183 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 184 | return STATUS_SUCCESS; 185 | } 186 | 187 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 188 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 189 | return STATUS_INSUFFICIENT_RESOURCES; 190 | } 191 | 192 | NTSTATUS ADSPFreeStream( 193 | _In_ PVOID _context, 194 | _In_ HANDLE Handle 195 | ) { 196 | SklHdAudBusPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, "%s called!\n", __func__); 197 | 198 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 199 | if (!devData->FdoContext) { 200 | return STATUS_NO_SUCH_DEVICE; 201 | } 202 | 203 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 204 | if (!stream || stream->PdoContext != devData) { 205 | return STATUS_INVALID_HANDLE; 206 | } 207 | 208 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 209 | 210 | if (stream->running) { 211 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 212 | return STATUS_INVALID_DEVICE_REQUEST; 213 | } 214 | 215 | PFDO_CONTEXT fdoContext = devData->FdoContext; 216 | int mask = HDA_PPCTL_PROCEN(stream->idx); 217 | UINT32 val = 0; 218 | val = read16(fdoContext->ppcap + HDA_REG_PP_PPCTL) & mask; 219 | 220 | if (val) { 221 | hdac_update32(fdoContext->ppcap, HDA_REG_PP_PPCTL, mask, 0); 222 | } 223 | 224 | stream->PdoContext = NULL; 225 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 226 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 227 | 228 | return STATUS_SUCCESS; 229 | } 230 | 231 | NTSTATUS ADSPPrepareDSP( 232 | _In_ PVOID _context, 233 | _In_ HANDLE Handle, 234 | _In_ unsigned int ByteSize, 235 | _In_ int NumBlocks, 236 | _Out_ PVOID* bdlBuf 237 | ) { 238 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 239 | if (!devData->FdoContext) { 240 | return STATUS_NO_SUCH_DEVICE; 241 | } 242 | 243 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 244 | if (!stream || stream->PdoContext != devData) { 245 | return STATUS_INVALID_HANDLE; 246 | } 247 | 248 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 249 | 250 | if (stream->running) { 251 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 252 | return STATUS_DEVICE_BUSY; 253 | } 254 | 255 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 256 | 257 | PHYSICAL_ADDRESS maxAddr; 258 | maxAddr.QuadPart = MAXULONG64; 259 | 260 | stream->mdlBuf = NULL; 261 | stream->bufSz = ByteSize; 262 | stream->numBlocks = (UINT16)NumBlocks; 263 | 264 | hdac_stream_reset(stream); 265 | 266 | /* reset BDL address */ 267 | stream_write32(stream, SD_BDLPL, 0); 268 | stream_write32(stream, SD_BDLPU, 0); 269 | 270 | hdac_stream_setup(stream); 271 | 272 | if (bdlBuf) 273 | *bdlBuf = stream->bdl; 274 | return STATUS_SUCCESS; 275 | } 276 | 277 | NTSTATUS ADSPCleanupDSP(_In_ PVOID _context, _In_ HANDLE Handle) { 278 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 279 | if (!devData->FdoContext) { 280 | return STATUS_NO_SUCH_DEVICE; 281 | } 282 | 283 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 284 | if (!stream || stream->PdoContext != devData) { 285 | return STATUS_INVALID_HANDLE; 286 | } 287 | 288 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 289 | 290 | stream_write32(stream, SD_BDLPL, 0); 291 | stream_write32(stream, SD_BDLPU, 0); 292 | stream_write32(stream, SD_CTL, 0); 293 | 294 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 295 | 296 | return STATUS_SUCCESS; 297 | } 298 | 299 | void ADSPStartStopDSP(_In_ PVOID _context, _In_ HANDLE Handle, BOOL startStop) { 300 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 301 | if (!devData->FdoContext) { 302 | return; 303 | } 304 | 305 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 306 | if (!stream || stream->PdoContext != devData) { 307 | return; 308 | } 309 | 310 | if (startStop) 311 | hdac_stream_start(stream); 312 | else 313 | hdac_stream_stop(stream); 314 | } 315 | 316 | void ADSPEnableSPIB(_In_ PVOID _context, _In_ HANDLE Handle, UINT32 value) { 317 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 318 | if (!devData->FdoContext) { 319 | return; 320 | } 321 | 322 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 323 | if (!stream || stream->PdoContext != devData) { 324 | return; 325 | } 326 | 327 | if (!devData->FdoContext->spbcap) { 328 | return; 329 | } 330 | 331 | UINT32 mask = (1 << stream->idx); 332 | hdac_update32(devData->FdoContext->spbcap, HDA_REG_SPB_SPBFCCTL, mask, mask); 333 | 334 | write32(stream->spib_addr, value); 335 | } 336 | 337 | void ADSPDisableSPIB(_In_ PVOID _context, _In_ HANDLE Handle) { 338 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 339 | if (!devData->FdoContext) { 340 | return; 341 | } 342 | 343 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 344 | if (!stream || stream->PdoContext != devData) { 345 | return; 346 | } 347 | 348 | if (!devData->FdoContext->spbcap) { 349 | return; 350 | } 351 | 352 | UINT32 mask = (1 << stream->idx); 353 | hdac_update32(devData->FdoContext->spbcap, HDA_REG_SPB_SPBFCCTL, mask, 0); 354 | 355 | write32(stream->spib_addr, 0); 356 | } 357 | 358 | UINT32 ADSPStreamPosition(_In_ PVOID _context, _In_ HANDLE Handle) { 359 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 360 | if (!devData->FdoContext) { 361 | return 0; 362 | } 363 | 364 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 365 | if (!stream || stream->PdoContext != devData) { 366 | return 0; 367 | } 368 | 369 | return *stream->posbuf; 370 | } 371 | 372 | ADSP_BUS_INTERFACE ADSP_BusInterface(PVOID Context) { 373 | ADSP_BUS_INTERFACE busInterface; 374 | RtlZeroMemory(&busInterface, sizeof(ADSP_BUS_INTERFACE)); 375 | 376 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)Context; 377 | 378 | busInterface.Size = sizeof(ADSP_BUS_INTERFACE); 379 | busInterface.Version = 1; 380 | busInterface.Context = Context; 381 | busInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; 382 | busInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; 383 | busInterface.CtlrDevId = devData->CodecIds.CtlrDevId; 384 | busInterface.GetResources = ADSPGetResources; 385 | busInterface.SetDSPPowerState = ADSPSetPowerState; 386 | busInterface.RegisterInterrupt = ADSPRegisterInterrupt; 387 | busInterface.UnregisterInterrupt = ADSPUnregisterInterrupt; 388 | 389 | busInterface.GetRenderStream = ADSPGetRenderStream; 390 | busInterface.GetCaptureStream = ADSPGetCaptureStream; 391 | busInterface.FreeStream = ADSPFreeStream; 392 | busInterface.PrepareDSP = ADSPPrepareDSP; 393 | busInterface.CleanupDSP = ADSPCleanupDSP; 394 | busInterface.TriggerDSP = ADSPStartStopDSP; 395 | busInterface.StreamPosition = ADSPStreamPosition; 396 | 397 | busInterface.DSPEnableSPIB = ADSPEnableSPIB; 398 | busInterface.DSPDisableSPIB = ADSPDisableSPIB; 399 | 400 | return busInterface; 401 | } -------------------------------------------------------------------------------- /sklhdaudbus/hdac_controller.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | //New 4 | NTSTATUS ResetHDAController(PFDO_CONTEXT fdoCtx, BOOLEAN wakeup) { 5 | UINT32 gctl; 6 | 7 | //Clear STATESTS 8 | hda_write16(fdoCtx, STATESTS, STATESTS_INT_MASK); 9 | 10 | //Stop all Streams DMA Engine 11 | for (UINT32 i = 0; i < fdoCtx->numStreams; i++) { 12 | hdac_stream_stop(&fdoCtx->streams[i]); 13 | } 14 | 15 | //Stop CORB and RIRB 16 | hda_write8(fdoCtx, CORBCTL, 0); 17 | hda_write8(fdoCtx, RIRBCTL, 0); 18 | 19 | //Reset DMA position buffer 20 | hda_write32(fdoCtx, DPLBASE, 0); 21 | hda_write32(fdoCtx, DPUBASE, 0); 22 | 23 | //Reset the controller for at least 100 us 24 | gctl = hda_read32(fdoCtx, GCTL); 25 | hda_write32(fdoCtx, GCTL, gctl & ~HDA_GCTL_RESET); 26 | 27 | for (int count = 0; count < 1000; count++) { 28 | gctl = hda_read32(fdoCtx, GCTL); 29 | if (!(gctl & HDA_GCTL_RESET)) { 30 | break; 31 | } 32 | udelay(10); 33 | } 34 | 35 | if (gctl & HDA_GCTL_RESET) { 36 | DbgPrint("Error: unable to put controller in reset\n"); 37 | return STATUS_DEVICE_POWER_FAILURE; 38 | } 39 | 40 | //If wakeup not requested, leave in reset state 41 | if (!wakeup) 42 | return STATUS_SUCCESS; 43 | 44 | udelay(100); 45 | gctl = hda_read32(fdoCtx, GCTL); 46 | hda_write32(fdoCtx, GCTL, gctl | HDA_GCTL_RESET); 47 | 48 | for (int count = 0; count < 1000; count++) { 49 | gctl = hda_read32(fdoCtx, GCTL); 50 | if (gctl & HDA_GCTL_RESET) { 51 | break; 52 | } 53 | udelay(10); 54 | } 55 | if (!(gctl & HDA_GCTL_RESET)) { 56 | DbgPrint("Error: controller stuck in reset\n"); 57 | return STATUS_DEVICE_POWER_FAILURE; 58 | } 59 | 60 | //Wait for codecs to finish their own reset sequence. Delay from VoodooHDA so it resets properly 61 | udelay(1000); 62 | 63 | if (!fdoCtx->codecMask) { 64 | fdoCtx->codecMask = hda_read16(fdoCtx, STATESTS); 65 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 66 | "codec mask = 0x%lx\n", fdoCtx->codecMask); 67 | } 68 | 69 | return STATUS_SUCCESS; 70 | } 71 | 72 | NTSTATUS GetHDACapabilities(PFDO_CONTEXT fdoCtx) { 73 | UINT16 gcap = hda_read16(fdoCtx, GCAP); 74 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 75 | "chipset global capabilities = 0x%x\n", gcap); 76 | 77 | fdoCtx->is64BitOK = (gcap & 0x1); 78 | if (!fdoCtx->is64BitOK) { 79 | return STATUS_DEVICE_PROTOCOL_ERROR; //64 bit required 80 | } 81 | 82 | fdoCtx->hwVersion = (hda_read8(fdoCtx, VMAJ) << 8) | hda_read8(fdoCtx, VMIN); 83 | 84 | fdoCtx->captureStreams = (gcap >> 8) & 0x0f; 85 | fdoCtx->playbackStreams = (gcap >> 12) & 0x0f; 86 | 87 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 88 | "streams (cap %d, playback %d)\n", fdoCtx->captureStreams, fdoCtx->playbackStreams); 89 | 90 | fdoCtx->captureIndexOff = 0; 91 | fdoCtx->playbackIndexOff = fdoCtx->captureStreams; 92 | fdoCtx->numStreams = fdoCtx->captureStreams + fdoCtx->playbackStreams; 93 | 94 | UINT8 corbSize = hda_read8(fdoCtx, CORBSIZE); 95 | if (!(corbSize & 0x40)) { 96 | return STATUS_DEVICE_FEATURE_NOT_SUPPORTED; //CORB must support 256 97 | } 98 | 99 | UINT8 rirbSize = hda_read8(fdoCtx, RIRBSIZE); 100 | if (!(rirbSize & 0x40)) { 101 | return STATUS_DEVICE_FEATURE_NOT_SUPPORTED; //RIRB must support 256 102 | } 103 | 104 | return STATUS_SUCCESS; 105 | } 106 | 107 | void HDAInitCorb(PFDO_CONTEXT fdoCtx) { 108 | //Set the corb size to 256 entries 109 | hda_write8(fdoCtx, CORBSIZE, 0x02); 110 | 111 | //Setup CORB address 112 | fdoCtx->corb.buf = (UINT32*)fdoCtx->rb; 113 | fdoCtx->corb.addr = MmGetPhysicalAddress(fdoCtx->corb.buf); 114 | hda_write32(fdoCtx, CORBLBASE, fdoCtx->corb.addr.LowPart); 115 | hda_write32(fdoCtx, CORBUBASE, fdoCtx->corb.addr.HighPart); 116 | 117 | //Set WP and RP 118 | fdoCtx->corb.wp = 0; 119 | hda_write16(fdoCtx, CORBWP, fdoCtx->corb.wp); 120 | hda_write16(fdoCtx, CORBRP, HDA_CORBRP_RST); 121 | 122 | udelay(10); //Delay for 10 us to reset 123 | 124 | hda_write16(fdoCtx, CORBRP, 0); 125 | } 126 | 127 | void HDAInitRirb(PFDO_CONTEXT fdoCtx) { 128 | //Set the rirb size to 256 entries 129 | hda_write8(fdoCtx, RIRBSIZE, 0x02); 130 | 131 | //Setup CORB address 132 | fdoCtx->rirb.buf = (UINT32*)(fdoCtx->rb + 0x800); 133 | fdoCtx->rirb.addr = MmGetPhysicalAddress(fdoCtx->rirb.buf); 134 | RtlZeroMemory(fdoCtx->rirb.cmds, sizeof(fdoCtx->rirb.cmds)); 135 | hda_write32(fdoCtx, RIRBLBASE, fdoCtx->rirb.addr.LowPart); 136 | hda_write32(fdoCtx, RIRBUBASE, fdoCtx->rirb.addr.HighPart); 137 | 138 | //Set WP and RP 139 | fdoCtx->rirb.rp = 0; 140 | hda_write16(fdoCtx, RIRBWP, HDA_RIRBWP_RST); 141 | 142 | //Set interrupt threshold 143 | hda_write16(fdoCtx, RINTCNT, 1); 144 | 145 | //Enable Received response reporting 146 | hda_write8(fdoCtx, RIRBCTL, HDA_RBCTL_IRQ_EN); 147 | } 148 | 149 | void HDAStartCorb(PFDO_CONTEXT fdoCtx) { 150 | UINT8 corbCTL; 151 | corbCTL = hda_read8(fdoCtx, CORBCTL); 152 | corbCTL |= HDA_CORBCTL_RUN; 153 | hda_write8(fdoCtx, CORBCTL, corbCTL); 154 | } 155 | 156 | void HDAStartRirb(PFDO_CONTEXT fdoCtx) { 157 | UINT8 rirbCTL; 158 | rirbCTL = hda_read8(fdoCtx, RIRBCTL); 159 | rirbCTL |= HDA_RBCTL_DMA_EN; 160 | hda_write8(fdoCtx, RIRBCTL, rirbCTL); 161 | } 162 | 163 | NTSTATUS StartHDAController(PFDO_CONTEXT fdoCtx) { 164 | NTSTATUS status; 165 | status = ResetHDAController(fdoCtx, TRUE); 166 | if (!NT_SUCCESS(status)) { 167 | goto exit; 168 | } 169 | 170 | //Clear STATESTS 171 | hda_write16(fdoCtx, STATESTS, STATESTS_INT_MASK); 172 | 173 | HDAInitCorb(fdoCtx); 174 | HDAInitRirb(fdoCtx); 175 | 176 | HDAStartCorb(fdoCtx); 177 | HDAStartRirb(fdoCtx); 178 | 179 | //Enabling Controller Interrupt 180 | hda_write32(fdoCtx, GCTL, hda_read32(fdoCtx, GCTL) | HDA_GCTL_UNSOL); 181 | hda_write32(fdoCtx, INTCTL, hda_read32(fdoCtx, INTCTL) | HDA_INT_CTRL_EN | HDA_INT_GLOBAL_EN); 182 | 183 | //Program position buffer 184 | PHYSICAL_ADDRESS posbufAddr = MmGetPhysicalAddress(fdoCtx->posbuf); 185 | hda_write32(fdoCtx, DPLBASE, posbufAddr.LowPart); 186 | hda_write32(fdoCtx, DPUBASE, posbufAddr.HighPart); 187 | 188 | udelay(1000); 189 | 190 | fdoCtx->ControllerEnabled = TRUE; 191 | 192 | exit: 193 | return status; 194 | } 195 | 196 | NTSTATUS StopHDAController(PFDO_CONTEXT fdoCtx) { 197 | NTSTATUS status = ResetHDAController(fdoCtx, FALSE); 198 | fdoCtx->ControllerEnabled = FALSE; 199 | return status; 200 | } 201 | 202 | static UINT16 HDACommandAddr(UINT32 cmd) { 203 | return (cmd >> 28) & 0xF; 204 | } 205 | 206 | NTSTATUS SendHDACmds(PFDO_CONTEXT fdoCtx, ULONG count, PHDAUDIO_CODEC_TRANSFER CodecTransfer) { 207 | WdfInterruptAcquireLock(fdoCtx->Interrupt); 208 | for (ULONG i = 0; i < count; i++) { 209 | PHDAUDIO_CODEC_TRANSFER transfer = &CodecTransfer[i]; 210 | RtlZeroMemory(&transfer->Input, sizeof(transfer->Input)); 211 | 212 | UINT16 addr = HDACommandAddr(transfer->Output.Command); 213 | 214 | //Add command to corb 215 | UINT16 wp = hda_read16(fdoCtx, CORBWP); 216 | if (wp == 0xffff) { 217 | //Something wrong, controller likely went to sleep 218 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 219 | "%s: device not found\n", __func__); 220 | WdfInterruptReleaseLock(fdoCtx->Interrupt); 221 | return STATUS_DEVICE_DOES_NOT_EXIST; 222 | } 223 | 224 | wp++; 225 | wp %= HDA_MAX_CORB_ENTRIES; 226 | 227 | UINT16 rp = hda_read16(fdoCtx, CORBRP); 228 | if (wp == rp) { 229 | //Oops it's full 230 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 231 | "%s: device busy\n", __func__); 232 | WdfInterruptReleaseLock(fdoCtx->Interrupt); 233 | return STATUS_RETRY; 234 | } 235 | 236 | LONG oldVal = InterlockedIncrement(&fdoCtx->rirb.cmds[addr]); 237 | fdoCtx->rirb.xfer[addr].xfer[oldVal - 1] = transfer; 238 | 239 | fdoCtx->corb.buf[wp] = transfer->Output.Command; 240 | 241 | hda_write16(fdoCtx, CORBWP, wp); 242 | } 243 | 244 | WdfInterruptReleaseLock(fdoCtx->Interrupt); 245 | return STATUS_SUCCESS; 246 | } 247 | 248 | NTSTATUS RunSingleHDACmd(PFDO_CONTEXT fdoCtx, ULONG val, ULONG* res) { 249 | HDAUDIO_CODEC_TRANSFER transfer = { 0 }; 250 | transfer.Output.Command = val; 251 | 252 | NTSTATUS status = SendHDACmds(fdoCtx, 1, &transfer); 253 | if (!NT_SUCCESS(status)) { 254 | return status; 255 | } 256 | 257 | LARGE_INTEGER StartTime; 258 | KeQuerySystemTime(&StartTime); 259 | 260 | int timeout_ms = 1000; 261 | for (ULONG loopcounter = 0; ; loopcounter++) { 262 | if (transfer.Input.IsValid) { 263 | if (res) { 264 | *res = transfer.Input.Response; 265 | } 266 | return STATUS_SUCCESS; 267 | } 268 | 269 | LARGE_INTEGER CurrentTime; 270 | KeQuerySystemTime(&CurrentTime); 271 | 272 | UINT16 addr = HDACommandAddr(transfer.Output.Command); 273 | 274 | if (((CurrentTime.QuadPart - StartTime.QuadPart) / (10 * 1000)) >= timeout_ms) { 275 | WdfInterruptAcquireLock(fdoCtx->Interrupt); 276 | InterlockedDecrement(&fdoCtx->rirb.cmds[addr]); 277 | WdfInterruptReleaseLock(fdoCtx->Interrupt); 278 | return STATUS_IO_TIMEOUT; 279 | } 280 | 281 | LARGE_INTEGER Timeout; 282 | Timeout.QuadPart = -10 * 100; 283 | KeWaitForSingleObject(&fdoCtx->rirb.xferEvent[addr], Executive, KernelMode, TRUE, &Timeout); 284 | } 285 | } 286 | 287 | #define HDA_RIRB_EX_UNSOL_EV (1<<4) 288 | 289 | static void HDAProcessUnsolEvents(PFDO_CONTEXT fdoCtx) { 290 | UINT rp; 291 | while (fdoCtx->unsol_rp != fdoCtx->unsol_wp) { 292 | rp = (fdoCtx->unsol_rp + 1) % HDA_UNSOL_QUEUE_SIZE; 293 | fdoCtx->unsol_rp = rp; 294 | 295 | HDAC_RIRB rirb = fdoCtx->unsol_queue[rp]; 296 | 297 | if (!(rirb.response_ex & HDA_RIRB_EX_UNSOL_EV)) //no unsolicited event 298 | continue; 299 | 300 | HDAUDIO_CODEC_RESPONSE response; 301 | RtlZeroMemory(&response, sizeof(HDAUDIO_CODEC_RESPONSE)); 302 | 303 | response.Response = rirb.response; 304 | response.IsUnsolicitedResponse = 1; 305 | 306 | PPDO_DEVICE_DATA codec = fdoCtx->codecs[rirb.response_ex & 0x0f]; 307 | if (!codec || codec->FdoContext != fdoCtx) 308 | continue; 309 | 310 | UINT Tag = response.Unsolicited.Tag; 311 | CODEC_UNSOLIT_CALLBACK callback = codec->unsolitCallbacks[Tag]; 312 | if (callback.inUse && callback.Routine) { 313 | callback.Routine(response, callback.Context); 314 | } 315 | } 316 | } 317 | 318 | static void HDAFlushRIRB(PFDO_CONTEXT fdoCtx) { 319 | UINT16 wp, addr; 320 | 321 | wp = hda_read16(fdoCtx, RIRBWP); 322 | if (wp == 0xffff) { 323 | //Invalid WP 324 | return; 325 | } 326 | 327 | if (wp == fdoCtx->rirb.wp) 328 | return; 329 | fdoCtx->rirb.wp = wp; 330 | 331 | while (fdoCtx->rirb.rp != wp) { 332 | fdoCtx->rirb.rp++; 333 | fdoCtx->rirb.rp %= HDA_MAX_RIRB_ENTRIES; 334 | 335 | HDAC_RIRB rirb = fdoCtx->rirb.rirbbuf[fdoCtx->rirb.rp]; 336 | 337 | addr = rirb.response_ex & 0xf; 338 | if (addr >= HDA_MAX_CODECS) { 339 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 340 | "Unexpected unsolicited response %x: %x\n", 341 | rirb.response, rirb.response_ex); 342 | } 343 | else if (rirb.response_ex & HDA_RIRB_EX_UNSOL_EV) { 344 | UINT unsol_wp = (fdoCtx->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE; 345 | fdoCtx->unsol_wp = unsol_wp; 346 | 347 | fdoCtx->unsol_queue[unsol_wp] = rirb; 348 | 349 | fdoCtx->processUnsol = TRUE; 350 | } 351 | else if (InterlockedAdd(&fdoCtx->rirb.cmds[addr], 0)) { 352 | PHDAC_CODEC_XFER codecXfer = &fdoCtx->rirb.xfer[addr]; 353 | if (codecXfer->xfer[0]) { 354 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 355 | "Got response for 0x%x: 0x%x\n", codecXfer->xfer[0]->Output.Command, rirb.response); 356 | codecXfer->xfer[0]->Input.Response = rirb.response; 357 | codecXfer->xfer[0]->Input.IsValid = 1; 358 | } 359 | else { 360 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 361 | "Got response 0x%x but no xfer!\n", rirb.response); 362 | } 363 | 364 | RtlMoveMemory(&codecXfer->xfer[0], &codecXfer->xfer[1], sizeof(PHDAUDIO_CODEC_TRANSFER) * (HDA_MAX_CORB_ENTRIES - 1)); 365 | codecXfer->xfer[HDA_MAX_CORB_ENTRIES - 1] = NULL; 366 | InterlockedDecrement(&fdoCtx->rirb.cmds[addr]); 367 | 368 | KeSetEvent(&fdoCtx->rirb.xferEvent[addr], IO_NO_INCREMENT, FALSE); 369 | } 370 | else { 371 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 372 | "Unexpected unsolicited response from address %d %x\n", addr, 373 | rirb.response); 374 | } 375 | } 376 | } 377 | 378 | int hda_stream_interrupt(PFDO_CONTEXT fdoCtx, unsigned int status) { 379 | int handled = 0; 380 | UINT8 sd_status; 381 | 382 | for (UINT32 i = 0; i < fdoCtx->numStreams; i++) { 383 | PHDAC_STREAM stream = &fdoCtx->streams[i]; 384 | if (status & stream->int_sta_mask) { 385 | sd_status = stream_read8(stream, SD_STS); 386 | stream_write8(stream, SD_STS, SD_INT_MASK); 387 | handled |= 1 << stream->idx; 388 | 389 | if (sd_status & SD_INT_COMPLETE) 390 | stream->irqReceived = TRUE; 391 | } 392 | } 393 | return handled; 394 | } 395 | 396 | BOOLEAN hda_interrupt( 397 | WDFINTERRUPT Interrupt, 398 | ULONG MessageID) { 399 | UNREFERENCED_PARAMETER(MessageID); 400 | 401 | WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); 402 | PFDO_CONTEXT fdoCtx = Fdo_GetContext(Device); 403 | 404 | BOOLEAN handled = FALSE; 405 | 406 | if (fdoCtx->dspInterruptCallback) { 407 | handled = (BOOLEAN)fdoCtx->dspInterruptCallback(fdoCtx->dspInterruptContext); 408 | } 409 | 410 | if (!fdoCtx->ControllerEnabled) 411 | return handled; 412 | 413 | UINT32 status = hda_read32(fdoCtx, INTSTS); 414 | if (status == 0 || status == 0xffffffff) 415 | return handled; 416 | 417 | handled = TRUE; 418 | 419 | if (hda_stream_interrupt(fdoCtx, status)) { 420 | WdfInterruptQueueDpcForIsr(Interrupt); 421 | } 422 | 423 | status = hda_read16(fdoCtx, RIRBSTS); 424 | if (status & RIRB_INT_MASK) { 425 | hda_write16(fdoCtx, RIRBSTS, RIRB_INT_MASK); 426 | if (status & RIRB_INT_RESPONSE) { 427 | HDAFlushRIRB(fdoCtx); 428 | } 429 | } 430 | 431 | if (fdoCtx->processUnsol) { 432 | WdfInterruptQueueDpcForIsr(Interrupt); 433 | } 434 | 435 | return handled; 436 | } 437 | 438 | void hda_dpc( 439 | WDFINTERRUPT Interrupt, 440 | WDFOBJECT AssociatedObject 441 | ) { 442 | UNREFERENCED_PARAMETER(AssociatedObject); 443 | 444 | WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); 445 | PFDO_CONTEXT fdoCtx = Fdo_GetContext(Device); 446 | 447 | for (UINT32 i = 0; i < fdoCtx->numStreams; i++) { 448 | PHDAC_STREAM stream = &fdoCtx->streams[i]; 449 | if (stream->irqReceived) { 450 | stream->irqReceived = FALSE; 451 | 452 | for (int j = 0; j < MAX_NOTIF_EVENTS; j++) { 453 | if (stream->registeredCallbacks[j].InUse) { 454 | LARGE_INTEGER unknownVal = { 0 }; 455 | KeQuerySystemTime(&unknownVal); 456 | stream->registeredCallbacks[j].NotificationCallback(stream->registeredCallbacks[j].CallbackContext, unknownVal); 457 | } 458 | } 459 | 460 | for (int j = 0; j < MAX_NOTIF_EVENTS; j++) { 461 | if (stream->registeredEvents[j]) { 462 | KeSetEvent(stream->registeredEvents[j], IO_NO_INCREMENT, FALSE); 463 | } 464 | } 465 | } 466 | } 467 | 468 | if (fdoCtx->processUnsol) { 469 | fdoCtx->processUnsol = FALSE; 470 | HDAProcessUnsolEvents(fdoCtx); 471 | } 472 | } -------------------------------------------------------------------------------- /sklhdaudbus/hda_verbs.h: -------------------------------------------------------------------------------- 1 | #if !defined(_HDA_VERBS_H_) 2 | #define _HDA_VERBS_H_ 3 | 4 | #define AC_NODE_ROOT 0x00 5 | 6 | /* 7 | * function group types 8 | */ 9 | enum { 10 | AC_GRP_AUDIO_FUNCTION = 0x01, 11 | AC_GRP_MODEM_FUNCTION = 0x02, 12 | }; 13 | 14 | /* 15 | * GET verbs 16 | */ 17 | #define AC_VERB_GET_STREAM_FORMAT 0x0a00 18 | #define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 19 | #define AC_VERB_GET_PROC_COEF 0x0c00 20 | #define AC_VERB_GET_COEF_INDEX 0x0d00 21 | #define AC_VERB_PARAMETERS 0x0f00 22 | #define AC_VERB_GET_CONNECT_SEL 0x0f01 23 | #define AC_VERB_GET_CONNECT_LIST 0x0f02 24 | #define AC_VERB_GET_PROC_STATE 0x0f03 25 | #define AC_VERB_GET_SDI_SELECT 0x0f04 26 | #define AC_VERB_GET_POWER_STATE 0x0f05 27 | #define AC_VERB_GET_CONV 0x0f06 28 | #define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 29 | #define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 30 | #define AC_VERB_GET_PIN_SENSE 0x0f09 31 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a 32 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c 33 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d 34 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ 35 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f 36 | /* f10-f1a: GPIO */ 37 | #define AC_VERB_GET_GPIO_DATA 0x0f15 38 | #define AC_VERB_GET_GPIO_MASK 0x0f16 39 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 40 | #define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 41 | #define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 42 | #define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a 43 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c 44 | /* f20: AFG/MFG */ 45 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 46 | #define AC_VERB_GET_STRIPE_CONTROL 0x0f24 47 | #define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d 48 | #define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e 49 | #define AC_VERB_GET_HDMI_ELDD 0x0f2f 50 | #define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 51 | #define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 52 | #define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 53 | #define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 54 | #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 55 | #define AC_VERB_GET_DEVICE_SEL 0xf35 56 | #define AC_VERB_GET_DEVICE_LIST 0xf36 57 | 58 | /* 59 | * SET verbs 60 | */ 61 | #define AC_VERB_SET_STREAM_FORMAT 0x200 62 | #define AC_VERB_SET_AMP_GAIN_MUTE 0x300 63 | #define AC_VERB_SET_PROC_COEF 0x400 64 | #define AC_VERB_SET_COEF_INDEX 0x500 65 | #define AC_VERB_SET_CONNECT_SEL 0x701 66 | #define AC_VERB_SET_PROC_STATE 0x703 67 | #define AC_VERB_SET_SDI_SELECT 0x704 68 | #define AC_VERB_SET_POWER_STATE 0x705 69 | #define AC_VERB_SET_CHANNEL_STREAMID 0x706 70 | #define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 71 | #define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 72 | #define AC_VERB_SET_PIN_SENSE 0x709 73 | #define AC_VERB_SET_BEEP_CONTROL 0x70a 74 | #define AC_VERB_SET_EAPD_BTLENABLE 0x70c 75 | #define AC_VERB_SET_DIGI_CONVERT_1 0x70d 76 | #define AC_VERB_SET_DIGI_CONVERT_2 0x70e 77 | #define AC_VERB_SET_DIGI_CONVERT_3 0x73e 78 | #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f 79 | #define AC_VERB_SET_GPIO_DATA 0x715 80 | #define AC_VERB_SET_GPIO_MASK 0x716 81 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 82 | #define AC_VERB_SET_GPIO_WAKE_MASK 0x718 83 | #define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 84 | #define AC_VERB_SET_GPIO_STICKY_MASK 0x71a 85 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c 86 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d 87 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e 88 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f 89 | #define AC_VERB_SET_EAPD 0x788 90 | #define AC_VERB_SET_CODEC_RESET 0x7ff 91 | #define AC_VERB_SET_STRIPE_CONTROL 0x724 92 | #define AC_VERB_SET_CVT_CHAN_COUNT 0x72d 93 | #define AC_VERB_SET_HDMI_DIP_INDEX 0x730 94 | #define AC_VERB_SET_HDMI_DIP_DATA 0x731 95 | #define AC_VERB_SET_HDMI_DIP_XMIT 0x732 96 | #define AC_VERB_SET_HDMI_CP_CTRL 0x733 97 | #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 98 | #define AC_VERB_SET_DEVICE_SEL 0x735 99 | 100 | /* 101 | * Parameter IDs 102 | */ 103 | #define AC_PAR_VENDOR_ID 0x00 104 | #define AC_PAR_SUBSYSTEM_ID 0x01 105 | #define AC_PAR_REV_ID 0x02 106 | #define AC_PAR_NODE_COUNT 0x04 107 | #define AC_PAR_FUNCTION_TYPE 0x05 108 | #define AC_PAR_AUDIO_FG_CAP 0x08 109 | #define AC_PAR_AUDIO_WIDGET_CAP 0x09 110 | #define AC_PAR_PCM 0x0a 111 | #define AC_PAR_STREAM 0x0b 112 | #define AC_PAR_PIN_CAP 0x0c 113 | #define AC_PAR_AMP_IN_CAP 0x0d 114 | #define AC_PAR_CONNLIST_LEN 0x0e 115 | #define AC_PAR_POWER_STATE 0x0f 116 | #define AC_PAR_PROC_CAP 0x10 117 | #define AC_PAR_GPIO_CAP 0x11 118 | #define AC_PAR_AMP_OUT_CAP 0x12 119 | #define AC_PAR_VOL_KNB_CAP 0x13 120 | #define AC_PAR_DEVLIST_LEN 0x15 121 | #define AC_PAR_HDMI_LPCM_CAP 0x20 122 | 123 | /* 124 | * AC_VERB_PARAMETERS results (32bit) 125 | */ 126 | 127 | /* Function Group Type */ 128 | #define AC_FGT_TYPE (0xff<<0) 129 | #define AC_FGT_TYPE_SHIFT 0 130 | #define AC_FGT_UNSOL_CAP (1<<8) 131 | 132 | /* Audio Function Group Capabilities */ 133 | #define AC_AFG_OUT_DELAY (0xf<<0) 134 | #define AC_AFG_IN_DELAY (0xf<<8) 135 | #define AC_AFG_BEEP_GEN (1<<16) 136 | 137 | /* Audio Widget Capabilities */ 138 | #define AC_WCAP_STEREO (1<<0) /* stereo I/O */ 139 | #define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ 140 | #define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ 141 | #define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ 142 | #define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ 143 | #define AC_WCAP_STRIPE (1<<5) /* stripe */ 144 | #define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ 145 | #define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ 146 | #define AC_WCAP_CONN_LIST (1<<8) /* connection list */ 147 | #define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ 148 | #define AC_WCAP_POWER (1<<10) /* power control */ 149 | #define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ 150 | #define AC_WCAP_CP_CAPS (1<<12) /* content protection */ 151 | #define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ 152 | #define AC_WCAP_DELAY (0xf<<16) 153 | #define AC_WCAP_DELAY_SHIFT 16 154 | #define AC_WCAP_TYPE (0xf<<20) 155 | #define AC_WCAP_TYPE_SHIFT 20 156 | 157 | /* supported PCM rates and bits */ 158 | #define AC_SUPPCM_RATES (0xfff << 0) 159 | #define AC_SUPPCM_BITS_8 (1<<16) 160 | #define AC_SUPPCM_BITS_16 (1<<17) 161 | #define AC_SUPPCM_BITS_20 (1<<18) 162 | #define AC_SUPPCM_BITS_24 (1<<19) 163 | #define AC_SUPPCM_BITS_32 (1<<20) 164 | 165 | /* supported PCM stream format */ 166 | #define AC_SUPFMT_PCM (1<<0) 167 | #define AC_SUPFMT_FLOAT32 (1<<1) 168 | #define AC_SUPFMT_AC3 (1<<2) 169 | 170 | /* GP I/O count */ 171 | #define AC_GPIO_IO_COUNT (0xff<<0) 172 | #define AC_GPIO_O_COUNT (0xff<<8) 173 | #define AC_GPIO_O_COUNT_SHIFT 8 174 | #define AC_GPIO_I_COUNT (0xff<<16) 175 | #define AC_GPIO_I_COUNT_SHIFT 16 176 | #define AC_GPIO_UNSOLICITED (1<<30) 177 | #define AC_GPIO_WAKE (1<<31) 178 | 179 | /* Converter stream, channel */ 180 | #define AC_CONV_CHANNEL (0xf<<0) 181 | #define AC_CONV_STREAM (0xf<<4) 182 | #define AC_CONV_STREAM_SHIFT 4 183 | 184 | /* Input converter SDI select */ 185 | #define AC_SDI_SELECT (0xf<<0) 186 | 187 | /* stream format id */ 188 | #define AC_FMT_CHAN_SHIFT 0 189 | #define AC_FMT_CHAN_MASK (0x0f << 0) 190 | #define AC_FMT_BITS_SHIFT 4 191 | #define AC_FMT_BITS_MASK (7 << 4) 192 | #define AC_FMT_BITS_8 (0 << 4) 193 | #define AC_FMT_BITS_16 (1 << 4) 194 | #define AC_FMT_BITS_20 (2 << 4) 195 | #define AC_FMT_BITS_24 (3 << 4) 196 | #define AC_FMT_BITS_32 (4 << 4) 197 | #define AC_FMT_DIV_SHIFT 8 198 | #define AC_FMT_DIV_MASK (7 << 8) 199 | #define AC_FMT_MULT_SHIFT 11 200 | #define AC_FMT_MULT_MASK (7 << 11) 201 | #define AC_FMT_BASE_SHIFT 14 202 | #define AC_FMT_BASE_48K (0 << 14) 203 | #define AC_FMT_BASE_44K (1 << 14) 204 | #define AC_FMT_TYPE_SHIFT 15 205 | #define AC_FMT_TYPE_PCM (0 << 15) 206 | #define AC_FMT_TYPE_NON_PCM (1 << 15) 207 | 208 | /* Unsolicited response control */ 209 | #define AC_UNSOL_TAG (0x3f<<0) 210 | #define AC_UNSOL_ENABLED (1<<7) 211 | #define AC_USRSP_EN AC_UNSOL_ENABLED 212 | 213 | /* Unsolicited responses */ 214 | #define AC_UNSOL_RES_TAG (0x3f<<26) 215 | #define AC_UNSOL_RES_TAG_SHIFT 26 216 | #define AC_UNSOL_RES_SUBTAG (0x1f<<21) 217 | #define AC_UNSOL_RES_SUBTAG_SHIFT 21 218 | #define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry 219 | * (for DP1.2 MST) 220 | */ 221 | #define AC_UNSOL_RES_DE_SHIFT 15 222 | #define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */ 223 | #define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ 224 | #define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ 225 | #define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ 226 | #define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ 227 | 228 | /* Pin widget capabilies */ 229 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ 230 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ 231 | #define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ 232 | #define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ 233 | #define AC_PINCAP_OUT (1<<4) /* output capable */ 234 | #define AC_PINCAP_IN (1<<5) /* input capable */ 235 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ 236 | /* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, 237 | * but is marked reserved in the Intel HDA specification. 238 | */ 239 | #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ 240 | /* Note: The same bit as LR_SWAP is newly defined as HDMI capability 241 | * in HD-audio specification 242 | */ 243 | #define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ 244 | #define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can 245 | * coexist with AC_PINCAP_HDMI 246 | */ 247 | #define AC_PINCAP_VREF (0x37<<8) 248 | #define AC_PINCAP_VREF_SHIFT 8 249 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ 250 | #define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ 251 | /* Vref status (used in pin cap) */ 252 | #define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ 253 | #define AC_PINCAP_VREF_50 (1<<1) /* 50% */ 254 | #define AC_PINCAP_VREF_GRD (1<<2) /* ground */ 255 | #define AC_PINCAP_VREF_80 (1<<4) /* 80% */ 256 | #define AC_PINCAP_VREF_100 (1<<5) /* 100% */ 257 | 258 | /* Amplifier capabilities */ 259 | #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ 260 | #define AC_AMPCAP_OFFSET_SHIFT 0 261 | #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ 262 | #define AC_AMPCAP_NUM_STEPS_SHIFT 8 263 | #define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB 264 | * in 0.25dB 265 | */ 266 | #define AC_AMPCAP_STEP_SIZE_SHIFT 16 267 | #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ 268 | #define AC_AMPCAP_MUTE_SHIFT 31 269 | 270 | /* driver-specific amp-caps: using bits 24-30 */ 271 | #define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ 272 | 273 | /* Connection list */ 274 | #define AC_CLIST_LENGTH (0x7f<<0) 275 | #define AC_CLIST_LONG (1<<7) 276 | 277 | /* Supported power status */ 278 | #define AC_PWRST_D0SUP (1<<0) 279 | #define AC_PWRST_D1SUP (1<<1) 280 | #define AC_PWRST_D2SUP (1<<2) 281 | #define AC_PWRST_D3SUP (1<<3) 282 | #define AC_PWRST_D3COLDSUP (1<<4) 283 | #define AC_PWRST_S3D3COLDSUP (1<<29) 284 | #define AC_PWRST_CLKSTOP (1<<30) 285 | #define AC_PWRST_EPSS (1U<<31) 286 | 287 | /* Power state values */ 288 | #define AC_PWRST_SETTING (0xf<<0) 289 | #define AC_PWRST_ACTUAL (0xf<<4) 290 | #define AC_PWRST_ACTUAL_SHIFT 4 291 | #define AC_PWRST_D0 0x00 292 | #define AC_PWRST_D1 0x01 293 | #define AC_PWRST_D2 0x02 294 | #define AC_PWRST_D3 0x03 295 | #define AC_PWRST_ERROR (1<<8) 296 | #define AC_PWRST_CLK_STOP_OK (1<<9) 297 | #define AC_PWRST_SETTING_RESET (1<<10) 298 | 299 | /* Processing capabilies */ 300 | #define AC_PCAP_BENIGN (1<<0) 301 | #define AC_PCAP_NUM_COEF (0xff<<8) 302 | #define AC_PCAP_NUM_COEF_SHIFT 8 303 | 304 | /* Volume knobs capabilities */ 305 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) 306 | #define AC_KNBCAP_DELTA (1<<7) 307 | 308 | /* HDMI LPCM capabilities */ 309 | #define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ 310 | #define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ 311 | #define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ 312 | #define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ 313 | #define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ 314 | #define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ 315 | #define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ 316 | #define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ 317 | #define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ 318 | #define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ 319 | #define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ 320 | #define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ 321 | #define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ 322 | #define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ 323 | 324 | /* Display pin's device list length */ 325 | #define AC_DEV_LIST_LEN_MASK 0x3f 326 | #define AC_MAX_DEV_LIST_LEN 64 327 | 328 | /* 329 | * Control Parameters 330 | */ 331 | 332 | /* Amp gain/mute */ 333 | #define AC_AMP_MUTE (1<<7) 334 | #define AC_AMP_GAIN (0x7f) 335 | #define AC_AMP_GET_INDEX (0xf<<0) 336 | 337 | #define AC_AMP_GET_LEFT (1<<13) 338 | #define AC_AMP_GET_RIGHT (0<<13) 339 | #define AC_AMP_GET_OUTPUT (1<<15) 340 | #define AC_AMP_GET_INPUT (0<<15) 341 | 342 | #define AC_AMP_SET_INDEX (0xf<<8) 343 | #define AC_AMP_SET_INDEX_SHIFT 8 344 | #define AC_AMP_SET_RIGHT (1<<12) 345 | #define AC_AMP_SET_LEFT (1<<13) 346 | #define AC_AMP_SET_INPUT (1<<14) 347 | #define AC_AMP_SET_OUTPUT (1<<15) 348 | 349 | /* DIGITAL1 bits */ 350 | #define AC_DIG1_ENABLE (1<<0) 351 | #define AC_DIG1_V (1<<1) 352 | #define AC_DIG1_VCFG (1<<2) 353 | #define AC_DIG1_EMPHASIS (1<<3) 354 | #define AC_DIG1_COPYRIGHT (1<<4) 355 | #define AC_DIG1_NONAUDIO (1<<5) 356 | #define AC_DIG1_PROFESSIONAL (1<<6) 357 | #define AC_DIG1_LEVEL (1<<7) 358 | 359 | /* DIGITAL2 bits */ 360 | #define AC_DIG2_CC (0x7f<<0) 361 | 362 | /* DIGITAL3 bits */ 363 | #define AC_DIG3_ICT (0xf<<0) 364 | #define AC_DIG3_KAE (1<<7) 365 | 366 | /* Pin widget control - 8bit */ 367 | #define AC_PINCTL_EPT (0x3<<0) 368 | #define AC_PINCTL_EPT_NATIVE 0 369 | #define AC_PINCTL_EPT_HBR 3 370 | #define AC_PINCTL_VREFEN (0x7<<0) 371 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ 372 | #define AC_PINCTL_VREF_50 1 /* 50% */ 373 | #define AC_PINCTL_VREF_GRD 2 /* ground */ 374 | #define AC_PINCTL_VREF_80 4 /* 80% */ 375 | #define AC_PINCTL_VREF_100 5 /* 100% */ 376 | #define AC_PINCTL_IN_EN (1<<5) 377 | #define AC_PINCTL_OUT_EN (1<<6) 378 | #define AC_PINCTL_HP_EN (1<<7) 379 | 380 | /* Pin sense - 32bit */ 381 | #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) 382 | #define AC_PINSENSE_PRESENCE (1<<31) 383 | #define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ 384 | 385 | /* EAPD/BTL enable - 32bit */ 386 | #define AC_EAPDBTL_BALANCED (1<<0) 387 | #define AC_EAPDBTL_EAPD (1<<1) 388 | #define AC_EAPDBTL_LR_SWAP (1<<2) 389 | 390 | /* HDMI ELD data */ 391 | #define AC_ELDD_ELD_VALID (1<<31) 392 | #define AC_ELDD_ELD_DATA 0xff 393 | 394 | /* HDMI DIP size */ 395 | #define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ 396 | #define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ 397 | 398 | /* HDMI DIP index */ 399 | #define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ 400 | #define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ 401 | 402 | /* HDMI DIP xmit (transmit) control */ 403 | #define AC_DIPXMIT_MASK (0x3<<6) 404 | #define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ 405 | #define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ 406 | #define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ 407 | 408 | /* HDMI content protection (CP) control */ 409 | #define AC_CPCTRL_CES (1<<9) /* current encryption state */ 410 | #define AC_CPCTRL_READY (1<<8) /* ready bit */ 411 | #define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ 412 | #define AC_CPCTRL_STATE (3<<0) /* current CP request state */ 413 | 414 | /* Converter channel <-> HDMI slot mapping */ 415 | #define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ 416 | #define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ 417 | 418 | /* configuration default - 32bit */ 419 | #define AC_DEFCFG_SEQUENCE (0xf<<0) 420 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) 421 | #define AC_DEFCFG_ASSOC_SHIFT 4 422 | #define AC_DEFCFG_MISC (0xf<<8) 423 | #define AC_DEFCFG_MISC_SHIFT 8 424 | #define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) 425 | #define AC_DEFCFG_COLOR (0xf<<12) 426 | #define AC_DEFCFG_COLOR_SHIFT 12 427 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) 428 | #define AC_DEFCFG_CONN_TYPE_SHIFT 16 429 | #define AC_DEFCFG_DEVICE (0xf<<20) 430 | #define AC_DEFCFG_DEVICE_SHIFT 20 431 | #define AC_DEFCFG_LOCATION (0x3f<<24) 432 | #define AC_DEFCFG_LOCATION_SHIFT 24 433 | #define AC_DEFCFG_PORT_CONN (0x3<<30) 434 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 435 | 436 | /* Display pin's device list entry */ 437 | #define AC_DE_PD (1<<0) 438 | #define AC_DE_ELDV (1<<1) 439 | #define AC_DE_IA (1<<2) 440 | 441 | /* device types (0x0-0xf) */ 442 | enum { 443 | AC_JACK_LINE_OUT, 444 | AC_JACK_SPEAKER, 445 | AC_JACK_HP_OUT, 446 | AC_JACK_CD, 447 | AC_JACK_SPDIF_OUT, 448 | AC_JACK_DIG_OTHER_OUT, 449 | AC_JACK_MODEM_LINE_SIDE, 450 | AC_JACK_MODEM_HAND_SIDE, 451 | AC_JACK_LINE_IN, 452 | AC_JACK_AUX, 453 | AC_JACK_MIC_IN, 454 | AC_JACK_TELEPHONY, 455 | AC_JACK_SPDIF_IN, 456 | AC_JACK_DIG_OTHER_IN, 457 | AC_JACK_OTHER = 0xf, 458 | }; 459 | 460 | /* jack connection types (0x0-0xf) */ 461 | enum { 462 | AC_JACK_CONN_UNKNOWN, 463 | AC_JACK_CONN_1_8, 464 | AC_JACK_CONN_1_4, 465 | AC_JACK_CONN_ATAPI, 466 | AC_JACK_CONN_RCA, 467 | AC_JACK_CONN_OPTICAL, 468 | AC_JACK_CONN_OTHER_DIGITAL, 469 | AC_JACK_CONN_OTHER_ANALOG, 470 | AC_JACK_CONN_DIN, 471 | AC_JACK_CONN_XLR, 472 | AC_JACK_CONN_RJ11, 473 | AC_JACK_CONN_COMB, 474 | AC_JACK_CONN_OTHER = 0xf, 475 | }; 476 | 477 | /* jack colors (0x0-0xf) */ 478 | enum { 479 | AC_JACK_COLOR_UNKNOWN, 480 | AC_JACK_COLOR_BLACK, 481 | AC_JACK_COLOR_GREY, 482 | AC_JACK_COLOR_BLUE, 483 | AC_JACK_COLOR_GREEN, 484 | AC_JACK_COLOR_RED, 485 | AC_JACK_COLOR_ORANGE, 486 | AC_JACK_COLOR_YELLOW, 487 | AC_JACK_COLOR_PURPLE, 488 | AC_JACK_COLOR_PINK, 489 | AC_JACK_COLOR_WHITE = 0xe, 490 | AC_JACK_COLOR_OTHER, 491 | }; 492 | 493 | /* Jack location (0x0-0x3f) */ 494 | /* common case */ 495 | enum { 496 | AC_JACK_LOC_NONE, 497 | AC_JACK_LOC_REAR, 498 | AC_JACK_LOC_FRONT, 499 | AC_JACK_LOC_LEFT, 500 | AC_JACK_LOC_RIGHT, 501 | AC_JACK_LOC_TOP, 502 | AC_JACK_LOC_BOTTOM, 503 | }; 504 | /* bits 4-5 */ 505 | enum { 506 | AC_JACK_LOC_EXTERNAL = 0x00, 507 | AC_JACK_LOC_INTERNAL = 0x10, 508 | AC_JACK_LOC_SEPARATE = 0x20, 509 | AC_JACK_LOC_OTHER = 0x30, 510 | }; 511 | enum { 512 | /* external on primary chasis */ 513 | AC_JACK_LOC_REAR_PANEL = 0x07, 514 | AC_JACK_LOC_DRIVE_BAY, 515 | /* internal */ 516 | AC_JACK_LOC_RISER = 0x17, 517 | AC_JACK_LOC_HDMI, 518 | AC_JACK_LOC_ATAPI, 519 | /* others */ 520 | AC_JACK_LOC_MOBILE_IN = 0x37, 521 | AC_JACK_LOC_MOBILE_OUT, 522 | }; 523 | 524 | /* Port connectivity (0-3) */ 525 | enum { 526 | AC_JACK_PORT_COMPLEX, 527 | AC_JACK_PORT_NONE, 528 | AC_JACK_PORT_FIXED, 529 | AC_JACK_PORT_BOTH, 530 | }; 531 | 532 | /* max. codec address */ 533 | #define HDA_MAX_CODEC_ADDRESS 0x0f 534 | 535 | #endif -------------------------------------------------------------------------------- /sklhdaudbus/buspdo.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "adsp.h" 3 | 4 | NTSTATUS 5 | Bus_CreatePdo( 6 | _In_ WDFDEVICE Device, 7 | _In_ PWDFDEVICE_INIT DeviceInit, 8 | _In_ PPDO_IDENTIFICATION_DESCRIPTION Desc 9 | ); 10 | 11 | NTSTATUS 12 | Bus_EvtChildListIdentificationDescriptionDuplicate( 13 | WDFCHILDLIST DeviceList, 14 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER SourceIdentificationDescription, 15 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER DestinationIdentificationDescription 16 | ) 17 | /*++ 18 | Routine Description: 19 | It is called when the framework needs to make a copy of a description. 20 | This happens when a request is made to create a new child device by 21 | calling WdfChildListAddOrUpdateChildDescriptionAsPresent. 22 | If this function is left unspecified, RtlCopyMemory will be used to copy the 23 | source description to destination. Memory for the description is managed by the 24 | framework. 25 | NOTE: Callback is invoked with an internal lock held. So do not call out 26 | to any WDF function which will require this lock 27 | (basically any other WDFCHILDLIST api) 28 | Arguments: 29 | DeviceList - Handle to the default WDFCHILDLIST created by the framework. 30 | SourceIdentificationDescription - Description of the child being created -memory in 31 | the calling thread stack. 32 | DestinationIdentificationDescription - Created by the framework in nonpaged pool. 33 | Return Value: 34 | NT Status code. 35 | --*/ 36 | { 37 | PPDO_IDENTIFICATION_DESCRIPTION src, dst; 38 | 39 | UNREFERENCED_PARAMETER(DeviceList); 40 | 41 | src = CONTAINING_RECORD(SourceIdentificationDescription, 42 | PDO_IDENTIFICATION_DESCRIPTION, 43 | Header); 44 | dst = CONTAINING_RECORD(DestinationIdentificationDescription, 45 | PDO_IDENTIFICATION_DESCRIPTION, 46 | Header); 47 | 48 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 49 | "%s\n", __func__); 50 | 51 | dst->FdoContext = src->FdoContext; 52 | RtlCopyMemory(&dst->CodecIds, &src->CodecIds, sizeof(dst->CodecIds)); 53 | 54 | return STATUS_SUCCESS; 55 | } 56 | 57 | BOOLEAN 58 | Bus_EvtChildListIdentificationDescriptionCompare( 59 | WDFCHILDLIST DeviceList, 60 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER FirstIdentificationDescription, 61 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER SecondIdentificationDescription 62 | ) 63 | /*++ 64 | Routine Description: 65 | It is called when the framework needs to compare one description with another. 66 | Typically this happens whenever a request is made to add a new child device. 67 | If this function is left unspecified, RtlCompareMemory will be used to compare the 68 | descriptions. 69 | NOTE: Callback is invoked with an internal lock held. So do not call out 70 | to any WDF function which will require this lock 71 | (basically any other WDFCHILDLIST api) 72 | Arguments: 73 | DeviceList - Handle to the default WDFCHILDLIST created by the framework. 74 | Return Value: 75 | TRUE or FALSE. 76 | --*/ 77 | { 78 | PPDO_IDENTIFICATION_DESCRIPTION lhs, rhs; 79 | 80 | UNREFERENCED_PARAMETER(DeviceList); 81 | 82 | lhs = CONTAINING_RECORD(FirstIdentificationDescription, 83 | PDO_IDENTIFICATION_DESCRIPTION, 84 | Header); 85 | rhs = CONTAINING_RECORD(SecondIdentificationDescription, 86 | PDO_IDENTIFICATION_DESCRIPTION, 87 | Header); 88 | 89 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 90 | "%s\n", __func__); 91 | 92 | return (lhs->FdoContext == rhs->FdoContext) && 93 | (RtlCompareMemory(&lhs->CodecIds, &rhs->CodecIds, sizeof(lhs->CodecIds)) == sizeof(lhs->CodecIds)); 94 | } 95 | 96 | VOID 97 | Bus_EvtChildListIdentificationDescriptionCleanup( 98 | _In_ WDFCHILDLIST DeviceList, 99 | _Inout_ PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription 100 | ) 101 | /*++ 102 | Routine Description: 103 | It is called to free up any memory resources allocated as part of the description. 104 | This happens when a child device is unplugged or ejected from the bus. 105 | Memory for the description itself will be freed by the framework. 106 | Arguments: 107 | DeviceList - Handle to the default WDFCHILDLIST created by the framework. 108 | IdentificationDescription - Description of the child being deleted 109 | Return Value: 110 | --*/ 111 | { 112 | UNREFERENCED_PARAMETER(DeviceList); 113 | UNREFERENCED_PARAMETER(IdentificationDescription); 114 | } 115 | 116 | NTSTATUS 117 | Bus_EvtDeviceListCreatePdo( 118 | WDFCHILDLIST DeviceList, 119 | PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, 120 | PWDFDEVICE_INIT ChildInit 121 | ) 122 | /*++ 123 | Routine Description: 124 | Called by the framework in response to Query-Device relation when 125 | a new PDO for a child device needs to be created. 126 | Arguments: 127 | DeviceList - Handle to the default WDFCHILDLIST created by the framework as part 128 | of FDO. 129 | IdentificationDescription - Decription of the new child device. 130 | ChildInit - It's a opaque structure used in collecting device settings 131 | and passed in as a parameter to CreateDevice. 132 | Return Value: 133 | NT Status code. 134 | --*/ 135 | { 136 | PPDO_IDENTIFICATION_DESCRIPTION pDesc; 137 | 138 | PAGED_CODE(); 139 | 140 | pDesc = CONTAINING_RECORD(IdentificationDescription, 141 | PDO_IDENTIFICATION_DESCRIPTION, 142 | Header); 143 | 144 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 145 | "%s\n", __func__); 146 | 147 | return Bus_CreatePdo(WdfChildListGetDevice(DeviceList), 148 | ChildInit, 149 | pDesc); 150 | } 151 | 152 | NTSTATUS 153 | Bus_CreatePdo( 154 | _In_ WDFDEVICE Device, 155 | _In_ PWDFDEVICE_INIT DeviceInit, 156 | _In_ PPDO_IDENTIFICATION_DESCRIPTION Desc 157 | ) 158 | { 159 | UNREFERENCED_PARAMETER(Device); 160 | 161 | NTSTATUS status; 162 | PPDO_DEVICE_DATA pdoData = NULL; 163 | WDFDEVICE hChild = NULL; 164 | WDF_QUERY_INTERFACE_CONFIG qiConfig; 165 | WDF_OBJECT_ATTRIBUTES pdoAttributes; 166 | WDF_DEVICE_PNP_CAPABILITIES pnpCaps; 167 | WDF_DEVICE_POWER_CAPABILITIES powerCaps; 168 | DECLARE_CONST_UNICODE_STRING(deviceLocation, L"High Definition Audio Bus"); 169 | DECLARE_UNICODE_STRING_SIZE(buffer, MAX_INSTANCE_ID_LEN); 170 | DECLARE_UNICODE_STRING_SIZE(deviceId, MAX_INSTANCE_ID_LEN); 171 | DECLARE_UNICODE_STRING_SIZE(compatId, MAX_INSTANCE_ID_LEN); 172 | 173 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 174 | "%s\n", __func__); 175 | 176 | if (Desc->CodecIds.IsDSP) { 177 | // 178 | // Set DeviceType 179 | // 180 | WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); 181 | 182 | // 183 | // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId 184 | // 185 | status = RtlUnicodeStringPrintf(&deviceId, L"CSAUDIO\\ADSP&CTLR_VEN_%04X&CTLR_DEV_%04X", 186 | Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId); 187 | if (!NT_SUCCESS(status)) { 188 | return status; 189 | } 190 | 191 | status = WdfPdoInitAssignInstanceID(DeviceInit, &deviceId); 192 | if (!NT_SUCCESS(status)) { 193 | return status; 194 | } 195 | 196 | status = WdfPdoInitAssignDeviceID(DeviceInit, &deviceId); 197 | if (!NT_SUCCESS(status)) { 198 | return status; 199 | } 200 | 201 | // 202 | // NOTE: same string is used to initialize hardware id too 203 | // 204 | status = WdfPdoInitAddHardwareID(DeviceInit, &deviceId); 205 | if (!NT_SUCCESS(status)) { 206 | return status; 207 | } 208 | 209 | status = RtlUnicodeStringPrintf(&compatId, L"CSAUDIO\\ADSP&CTLR_VEN_%04X&CTLR_DEV_%04X", 210 | Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId); 211 | if (!NT_SUCCESS(status)) { 212 | return status; 213 | } 214 | 215 | // 216 | // NOTE: same string is used to initialize compat id too 217 | // 218 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 219 | if (!NT_SUCCESS(status)) { 220 | return status; 221 | } 222 | } 223 | else { 224 | // 225 | // Set DeviceType 226 | // 227 | WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SOUND); 228 | 229 | PWCHAR prefix = L"HDAUDIO"; 230 | PWCHAR funcPrefix = L""; 231 | if (Desc->CodecIds.IsGraphicsCodec) { 232 | funcPrefix = L"SGPC_"; 233 | } 234 | 235 | // 236 | // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId 237 | // 238 | status = RtlUnicodeStringPrintf(&deviceId, L"%s\\%sFUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%04X", 239 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.VenId, Desc->CodecIds.DevId, Desc->CodecIds.SubsysId, Desc->CodecIds.RevId); 240 | if (!NT_SUCCESS(status)) { 241 | return status; 242 | } 243 | 244 | status = WdfPdoInitAssignDeviceID(DeviceInit, &deviceId); 245 | if (!NT_SUCCESS(status)) { 246 | return status; 247 | } 248 | 249 | // 250 | // NOTE: same string is used to initialize hardware id too 251 | // 252 | status = WdfPdoInitAddHardwareID(DeviceInit, &deviceId); 253 | if (!NT_SUCCESS(status)) { 254 | return status; 255 | } 256 | 257 | //Add second hardware ID without Rev 258 | status = RtlUnicodeStringPrintf(&deviceId, L"%s\\%sFUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", 259 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.VenId, Desc->CodecIds.DevId, Desc->CodecIds.SubsysId); 260 | if (!NT_SUCCESS(status)) { 261 | return status; 262 | } 263 | 264 | status = WdfPdoInitAddHardwareID(DeviceInit, &deviceId); 265 | if (!NT_SUCCESS(status)) { 266 | return status; 267 | } 268 | 269 | //Add Compatible Ids 270 | { 271 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&CTLR_DEV_%02X&VEN_%04X&DEV_%04X&REV_%04X", 272 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId, Desc->CodecIds.VenId, Desc->CodecIds.DevId, Desc->CodecIds.RevId); 273 | if (!NT_SUCCESS(status)) { 274 | return status; 275 | } 276 | 277 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 278 | if (!NT_SUCCESS(status)) { 279 | return status; 280 | } 281 | 282 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&VEN_%04X&DEV_%04X&REV_%04X", 283 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.VenId, Desc->CodecIds.DevId, Desc->CodecIds.RevId); 284 | if (!NT_SUCCESS(status)) { 285 | return status; 286 | } 287 | 288 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 289 | if (!NT_SUCCESS(status)) { 290 | return status; 291 | } 292 | 293 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&VEN_%04X&DEV_%04X&REV_%04X", 294 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.VenId, Desc->CodecIds.DevId, Desc->CodecIds.RevId); 295 | if (!NT_SUCCESS(status)) { 296 | return status; 297 | } 298 | 299 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 300 | if (!NT_SUCCESS(status)) { 301 | return status; 302 | } 303 | 304 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&CTLR_DEV_%02X&VEN_%04X&DEV_%04X", 305 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId, Desc->CodecIds.VenId, Desc->CodecIds.DevId); 306 | if (!NT_SUCCESS(status)) { 307 | return status; 308 | } 309 | 310 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 311 | if (!NT_SUCCESS(status)) { 312 | return status; 313 | } 314 | 315 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&VEN_%04X&DEV_%04X", 316 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.VenId, Desc->CodecIds.DevId); 317 | if (!NT_SUCCESS(status)) { 318 | return status; 319 | } 320 | 321 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 322 | if (!NT_SUCCESS(status)) { 323 | return status; 324 | } 325 | 326 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&VEN_%04X&DEV_%04X", 327 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.VenId, Desc->CodecIds.DevId); 328 | if (!NT_SUCCESS(status)) { 329 | return status; 330 | } 331 | 332 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 333 | if (!NT_SUCCESS(status)) { 334 | return status; 335 | } 336 | 337 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&CTLR_DEV_%02X&VEN_%04X", 338 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId, Desc->CodecIds.VenId); 339 | if (!NT_SUCCESS(status)) { 340 | return status; 341 | } 342 | 343 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 344 | if (!NT_SUCCESS(status)) { 345 | return status; 346 | } 347 | 348 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&VEN_%04X", 349 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.VenId); 350 | if (!NT_SUCCESS(status)) { 351 | return status; 352 | } 353 | 354 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 355 | if (!NT_SUCCESS(status)) { 356 | return status; 357 | } 358 | 359 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&VEN_%04X", 360 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.VenId); 361 | if (!NT_SUCCESS(status)) { 362 | return status; 363 | } 364 | 365 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 366 | if (!NT_SUCCESS(status)) { 367 | return status; 368 | } 369 | 370 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X&CTLR_DEV_%02X", 371 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId, Desc->CodecIds.CtlrDevId); 372 | if (!NT_SUCCESS(status)) { 373 | return status; 374 | } 375 | 376 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 377 | if (!NT_SUCCESS(status)) { 378 | return status; 379 | } 380 | 381 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X&CTLR_VEN_%02X", 382 | prefix, funcPrefix, Desc->CodecIds.FuncId, Desc->CodecIds.CtlrVenId); 383 | if (!NT_SUCCESS(status)) { 384 | return status; 385 | } 386 | 387 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 388 | if (!NT_SUCCESS(status)) { 389 | return status; 390 | } 391 | 392 | status = RtlUnicodeStringPrintf(&compatId, L"%s\\%sFUNC_%02X", 393 | prefix, funcPrefix, Desc->CodecIds.FuncId); 394 | if (!NT_SUCCESS(status)) { 395 | return status; 396 | } 397 | 398 | status = WdfPdoInitAddCompatibleID(DeviceInit, &compatId); 399 | if (!NT_SUCCESS(status)) { 400 | return status; 401 | } 402 | } 403 | } 404 | 405 | status = RtlUnicodeStringPrintf(&buffer, L"%02d", Desc->CodecIds.CodecAddress); 406 | if (!NT_SUCCESS(status)) { 407 | return status; 408 | } 409 | 410 | status = WdfPdoInitAssignInstanceID(DeviceInit, &buffer); 411 | if (!NT_SUCCESS(status)) { 412 | return status; 413 | } 414 | 415 | // 416 | // Provide a description about the device. This text is usually read from 417 | // the device. In the case of USB device, this text comes from the string 418 | // descriptor. This text is displayed momentarily by the PnP manager while 419 | // it's looking for a matching INF. If it finds one, it uses the Device 420 | // Description from the INF file or the friendly name created by 421 | // coinstallers to display in the device manager. FriendlyName takes 422 | // precedence over the DeviceDesc from the INF file. 423 | // 424 | if (Desc->CodecIds.IsDSP) { 425 | status = RtlUnicodeStringPrintf(&buffer, 426 | L"Intel Audio DSP"); 427 | } 428 | else { 429 | status = RtlUnicodeStringPrintf(&buffer, 430 | L"High Definition Audio Device"); 431 | } 432 | if (!NT_SUCCESS(status)) { 433 | return status; 434 | } 435 | 436 | // 437 | // You can call WdfPdoInitAddDeviceText multiple times, adding device 438 | // text for multiple locales. When the system displays the text, it 439 | // chooses the text that matches the current locale, if available. 440 | // Otherwise it will use the string for the default locale. 441 | // The driver can specify the driver's default locale by calling 442 | // WdfPdoInitSetDefaultLocale. 443 | // 444 | status = WdfPdoInitAddDeviceText(DeviceInit, 445 | &buffer, 446 | &deviceLocation, 447 | 0x409); 448 | if (!NT_SUCCESS(status)) { 449 | return status; 450 | } 451 | 452 | WdfPdoInitSetDefaultLocale(DeviceInit, 0x409); 453 | 454 | // 455 | // Initialize the attributes to specify the size of PDO device extension. 456 | // All the state information private to the PDO will be tracked here. 457 | // 458 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_DATA); 459 | 460 | status = WdfDeviceCreate(&DeviceInit, &pdoAttributes, &hChild); 461 | if (!NT_SUCCESS(status)) { 462 | return status; 463 | } 464 | 465 | // 466 | // Get the device context. 467 | // 468 | pdoData = PdoGetData(hChild); 469 | 470 | pdoData->FdoContext = Desc->FdoContext; 471 | RtlCopyMemory(&pdoData->CodecIds, &Desc->CodecIds, sizeof(Desc->CodecIds)); 472 | 473 | if (!Desc->CodecIds.IsDSP) 474 | Desc->FdoContext->codecs[Desc->CodecIds.CodecAddress] = pdoData; 475 | 476 | // 477 | // Set some properties for the child device. 478 | // 479 | WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); 480 | pnpCaps.Removable = WdfFalse; 481 | pnpCaps.EjectSupported = Desc->CodecIds.IsGraphicsCodec ? WdfTrue : WdfFalse; 482 | pnpCaps.SurpriseRemovalOK = Desc->CodecIds.IsGraphicsCodec ? WdfTrue : WdfFalse; 483 | 484 | pnpCaps.Address = Desc->CodecIds.CodecAddress; 485 | pnpCaps.UINumber = Desc->CodecIds.CodecAddress; 486 | 487 | WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); 488 | 489 | WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps); 490 | 491 | powerCaps.DeviceD1 = WdfTrue; 492 | powerCaps.WakeFromD1 = WdfTrue; 493 | powerCaps.DeviceWake = PowerDeviceD1; 494 | 495 | powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD1; 496 | powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; 497 | powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD2; 498 | powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD2; 499 | powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3; 500 | powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3; 501 | 502 | WdfDeviceSetPowerCapabilities(hChild, &powerCaps); 503 | 504 | if (Desc->CodecIds.IsDSP) { 505 | ADSP_BUS_INTERFACE busInterface = ADSP_BusInterface(pdoData); 506 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 507 | (PINTERFACE)&busInterface, 508 | &GUID_ADSP_BUS_INTERFACE, 509 | NULL); 510 | status = WdfDeviceAddQueryInterface(hChild, &qiConfig); 511 | } 512 | else { 513 | HDAUDIO_BUS_INTERFACE busInterface = HDA_BusInterface(pdoData); 514 | 515 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 516 | (PINTERFACE)&busInterface, 517 | &GUID_HDAUDIO_BUS_INTERFACE, 518 | NULL); 519 | 520 | status = WdfDeviceAddQueryInterface(hChild, &qiConfig); 521 | if (!NT_SUCCESS(status)) { 522 | return status; 523 | } 524 | 525 | HDAUDIO_BUS_INTERFACE_V2 busInterface2 = HDA_BusInterfaceV2(pdoData); 526 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 527 | (PINTERFACE)&busInterface2, 528 | &GUID_HDAUDIO_BUS_INTERFACE_V2, 529 | NULL); 530 | status = WdfDeviceAddQueryInterface(hChild, &qiConfig); 531 | if (!NT_SUCCESS(status)) { 532 | return status; 533 | } 534 | 535 | HDAUDIO_BUS_INTERFACE_V3 busInterface3 = HDA_BusInterfaceV3(pdoData); 536 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 537 | (PINTERFACE)&busInterface3, 538 | &GUID_HDAUDIO_BUS_INTERFACE_V3, 539 | NULL); 540 | status = WdfDeviceAddQueryInterface(hChild, &qiConfig); 541 | if (!NT_SUCCESS(status)) { 542 | return status; 543 | } 544 | } 545 | 546 | return status; 547 | } -------------------------------------------------------------------------------- /sklhdaudbus/hdaudio.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | NTSTATUS HDA_TransferCodecVerbs( 4 | _In_ PVOID _context, 5 | _In_ ULONG Count, 6 | _Inout_updates_(Count) 7 | PHDAUDIO_CODEC_TRANSFER CodecTransfer, 8 | _In_opt_ PHDAUDIO_TRANSFER_COMPLETE_CALLBACK Callback, 9 | _In_opt_ PVOID Context 10 | ) { 11 | SklHdAudBusPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, "%s called (Count: %d)!\n", __func__, Count); 12 | 13 | if (!_context) 14 | return STATUS_NO_SUCH_DEVICE; 15 | 16 | NTSTATUS status = STATUS_SUCCESS; 17 | 18 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 19 | if (!devData->FdoContext) { 20 | return STATUS_NO_SUCH_DEVICE; 21 | } 22 | 23 | PFDO_CONTEXT fdoCtx = devData->FdoContext; 24 | 25 | status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 26 | if (!NT_SUCCESS(status)) { 27 | return status; 28 | } 29 | 30 | status = SendHDACmds(fdoCtx, Count, CodecTransfer); 31 | if (!NT_SUCCESS(status)) { 32 | goto out; 33 | } 34 | 35 | UINT16 codecAddr = (UINT16)devData->CodecIds.CodecAddress; 36 | 37 | int timeout_ms = 1000; 38 | LARGE_INTEGER StartTime; 39 | KeQuerySystemTime(&StartTime); 40 | for (ULONG loopcounter = 0; ; loopcounter++) { 41 | ULONG TransferredCount = 0; 42 | for (ULONG i = 0; i < Count; i++) { 43 | if (CodecTransfer[i].Input.IsValid) { 44 | TransferredCount++; 45 | } 46 | } 47 | if (TransferredCount >= Count) { 48 | break; 49 | } 50 | 51 | LARGE_INTEGER CurrentTime; 52 | KeQuerySystemTime(&CurrentTime); 53 | 54 | if (((CurrentTime.QuadPart - StartTime.QuadPart) / (10 * 1000)) >= timeout_ms) { 55 | InterlockedAdd(&fdoCtx->rirb.cmds[codecAddr], Count - TransferredCount); 56 | 57 | SklHdAudBusPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, "%s timeout (Count: %d, transferred %d)!\n", __func__, Count, TransferredCount); 58 | status = STATUS_IO_TIMEOUT; 59 | goto out; 60 | } 61 | 62 | LARGE_INTEGER Timeout; 63 | Timeout.QuadPart = -10 * 100; 64 | KeWaitForSingleObject(&fdoCtx->rirb.xferEvent[codecAddr], Executive, KernelMode, TRUE, &Timeout); 65 | } 66 | 67 | SklHdAudBusPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, "%s exit (Count: %d)!\n", __func__, Count); 68 | 69 | if (Callback) { //TODO: Do this async 70 | DbgPrint("Got Callback\n"); 71 | Callback(CodecTransfer, Context); 72 | } 73 | 74 | status = STATUS_SUCCESS; 75 | 76 | out: 77 | WdfDeviceResumeIdle(fdoCtx->WdfDevice); 78 | return status; 79 | } 80 | 81 | NTSTATUS HDA_AllocateCaptureDmaEngine( 82 | _In_ PVOID _context, 83 | _In_ UCHAR CodecAddress, 84 | _In_ PHDAUDIO_STREAM_FORMAT StreamFormat, 85 | _Out_ PHANDLE Handle, 86 | _Out_ PHDAUDIO_CONVERTER_FORMAT ConverterFormat 87 | ) { 88 | UNREFERENCED_PARAMETER(CodecAddress); 89 | 90 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 91 | return STATUS_UNSUCCESSFUL; 92 | } 93 | 94 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 95 | if (!devData->FdoContext) { 96 | return STATUS_NO_SUCH_DEVICE; 97 | } 98 | 99 | PFDO_CONTEXT fdoContext = devData->FdoContext; 100 | 101 | NTSTATUS status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 102 | if (!NT_SUCCESS(status)) { 103 | return status; 104 | } 105 | 106 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 107 | for (UINT32 i = 0; i < fdoContext->captureStreams; i++) { 108 | int tag = fdoContext->captureIndexOff + i; 109 | PHDAC_STREAM stream = &fdoContext->streams[tag]; 110 | if (stream->PdoContext != NULL) { 111 | continue; 112 | } 113 | 114 | stream->PdoContext = devData; 115 | stream->running = FALSE; 116 | stream->streamFormat = *StreamFormat; 117 | 118 | ConverterFormat->ConverterFormat = hdac_format(stream); 119 | 120 | if (Handle) 121 | *Handle = (HANDLE)stream; 122 | 123 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 124 | return STATUS_SUCCESS; 125 | } 126 | 127 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 128 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 129 | return STATUS_INSUFFICIENT_RESOURCES; 130 | } 131 | 132 | NTSTATUS HDA_AllocateRenderDmaEngine( 133 | _In_ PVOID _context, 134 | _In_ PHDAUDIO_STREAM_FORMAT StreamFormat, 135 | _In_ BOOLEAN Stripe, 136 | _Out_ PHANDLE Handle, 137 | _Out_ PHDAUDIO_CONVERTER_FORMAT ConverterFormat 138 | ) { 139 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 140 | return STATUS_UNSUCCESSFUL; 141 | } 142 | 143 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 144 | if (!devData->FdoContext) { 145 | return STATUS_NO_SUCH_DEVICE; 146 | } 147 | 148 | PFDO_CONTEXT fdoContext = devData->FdoContext; 149 | 150 | NTSTATUS status = WdfDeviceStopIdle(devData->FdoContext->WdfDevice, TRUE); 151 | if (!NT_SUCCESS(status)) { 152 | return status; 153 | } 154 | 155 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 156 | for (UINT32 i = 0; i < fdoContext->playbackStreams; i++) { 157 | int tag = fdoContext->playbackIndexOff + i; 158 | PHDAC_STREAM stream = &fdoContext->streams[tag]; 159 | if (stream->PdoContext != NULL) { 160 | continue; 161 | } 162 | 163 | stream->stripe = Stripe; 164 | stream->PdoContext = devData; 165 | stream->running = FALSE; 166 | stream->streamFormat = *StreamFormat; 167 | 168 | ConverterFormat->ConverterFormat = hdac_format(stream); 169 | 170 | if (Handle) 171 | *Handle = (HANDLE)stream; 172 | 173 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 174 | return STATUS_SUCCESS; 175 | } 176 | 177 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 178 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 179 | return STATUS_INSUFFICIENT_RESOURCES; 180 | } 181 | 182 | NTSTATUS HDA_ChangeBandwidthAllocation( 183 | _In_ PVOID _context, 184 | _In_ HANDLE Handle, 185 | _In_ PHDAUDIO_STREAM_FORMAT StreamFormat, 186 | _Out_ PHDAUDIO_CONVERTER_FORMAT ConverterFormat 187 | ) { 188 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 189 | return STATUS_UNSUCCESSFUL; 190 | } 191 | 192 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 193 | if (!devData->FdoContext) { 194 | return STATUS_NO_SUCH_DEVICE; 195 | } 196 | 197 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 198 | if (stream->PdoContext != devData) { 199 | return STATUS_INVALID_HANDLE; 200 | } 201 | 202 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 203 | 204 | if (stream->running) { 205 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 206 | return STATUS_INVALID_DEVICE_REQUEST; 207 | } 208 | 209 | stream->streamFormat = *StreamFormat; 210 | ConverterFormat->ConverterFormat = hdac_format(stream); 211 | 212 | hdac_stream_setup(stream); 213 | 214 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 215 | 216 | SklHdAudBusPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, "%s called!\n", __func__); 217 | 218 | return STATUS_SUCCESS; 219 | } 220 | 221 | NTSTATUS HDA_FreeDmaEngine( 222 | _In_ PVOID _context, 223 | _In_ HANDLE Handle 224 | ) { 225 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 226 | return STATUS_UNSUCCESSFUL; 227 | } 228 | 229 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 230 | if (!devData->FdoContext) { 231 | return STATUS_NO_SUCH_DEVICE; 232 | } 233 | 234 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 235 | if (stream->PdoContext != devData) { 236 | return STATUS_INVALID_HANDLE; 237 | } 238 | 239 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 240 | 241 | if (stream->running) { 242 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 243 | return STATUS_INVALID_DEVICE_REQUEST; 244 | } 245 | 246 | stream->PdoContext = NULL; 247 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 248 | 249 | WdfDeviceResumeIdle(devData->FdoContext->WdfDevice); 250 | 251 | return STATUS_SUCCESS; 252 | } 253 | 254 | NTSTATUS HDA_SetDmaEngineState( 255 | _In_ PVOID _context, 256 | _In_ HDAUDIO_STREAM_STATE StreamState, 257 | _In_ ULONG NumberOfHandles, 258 | _In_reads_(NumberOfHandles) PHANDLE Handles 259 | ) { 260 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 261 | if (!devData->FdoContext) { 262 | return STATUS_NO_SUCH_DEVICE; 263 | } 264 | 265 | for (ULONG i = 0; i < NumberOfHandles; i++) { 266 | PHDAC_STREAM stream = (PHDAC_STREAM)Handles[i]; 267 | if (stream->PdoContext != devData) { 268 | return STATUS_INVALID_HANDLE; 269 | } 270 | 271 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 272 | 273 | if (StreamState == RunState && !stream->running) { 274 | hdac_stream_start(stream); 275 | stream->running = TRUE; 276 | } 277 | else if ((StreamState == PauseState || StreamState == StopState) && stream->running) { 278 | hdac_stream_stop(stream); 279 | stream->running = FALSE; 280 | } 281 | else if (StreamState == ResetState) { 282 | if (!stream->running) { 283 | hdac_stream_reset(stream); 284 | } 285 | else { 286 | return STATUS_INVALID_PARAMETER; 287 | } 288 | } 289 | 290 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 291 | } 292 | 293 | return STATUS_SUCCESS; 294 | } 295 | 296 | VOID HDA_GetWallClockRegister( 297 | _In_ PVOID _context, 298 | _Out_ PULONG* Wallclock 299 | ) { 300 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 301 | if (!devData->FdoContext) { 302 | *Wallclock = NULL; 303 | return; 304 | } 305 | *Wallclock = (ULONG *)((devData->FdoContext)->m_BAR0.Base.baseptr + HDA_REG_WALLCLK); 306 | } 307 | 308 | NTSTATUS HDA_GetLinkPositionRegister( 309 | _In_ PVOID _context, 310 | _In_ HANDLE Handle, 311 | _Out_ PULONG* Position 312 | ) { 313 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 314 | if (!devData->FdoContext) { 315 | return STATUS_NO_SUCH_DEVICE; 316 | } 317 | 318 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 319 | if (stream->PdoContext != devData) { 320 | return STATUS_INVALID_HANDLE; 321 | } 322 | 323 | *Position = (ULONG *)stream->posbuf; 324 | 325 | return STATUS_SUCCESS; 326 | } 327 | 328 | NTSTATUS HDA_RegisterEventCallback( 329 | _In_ PVOID _context, 330 | _In_ PHDAUDIO_UNSOLICITED_RESPONSE_CALLBACK Routine, 331 | _In_opt_ PVOID Context, 332 | _Out_ PUCHAR Tag 333 | ) { 334 | if (!_context) 335 | return STATUS_NO_SUCH_DEVICE; 336 | 337 | 338 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 339 | if (devData->FdoContext) { 340 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 341 | } 342 | 343 | for (UINT8 i = 0; i < MAX_UNSOLICIT_CALLBACKS; i++) { 344 | if (devData->unsolitCallbacks[i].inUse) 345 | continue; 346 | 347 | if (Tag) 348 | *Tag = i; 349 | 350 | devData->unsolitCallbacks[i].inUse = TRUE; 351 | devData->unsolitCallbacks[i].Context = Context; 352 | devData->unsolitCallbacks[i].Routine = Routine; 353 | 354 | if (devData->FdoContext) { 355 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 356 | } 357 | return STATUS_SUCCESS; 358 | } 359 | 360 | if (devData->FdoContext) { 361 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 362 | } 363 | return STATUS_INSUFFICIENT_RESOURCES; 364 | } 365 | 366 | NTSTATUS HDA_UnregisterEventCallback( 367 | _In_ PVOID _context, 368 | _In_ UCHAR Tag 369 | ) { 370 | if (!_context) 371 | return STATUS_NO_SUCH_DEVICE; 372 | 373 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 374 | if (!devData->unsolitCallbacks[Tag].inUse) { 375 | return STATUS_NOT_FOUND; 376 | } 377 | 378 | if (devData->FdoContext) { 379 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 380 | } 381 | 382 | devData->unsolitCallbacks[Tag].Routine = NULL; 383 | devData->unsolitCallbacks[Tag].Context = NULL; 384 | devData->unsolitCallbacks[Tag].inUse = FALSE; 385 | 386 | if (devData->FdoContext) { 387 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 388 | } 389 | 390 | return STATUS_SUCCESS; 391 | } 392 | 393 | NTSTATUS HDA_GetDeviceInformation( 394 | _In_ PVOID _context, 395 | _Inout_ PHDAUDIO_DEVICE_INFORMATION DeviceInformation 396 | ) { 397 | if (!_context) 398 | return STATUS_NO_SUCH_DEVICE; 399 | 400 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 401 | if (!devData->FdoContext) { 402 | return STATUS_NO_SUCH_DEVICE; 403 | } 404 | 405 | if (DeviceInformation->Size >= sizeof(HDAUDIO_DEVICE_INFORMATION)) { 406 | DeviceInformation->CodecsDetected = devData->FdoContext->numCodecs; 407 | DeviceInformation->DeviceVersion = devData->FdoContext->hwVersion; 408 | DeviceInformation->DriverVersion = 0x100; 409 | DeviceInformation->IsStripingSupported = TRUE; 410 | } 411 | if (DeviceInformation->Size >= sizeof(HDAUDIO_DEVICE_INFORMATION_V2)) { 412 | PHDAUDIO_DEVICE_INFORMATION_V2 DeviceInformationV2 = (PHDAUDIO_DEVICE_INFORMATION_V2)DeviceInformation; 413 | DeviceInformationV2->CtrlRevision = devData->FdoContext->revId; 414 | DeviceInformationV2->CtrlVendorId = devData->FdoContext->venId; 415 | DeviceInformationV2->CtrlDeviceId = devData->FdoContext->devId; 416 | } 417 | 418 | return STATUS_SUCCESS; 419 | } 420 | 421 | void HDA_GetResourceInformation( 422 | _In_ PVOID _context, 423 | _Out_ PUCHAR CodecAddress, 424 | _Out_ PUCHAR FunctionGroupStartNode 425 | ) { 426 | if (!_context) 427 | return; 428 | 429 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 430 | if (CodecAddress) 431 | *CodecAddress = (UINT8)devData->CodecIds.CodecAddress; 432 | if (FunctionGroupStartNode) 433 | *FunctionGroupStartNode = devData->CodecIds.FunctionGroupStartNode; 434 | } 435 | 436 | NTSTATUS HDA_AllocateDmaBufferWithNotification( 437 | _In_ PVOID _context, 438 | _In_ HANDLE Handle, 439 | _In_ ULONG NotificationCount, 440 | _In_ SIZE_T RequestedBufferSize, 441 | _Out_ PMDL* BufferMdl, 442 | _Out_ PSIZE_T AllocatedBufferSize, 443 | _Out_ PSIZE_T OffsetFromFirstPage, 444 | _Out_ PUCHAR StreamId, 445 | _Out_ PULONG FifoSize 446 | ) { 447 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 448 | return STATUS_UNSUCCESSFUL; 449 | } 450 | 451 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 452 | if (!devData->FdoContext) { 453 | return STATUS_NO_SUCH_DEVICE; 454 | } 455 | 456 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 457 | if (stream->PdoContext != devData) { 458 | return STATUS_INVALID_HANDLE; 459 | } 460 | 461 | if (stream->running) { 462 | return STATUS_INVALID_DEVICE_REQUEST; 463 | } 464 | 465 | if (stream->mdlBuf) { 466 | return STATUS_INVALID_DEVICE_REQUEST; 467 | } 468 | 469 | PHYSICAL_ADDRESS zeroAddr; 470 | zeroAddr.QuadPart = 0; 471 | PHYSICAL_ADDRESS maxAddr; 472 | maxAddr.QuadPart = MAXUINT64; 473 | 474 | UINT32 allocSize = (UINT32)RequestedBufferSize; 475 | UINT32 allocOffset = 0; 476 | UINT32 halfSize = 0; 477 | if (NotificationCount == 2) { 478 | halfSize = (UINT32)RequestedBufferSize / 2; 479 | allocOffset = PAGE_SIZE - (halfSize % PAGE_SIZE); 480 | allocSize = (UINT32)RequestedBufferSize + allocOffset; 481 | } 482 | 483 | PMDL mdl = MmAllocatePagesForMdl(zeroAddr, maxAddr, zeroAddr, allocSize); 484 | if (!mdl) { 485 | return STATUS_NO_MEMORY; 486 | } 487 | 488 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 489 | stream->mdlBuf = mdl; 490 | stream->bufSz = (UINT32)RequestedBufferSize; 491 | 492 | *BufferMdl = mdl; 493 | *AllocatedBufferSize = RequestedBufferSize; 494 | *OffsetFromFirstPage = allocOffset; 495 | *StreamId = stream->streamTag; 496 | 497 | { 498 | UINT16 numBlocks = 0; 499 | UINT16 pageNum = 0; 500 | 501 | //Set up the BDL 502 | PHDAC_BDLENTRY bdl = stream->bdl; 503 | UINT32 size = (UINT32)RequestedBufferSize; 504 | 505 | PPFN_NUMBER pfnArray = MmGetMdlPfnArray(mdl); 506 | UINT32 offset = allocOffset; 507 | while (halfSize > 0) { 508 | if (numBlocks > HDA_MAX_BDL_ENTRIES) { 509 | DbgPrint("Too many BDL entries!\n"); 510 | numBlocks = HDA_MAX_BDL_ENTRIES; 511 | break; 512 | } 513 | 514 | UINT32 pageOff = offset % PAGE_SIZE; 515 | UINT32 chunk = (pageOff == 0) ? PAGE_SIZE : (PAGE_SIZE - pageOff); 516 | if (halfSize < chunk) 517 | chunk = halfSize; 518 | 519 | PFN_NUMBER pfn = pfnArray[pageNum]; 520 | PHYSICAL_ADDRESS addr = { 0 }; 521 | addr.QuadPart = pfn << PAGE_SHIFT; 522 | 523 | bdl->lowAddr = addr.LowPart + pageOff; 524 | bdl->highAddr = addr.HighPart; 525 | bdl->len = chunk; 526 | 527 | halfSize -= chunk; 528 | size -= chunk; 529 | 530 | //Program interrupt for when buffer is halfway 531 | bdl->ioc = (halfSize > 0) ? 0 : 1; 532 | bdl++; 533 | numBlocks++; 534 | offset += chunk; 535 | if ((offset % PAGE_SIZE) == 0) 536 | pageNum++; //Only increment page num if we go past page boundary 537 | } 538 | 539 | while (size > 0) { 540 | if (numBlocks > HDA_MAX_BDL_ENTRIES) { 541 | DbgPrint("Too many BDL entries!\n"); 542 | numBlocks = HDA_MAX_BDL_ENTRIES; 543 | break; 544 | } 545 | 546 | UINT32 pageOff = offset % PAGE_SIZE; 547 | UINT32 chunk = (pageOff == 0) ? PAGE_SIZE : (PAGE_SIZE - pageOff); 548 | if (size < chunk) 549 | chunk = size; 550 | 551 | PFN_NUMBER pfn = pfnArray[pageNum]; 552 | PHYSICAL_ADDRESS addr = { 0 }; 553 | addr.QuadPart = pfn << PAGE_SHIFT; 554 | bdl->lowAddr = addr.LowPart + pageOff; 555 | bdl->highAddr = addr.HighPart; 556 | bdl->len = chunk; 557 | 558 | size -= chunk; 559 | //Program interrupt for when buffer ends 560 | bdl->ioc = (size > 0) ? 0 : 1; 561 | bdl++; 562 | numBlocks++; 563 | offset += chunk; 564 | if ((offset % PAGE_SIZE) == 0) 565 | pageNum++; //Only increment page num if we go past page boundary 566 | } 567 | stream->numBlocks = numBlocks; 568 | } 569 | 570 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 571 | 572 | hdac_stream_reset(stream); 573 | hdac_stream_setup(stream); 574 | 575 | *FifoSize = stream->fifoSize; 576 | return STATUS_SUCCESS; 577 | } 578 | 579 | NTSTATUS HDA_FreeDmaBufferWithNotification( 580 | _In_ PVOID _context, 581 | _In_ HANDLE Handle, 582 | _In_ PMDL BufferMdl, 583 | _In_ SIZE_T BufferSize 584 | ) { 585 | UNREFERENCED_PARAMETER(BufferMdl); 586 | UNREFERENCED_PARAMETER(BufferSize); 587 | 588 | if (KeGetCurrentIrql() > PASSIVE_LEVEL) { 589 | return STATUS_UNSUCCESSFUL; 590 | } 591 | 592 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 593 | if (!devData->FdoContext) { 594 | return STATUS_NO_SUCH_DEVICE; 595 | } 596 | 597 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 598 | if (stream->PdoContext != devData) { 599 | return STATUS_INVALID_HANDLE; 600 | } 601 | 602 | if (stream->running) { 603 | return STATUS_INVALID_DEVICE_REQUEST; 604 | } 605 | 606 | if (!stream->mdlBuf) { 607 | return STATUS_INVALID_DEVICE_REQUEST; 608 | } 609 | 610 | WdfInterruptAcquireLock(devData->FdoContext->Interrupt); 611 | 612 | stream_write32(stream, SD_BDLPL, 0); 613 | stream_write32(stream, SD_BDLPU, 0); 614 | stream_write32(stream, SD_CTL, 0); 615 | 616 | PMDL mdl = stream->mdlBuf; 617 | stream->mdlBuf = NULL; 618 | 619 | WdfInterruptReleaseLock(devData->FdoContext->Interrupt); 620 | 621 | MmFreePagesFromMdl(mdl); 622 | ExFreePool(mdl); 623 | 624 | return STATUS_SUCCESS; 625 | } 626 | 627 | NTSTATUS HDA_AllocateDmaBuffer( 628 | _In_ PVOID _context, 629 | _In_ HANDLE Handle, 630 | _In_ SIZE_T RequestedBufferSize, 631 | _Out_ PMDL* BufferMdl, 632 | _Out_ PSIZE_T AllocatedBufferSize, 633 | _Out_ PUCHAR StreamId, 634 | _Out_ PULONG FifoSize 635 | ) { 636 | SIZE_T OffsetFromFirstPage; 637 | return HDA_AllocateDmaBufferWithNotification(_context, Handle, 1, RequestedBufferSize, BufferMdl, AllocatedBufferSize, &OffsetFromFirstPage, StreamId, FifoSize); 638 | } 639 | 640 | NTSTATUS HDA_FreeDmaBuffer( 641 | _In_ PVOID _context, 642 | _In_ HANDLE Handle 643 | ) { 644 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 645 | if (!devData->FdoContext) { 646 | return STATUS_NO_SUCH_DEVICE; 647 | } 648 | 649 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 650 | if (stream->PdoContext != devData) { 651 | return STATUS_INVALID_HANDLE; 652 | } 653 | 654 | return HDA_FreeDmaBufferWithNotification(_context, Handle, stream->mdlBuf, stream->bufSz); 655 | } 656 | 657 | NTSTATUS HDA_RegisterNotificationEvent( 658 | _In_ PVOID _context, 659 | _In_ HANDLE Handle, 660 | _In_ PKEVENT NotificationEvent 661 | ) { 662 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 663 | if (!devData->FdoContext) { 664 | return STATUS_NO_SUCH_DEVICE; 665 | } 666 | 667 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 668 | if (stream->PdoContext != devData) { 669 | return STATUS_INVALID_HANDLE; 670 | } 671 | 672 | BOOL registered = FALSE; 673 | 674 | for (int i = 0; i < MAX_NOTIF_EVENTS; i++) { 675 | if (stream->registeredEvents[i]) 676 | continue; 677 | stream->registeredEvents[i] = NotificationEvent; 678 | registered = true; 679 | break; 680 | } 681 | 682 | return registered ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 683 | } 684 | 685 | NTSTATUS HDA_UnregisterNotificationEvent( 686 | _In_ PVOID _context, 687 | _In_ HANDLE Handle, 688 | _In_ PKEVENT NotificationEvent 689 | ) { 690 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 691 | if (!devData->FdoContext) { 692 | return STATUS_NO_SUCH_DEVICE; 693 | } 694 | 695 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 696 | if (stream->PdoContext != devData) { 697 | return STATUS_INVALID_HANDLE; 698 | } 699 | 700 | BOOL registered = FALSE; 701 | 702 | for (int i = 0; i < MAX_NOTIF_EVENTS; i++) { 703 | if (stream->registeredEvents[i] != NotificationEvent) 704 | continue; 705 | stream->registeredEvents[i] = NULL; 706 | registered = true; 707 | break; 708 | } 709 | 710 | return registered ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER; 711 | } 712 | 713 | NTSTATUS HDA_RegisterNotificationCallback( 714 | _In_ PVOID _context, 715 | _In_ HANDLE Handle, 716 | PDEVICE_OBJECT Fdo, 717 | PHDAUDIO_DMA_NOTIFICATION_CALLBACK NotificationCallback, 718 | PVOID CallbackContext 719 | ) { 720 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 721 | if (!devData->FdoContext) { 722 | return STATUS_NO_SUCH_DEVICE; 723 | } 724 | 725 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 726 | if (stream->PdoContext != devData) { 727 | return STATUS_INVALID_HANDLE; 728 | } 729 | 730 | BOOL registered = FALSE; 731 | 732 | for (int i = 0; i < MAX_NOTIF_EVENTS; i++) { 733 | if (stream->registeredCallbacks[i].InUse) 734 | continue; 735 | stream->registeredCallbacks[i].InUse = TRUE; 736 | stream->registeredCallbacks[i].Fdo = Fdo; 737 | stream->registeredCallbacks[i].NotificationCallback = NotificationCallback; 738 | stream->registeredCallbacks[i].CallbackContext = CallbackContext; 739 | 740 | InterlockedIncrement(&Fdo->ReferenceCount); 741 | 742 | registered = true; 743 | break; 744 | } 745 | 746 | return registered ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 747 | } 748 | 749 | NTSTATUS HDA_UnregisterNotificationCallback( 750 | _In_ PVOID _context, 751 | _In_ HANDLE Handle, 752 | PHDAUDIO_DMA_NOTIFICATION_CALLBACK NotificationCallback, 753 | PVOID CallbackContext 754 | ) { 755 | PPDO_DEVICE_DATA devData = (PPDO_DEVICE_DATA)_context; 756 | if (!devData->FdoContext) { 757 | return STATUS_NO_SUCH_DEVICE; 758 | } 759 | 760 | PHDAC_STREAM stream = (PHDAC_STREAM)Handle; 761 | if (stream->PdoContext != devData) { 762 | return STATUS_INVALID_HANDLE; 763 | } 764 | 765 | BOOL registered = FALSE; 766 | 767 | for (int i = 0; i < MAX_NOTIF_EVENTS; i++) { 768 | if (stream->registeredCallbacks[i].InUse && 769 | stream->registeredCallbacks[i].NotificationCallback != NotificationCallback && 770 | stream->registeredCallbacks[i].CallbackContext != CallbackContext) 771 | continue; 772 | 773 | InterlockedDecrement(&stream->registeredCallbacks[i].Fdo->ReferenceCount); 774 | 775 | RtlZeroMemory(&stream->registeredCallbacks[i], sizeof(stream->registeredCallbacks[i])); 776 | registered = true; 777 | break; 778 | } 779 | 780 | return registered ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER; 781 | } 782 | 783 | HDAUDIO_BUS_INTERFACE_V2 HDA_BusInterfaceV2(PVOID Context) { 784 | HDAUDIO_BUS_INTERFACE_V2 busInterface; 785 | RtlZeroMemory(&busInterface, sizeof(HDAUDIO_BUS_INTERFACE_V2)); 786 | 787 | busInterface.Size = sizeof(HDAUDIO_BUS_INTERFACE_V2); 788 | busInterface.Version = 0x0100; 789 | busInterface.Context = Context; 790 | busInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; 791 | busInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; 792 | busInterface.TransferCodecVerbs = HDA_TransferCodecVerbs; 793 | busInterface.AllocateCaptureDmaEngine = HDA_AllocateCaptureDmaEngine; 794 | busInterface.AllocateRenderDmaEngine = HDA_AllocateRenderDmaEngine; 795 | busInterface.ChangeBandwidthAllocation = HDA_ChangeBandwidthAllocation; 796 | busInterface.AllocateDmaBuffer = HDA_AllocateDmaBuffer; 797 | busInterface.FreeDmaBuffer = HDA_FreeDmaBuffer; 798 | busInterface.FreeDmaEngine = HDA_FreeDmaEngine; 799 | busInterface.SetDmaEngineState = HDA_SetDmaEngineState; 800 | busInterface.GetWallClockRegister = HDA_GetWallClockRegister; 801 | busInterface.GetLinkPositionRegister = HDA_GetLinkPositionRegister; 802 | busInterface.RegisterEventCallback = HDA_RegisterEventCallback; 803 | busInterface.UnregisterEventCallback = HDA_UnregisterEventCallback; 804 | busInterface.GetDeviceInformation = HDA_GetDeviceInformation; 805 | busInterface.GetResourceInformation = HDA_GetResourceInformation; 806 | busInterface.AllocateDmaBufferWithNotification = HDA_AllocateDmaBufferWithNotification; 807 | busInterface.FreeDmaBufferWithNotification = HDA_FreeDmaBufferWithNotification; 808 | busInterface.RegisterNotificationEvent = HDA_RegisterNotificationEvent; 809 | busInterface.UnregisterNotificationEvent = HDA_UnregisterNotificationEvent; 810 | 811 | return busInterface; 812 | } 813 | 814 | HDAUDIO_BUS_INTERFACE_V3 HDA_BusInterfaceV3(PVOID Context) { 815 | HDAUDIO_BUS_INTERFACE_V3 busInterface; 816 | RtlZeroMemory(&busInterface, sizeof(HDAUDIO_BUS_INTERFACE_V3)); 817 | 818 | busInterface.Size = sizeof(HDAUDIO_BUS_INTERFACE_V3); 819 | busInterface.Version = 0x0100; 820 | busInterface.Context = Context; 821 | busInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; 822 | busInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; 823 | busInterface.TransferCodecVerbs = HDA_TransferCodecVerbs; 824 | busInterface.AllocateCaptureDmaEngine = HDA_AllocateCaptureDmaEngine; 825 | busInterface.AllocateRenderDmaEngine = HDA_AllocateRenderDmaEngine; 826 | busInterface.ChangeBandwidthAllocation = HDA_ChangeBandwidthAllocation; 827 | busInterface.AllocateDmaBuffer = HDA_AllocateDmaBuffer; 828 | busInterface.FreeDmaBuffer = HDA_FreeDmaBuffer; 829 | busInterface.FreeDmaEngine = HDA_FreeDmaEngine; 830 | busInterface.SetDmaEngineState = HDA_SetDmaEngineState; 831 | busInterface.GetWallClockRegister = HDA_GetWallClockRegister; 832 | busInterface.GetLinkPositionRegister = HDA_GetLinkPositionRegister; 833 | busInterface.RegisterEventCallback = HDA_RegisterEventCallback; 834 | busInterface.UnregisterEventCallback = HDA_UnregisterEventCallback; 835 | busInterface.GetDeviceInformation = HDA_GetDeviceInformation; 836 | busInterface.GetResourceInformation = HDA_GetResourceInformation; 837 | busInterface.AllocateDmaBufferWithNotification = HDA_AllocateDmaBufferWithNotification; 838 | busInterface.FreeDmaBufferWithNotification = HDA_FreeDmaBufferWithNotification; 839 | busInterface.RegisterNotificationEvent = HDA_RegisterNotificationEvent; 840 | busInterface.UnregisterNotificationEvent = HDA_UnregisterNotificationEvent; 841 | busInterface.RegisterNotificationCallback = HDA_RegisterNotificationCallback; 842 | busInterface.UnregisterNotificationCallback = HDA_UnregisterNotificationCallback; 843 | 844 | return busInterface; 845 | } 846 | 847 | HDAUDIO_BUS_INTERFACE HDA_BusInterface(PVOID Context) { 848 | HDAUDIO_BUS_INTERFACE busInterface; 849 | RtlZeroMemory(&busInterface, sizeof(HDAUDIO_BUS_INTERFACE)); 850 | 851 | busInterface.Size = sizeof(HDAUDIO_BUS_INTERFACE); 852 | busInterface.Version = 0x0100; 853 | busInterface.Context = Context; 854 | busInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; 855 | busInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; 856 | busInterface.TransferCodecVerbs = HDA_TransferCodecVerbs; 857 | busInterface.AllocateCaptureDmaEngine = HDA_AllocateCaptureDmaEngine; 858 | busInterface.AllocateRenderDmaEngine = HDA_AllocateRenderDmaEngine; 859 | busInterface.ChangeBandwidthAllocation = HDA_ChangeBandwidthAllocation; 860 | busInterface.AllocateDmaBuffer = HDA_AllocateDmaBuffer; 861 | busInterface.FreeDmaBuffer = HDA_FreeDmaBuffer; 862 | busInterface.FreeDmaEngine = HDA_FreeDmaEngine; 863 | busInterface.SetDmaEngineState = HDA_SetDmaEngineState; 864 | busInterface.GetWallClockRegister = HDA_GetWallClockRegister; 865 | busInterface.GetLinkPositionRegister = HDA_GetLinkPositionRegister; 866 | busInterface.RegisterEventCallback = HDA_RegisterEventCallback; 867 | busInterface.UnregisterEventCallback = HDA_UnregisterEventCallback; 868 | busInterface.GetDeviceInformation = HDA_GetDeviceInformation; 869 | busInterface.GetResourceInformation = HDA_GetResourceInformation; 870 | 871 | return busInterface; 872 | } -------------------------------------------------------------------------------- /sklhdaudbus/fdo.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "nhlt.h" 3 | #include "sof-tplg.h" 4 | 5 | EVT_WDF_DEVICE_PREPARE_HARDWARE Fdo_EvtDevicePrepareHardware; 6 | EVT_WDF_DEVICE_RELEASE_HARDWARE Fdo_EvtDeviceReleaseHardware; 7 | EVT_WDF_DEVICE_D0_ENTRY Fdo_EvtDeviceD0Entry; 8 | EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED Fdo_EvtDeviceD0EntryPostInterrupts; 9 | EVT_WDF_DEVICE_D0_EXIT Fdo_EvtDeviceD0Exit; 10 | EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT Fdo_EvtDeviceSelfManagedIoInit; 11 | 12 | void CheckHDAGraphicsRegistryKeys(PFDO_CONTEXT fdoCtx); 13 | 14 | NTSTATUS 15 | HDAGraphicsPowerInterfaceCallback( 16 | PVOID NotificationStruct, 17 | PVOID Context 18 | ); 19 | 20 | NTSTATUS 21 | Fdo_Initialize( 22 | _In_ PFDO_CONTEXT FdoCtx 23 | ); 24 | 25 | NTSTATUS 26 | Fdo_Create( 27 | _Inout_ PWDFDEVICE_INIT DeviceInit 28 | ) 29 | { 30 | WDF_CHILD_LIST_CONFIG config; 31 | WDF_OBJECT_ATTRIBUTES attributes; 32 | WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; 33 | PFDO_CONTEXT fdoCtx; 34 | WDFDEVICE wdfDevice; 35 | NTSTATUS status; 36 | 37 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 38 | "%s\n", __func__); 39 | 40 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); 41 | pnpPowerCallbacks.EvtDevicePrepareHardware = Fdo_EvtDevicePrepareHardware; 42 | pnpPowerCallbacks.EvtDeviceReleaseHardware = Fdo_EvtDeviceReleaseHardware; 43 | pnpPowerCallbacks.EvtDeviceD0Entry = Fdo_EvtDeviceD0Entry; 44 | pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = Fdo_EvtDeviceD0EntryPostInterrupts; 45 | pnpPowerCallbacks.EvtDeviceD0Exit = Fdo_EvtDeviceD0Exit; 46 | pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = Fdo_EvtDeviceSelfManagedIoInit; 47 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); 48 | 49 | // 50 | // WDF_ DEVICE_LIST_CONFIG describes how the framework should handle 51 | // dynamic child enumeration on behalf of the driver writer. 52 | // Since we are a bus driver, we need to specify identification description 53 | // for our child devices. This description will serve as the identity of our 54 | // child device. Since the description is opaque to the framework, we 55 | // have to provide bunch of callbacks to compare, copy, or free 56 | // any other resources associated with the description. 57 | // 58 | WDF_CHILD_LIST_CONFIG_INIT(&config, 59 | sizeof(PDO_IDENTIFICATION_DESCRIPTION), 60 | Bus_EvtDeviceListCreatePdo // callback to create a child device. 61 | ); 62 | 63 | // 64 | // This function pointer will be called when the framework needs to copy a 65 | // identification description from one location to another. An implementation 66 | // of this function is only necessary if the description contains description 67 | // relative pointer values (like LIST_ENTRY for instance) . 68 | // If set to NULL, the framework will use RtlCopyMemory to copy an identification . 69 | // description. In this sample, it's not required to provide these callbacks. 70 | // they are added just for illustration. 71 | // 72 | config.EvtChildListIdentificationDescriptionDuplicate = 73 | Bus_EvtChildListIdentificationDescriptionDuplicate; 74 | 75 | // 76 | // This function pointer will be called when the framework needs to compare 77 | // two identificaiton descriptions. If left NULL a call to RtlCompareMemory 78 | // will be used to compare two identificaiton descriptions. 79 | // 80 | config.EvtChildListIdentificationDescriptionCompare = 81 | Bus_EvtChildListIdentificationDescriptionCompare; 82 | // 83 | // This function pointer will be called when the framework needs to free a 84 | // identification description. An implementation of this function is only 85 | // necessary if the description contains dynamically allocated memory 86 | // (by the driver writer) that needs to be freed. The actual identification 87 | // description pointer itself will be freed by the framework. 88 | // 89 | config.EvtChildListIdentificationDescriptionCleanup = 90 | Bus_EvtChildListIdentificationDescriptionCleanup; 91 | 92 | // 93 | // Tell the framework to use the built-in childlist to track the state 94 | // of the device based on the configuration we just created. 95 | // 96 | WdfFdoInitSetDefaultChildListConfig(DeviceInit, 97 | &config, 98 | WDF_NO_OBJECT_ATTRIBUTES); 99 | 100 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_CONTEXT); 101 | status = WdfDeviceCreate(&DeviceInit, &attributes, &wdfDevice); 102 | if (!NT_SUCCESS(status)) { 103 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 104 | "WdfDriverCreate failed %x\n", status); 105 | goto Exit; 106 | } 107 | 108 | { 109 | WDF_DEVICE_STATE deviceState; 110 | WDF_DEVICE_STATE_INIT(&deviceState); 111 | 112 | deviceState.NotDisableable = WdfFalse; 113 | WdfDeviceSetDeviceState(wdfDevice, &deviceState); 114 | } 115 | 116 | fdoCtx = Fdo_GetContext(wdfDevice); 117 | fdoCtx->WdfDevice = wdfDevice; 118 | 119 | status = Fdo_Initialize(fdoCtx); 120 | if (!NT_SUCCESS(status)) 121 | { 122 | goto Exit; 123 | } 124 | 125 | CheckHDAGraphicsRegistryKeys(fdoCtx); 126 | 127 | Exit: 128 | return status; 129 | } 130 | 131 | NTSTATUS 132 | Fdo_Initialize( 133 | _In_ PFDO_CONTEXT FdoCtx 134 | ) 135 | { 136 | NTSTATUS status; 137 | WDFDEVICE device; 138 | WDF_INTERRUPT_CONFIG interruptConfig; 139 | 140 | device = FdoCtx->WdfDevice; 141 | 142 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 143 | "%s\n", __func__); 144 | 145 | // 146 | // Create an interrupt object for hardware notifications 147 | // 148 | WDF_INTERRUPT_CONFIG_INIT( 149 | &interruptConfig, 150 | hda_interrupt, 151 | hda_dpc); 152 | 153 | status = WdfInterruptCreate( 154 | device, 155 | &interruptConfig, 156 | WDF_NO_OBJECT_ATTRIBUTES, 157 | &FdoCtx->Interrupt); 158 | 159 | if (!NT_SUCCESS(status)) 160 | { 161 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 162 | "Error creating WDF interrupt object - %!STATUS!", 163 | status); 164 | 165 | return status; 166 | } 167 | 168 | 169 | status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &FdoCtx->GraphicsDevicesCollectionWaitLock); 170 | if (!NT_SUCCESS(status)) 171 | { 172 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 173 | "Error creating WDF wait lock - %!STATUS!", 174 | status); 175 | 176 | return status; 177 | } 178 | 179 | status = WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &FdoCtx->GraphicsDevicesCollection); 180 | 181 | if (!NT_SUCCESS(status)) 182 | { 183 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 184 | "Error creating WDF collection - %!STATUS!", 185 | status); 186 | 187 | return status; 188 | } 189 | 190 | return STATUS_SUCCESS; 191 | } 192 | 193 | NTSTATUS 194 | Fdo_EvtDevicePrepareHardware( 195 | _In_ WDFDEVICE Device, 196 | _In_ WDFCMRESLIST ResourcesRaw, 197 | _In_ WDFCMRESLIST ResourcesTranslated 198 | ) 199 | { 200 | UNREFERENCED_PARAMETER(ResourcesRaw); 201 | 202 | BOOLEAN fBar0Found = FALSE; 203 | BOOLEAN fBar4Found = FALSE; 204 | NTSTATUS status; 205 | PFDO_CONTEXT fdoCtx; 206 | ULONG resourceCount; 207 | 208 | fdoCtx = Fdo_GetContext(Device); 209 | resourceCount = WdfCmResourceListGetCount(ResourcesTranslated); 210 | 211 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 212 | "%s\n", __func__); 213 | 214 | status = WdfFdoQueryForInterface(Device, &GUID_BUS_INTERFACE_STANDARD, (PINTERFACE)&fdoCtx->BusInterface, sizeof(BUS_INTERFACE_STANDARD), 1, NULL); 215 | if (!NT_SUCCESS(status)) { 216 | return status; 217 | } 218 | 219 | for (ULONG i = 0; i < resourceCount; i++) 220 | { 221 | PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 222 | 223 | pDescriptor = WdfCmResourceListGetDescriptor( 224 | ResourcesTranslated, i); 225 | 226 | switch (pDescriptor->Type) 227 | { 228 | case CmResourceTypeMemory: 229 | //Look for BAR0 and BAR4 230 | if (fBar0Found == FALSE) { 231 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 232 | "Found BAR0: 0x%llx (size 0x%lx)\n", pDescriptor->u.Memory.Start.QuadPart, pDescriptor->u.Memory.Length); 233 | 234 | fdoCtx->m_BAR0.Base.Base = MmMapIoSpace(pDescriptor->u.Memory.Start, pDescriptor->u.Memory.Length, MmNonCached); 235 | fdoCtx->m_BAR0.Len = pDescriptor->u.Memory.Length; 236 | 237 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 238 | "Mapped to %p\n", fdoCtx->m_BAR0.Base.baseptr); 239 | fBar0Found = TRUE; 240 | } 241 | else if (fBar4Found == FALSE) { 242 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 243 | "Found BAR4: 0x%llx (size 0x%lx)\n", pDescriptor->u.Memory.Start.QuadPart, pDescriptor->u.Memory.Length); 244 | 245 | fdoCtx->m_BAR4.Base.Base = MmMapIoSpace(pDescriptor->u.Memory.Start, pDescriptor->u.Memory.Length, MmNonCached); 246 | fdoCtx->m_BAR4.Len = pDescriptor->u.Memory.Length; 247 | 248 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 249 | "Mapped to %p\n", fdoCtx->m_BAR4.Base.baseptr); 250 | fBar4Found = TRUE; 251 | } 252 | break; 253 | } 254 | } 255 | 256 | if (fdoCtx->m_BAR0.Base.Base == NULL) { 257 | status = STATUS_NOT_FOUND; //BAR0 is required 258 | return status; 259 | } 260 | 261 | fdoCtx->BusInterface.GetBusData(fdoCtx->BusInterface.Context, PCI_WHICHSPACE_CONFIG, &fdoCtx->venId, 0, sizeof(UINT16)); 262 | fdoCtx->BusInterface.GetBusData(fdoCtx->BusInterface.Context, PCI_WHICHSPACE_CONFIG, &fdoCtx->devId, 2, sizeof(UINT16)); 263 | fdoCtx->BusInterface.GetBusData(fdoCtx->BusInterface.Context, PCI_WHICHSPACE_CONFIG, &fdoCtx->revId, 1, sizeof(UINT8)); 264 | 265 | //mlcap & lctl (hda_intel_init_chip) 266 | if (fdoCtx->venId == VEN_INTEL) { 267 | //read bus capabilities 268 | 269 | unsigned int cur_cap; 270 | unsigned int offset; 271 | unsigned int counter = 0; 272 | 273 | offset = hda_read16(fdoCtx, LLCH); 274 | 275 | #define HDAC_MAX_CAPS 10 276 | 277 | /* Lets walk the linked capabilities list */ 278 | do { 279 | cur_cap = read32(fdoCtx->m_BAR0.Base.baseptr + offset); 280 | 281 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 282 | "Capability version: 0x%x\n", 283 | (cur_cap & HDA_CAP_HDR_VER_MASK) >> HDA_CAP_HDR_VER_OFF); 284 | 285 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 286 | "HDA capability ID: 0x%x\n", 287 | (cur_cap & HDA_CAP_HDR_ID_MASK) >> HDA_CAP_HDR_ID_OFF); 288 | 289 | if (cur_cap == -1) { 290 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 291 | "Invalid capability reg read\n"); 292 | break; 293 | } 294 | 295 | switch ((cur_cap & HDA_CAP_HDR_ID_MASK) >> HDA_CAP_HDR_ID_OFF) { 296 | case HDA_ML_CAP_ID: 297 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 298 | "Found ML capability\n"); 299 | fdoCtx->mlcap = fdoCtx->m_BAR0.Base.baseptr + offset; 300 | break; 301 | 302 | case HDA_GTS_CAP_ID: 303 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 304 | "Found GTS capability offset=%x\n", offset); 305 | break; 306 | 307 | case HDA_PP_CAP_ID: 308 | /* PP capability found, the Audio DSP is present */ 309 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 310 | "Found PP capability offset=%x\n", offset); 311 | fdoCtx->ppcap = fdoCtx->m_BAR0.Base.baseptr + offset; 312 | break; 313 | 314 | case HDA_SPB_CAP_ID: 315 | /* SPIB capability found, handler function */ 316 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 317 | "Found SPB capability\n"); 318 | fdoCtx->spbcap = fdoCtx->m_BAR0.Base.baseptr + offset; 319 | break; 320 | 321 | case HDA_DRSM_CAP_ID: 322 | /* DMA resume capability found, handler function */ 323 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 324 | "Found DRSM capability\n"); 325 | break; 326 | 327 | default: 328 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Unknown capability %d\n", cur_cap); 329 | cur_cap = 0; 330 | break; 331 | } 332 | 333 | counter++; 334 | 335 | if (counter > HDAC_MAX_CAPS) { 336 | SklHdAudBusPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "We exceeded HDAC capabilities!!!\n"); 337 | break; 338 | } 339 | 340 | /* read the offset of next capability */ 341 | offset = cur_cap & HDA_CAP_HDR_NXT_PTR_MASK; 342 | 343 | } while (offset); 344 | } 345 | 346 | status = GetHDACapabilities(fdoCtx); 347 | if (!NT_SUCCESS(status)) { 348 | return status; 349 | } 350 | 351 | fdoCtx->streams = (PHDAC_STREAM)ExAllocatePoolZero(NonPagedPool, sizeof(HDAC_STREAM) * fdoCtx->numStreams, SKLHDAUDBUS_POOL_TAG); 352 | if (!fdoCtx->streams) { 353 | return STATUS_NO_MEMORY; 354 | } 355 | RtlZeroMemory(fdoCtx->streams, sizeof(HDAC_STREAM) * fdoCtx->numStreams); 356 | 357 | PHYSICAL_ADDRESS maxAddr; 358 | maxAddr.QuadPart = MAXULONG64; 359 | 360 | fdoCtx->posbuf = MmAllocateContiguousMemory(PAGE_SIZE, maxAddr); 361 | RtlZeroMemory(fdoCtx->posbuf, PAGE_SIZE); 362 | if (!fdoCtx->posbuf) { 363 | return STATUS_NO_MEMORY; 364 | } 365 | 366 | fdoCtx->rb = (UINT8 *)MmAllocateContiguousMemory(PAGE_SIZE, maxAddr); 367 | if (!fdoCtx->rb) { 368 | return STATUS_NO_MEMORY; 369 | } 370 | 371 | RtlZeroMemory(fdoCtx->rb, PAGE_SIZE); 372 | 373 | //Init Streams 374 | { 375 | UINT8 i; 376 | UINT8 streamTags[2] = { 0, 0 }; 377 | 378 | for (i = 0; i < fdoCtx->numStreams; i++) { 379 | int isCapture = (i >= fdoCtx->captureIndexOff && 380 | i < fdoCtx->captureIndexOff + fdoCtx->captureStreams); 381 | /* stream tag must be unique throughout 382 | * the stream direction group, 383 | * valid values 1...15 384 | * use separate stream tag 385 | */ 386 | UINT8 tag = ++streamTags[isCapture]; 387 | 388 | { 389 | UINT64 idx = i; 390 | 391 | PHDAC_STREAM stream = &fdoCtx->streams[i]; 392 | stream->FdoContext = fdoCtx; 393 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ 394 | stream->sdAddr = fdoCtx->m_BAR0.Base.baseptr + (0x20 * idx + 0x80); 395 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ 396 | stream->int_sta_mask = 1 << i; 397 | stream->idx = i; 398 | if (fdoCtx->venId == VEN_INTEL) 399 | stream->streamTag = tag; 400 | else 401 | stream->streamTag = i + 1; 402 | 403 | stream->posbuf = (UINT32 *)(((UINT8 *)fdoCtx->posbuf) + (idx * 8)); 404 | 405 | stream->spib_addr = NULL; 406 | if (fdoCtx->spbcap) { 407 | stream->spib_addr = fdoCtx->spbcap + HDA_SPB_BASE + (HDA_SPB_INTERVAL * idx) + HDA_SPB_SPIB; 408 | } 409 | 410 | stream->bdl = (PHDAC_BDLENTRY)MmAllocateContiguousMemory(BDL_SIZE, maxAddr); 411 | } 412 | 413 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 414 | "Stream tag (idx %d): %d\n", i, tag); 415 | } 416 | } 417 | 418 | fdoCtx->nhlt = NULL; 419 | fdoCtx->nhltSz = 0; 420 | 421 | { //Check NHLT for Intel SST 422 | NTSTATUS status2 = NHLTCheckSupported(Device); 423 | if (NT_SUCCESS(status2)) { 424 | UINT64 nhltAddr; 425 | UINT64 nhltSz; 426 | 427 | status2 = NHLTQueryTableAddress(Device, &nhltAddr, &nhltSz); 428 | 429 | if (NT_SUCCESS(status2)) { 430 | PHYSICAL_ADDRESS nhltBaseAddr; 431 | nhltBaseAddr.QuadPart = nhltAddr; 432 | 433 | if (nhltAddr != 0 && nhltSz != 0) { 434 | fdoCtx->nhlt = MmMapIoSpace(nhltBaseAddr, nhltSz, MmCached); 435 | fdoCtx->nhltSz = nhltSz; 436 | } 437 | } 438 | } 439 | } 440 | 441 | fdoCtx->sofTplg = NULL; 442 | fdoCtx->sofTplgSz = 0; 443 | 444 | { //Check topology for Intel SOF 445 | SOF_TPLG sofTplg = { 0 }; 446 | NTSTATUS status2 = GetSOFTplg(Device, &sofTplg); 447 | if (NT_SUCCESS(status2) && sofTplg.magic == SOFTPLG_MAGIC) { 448 | fdoCtx->sofTplg = ExAllocatePoolWithTag(NonPagedPool, sofTplg.length, SKLHDAUDBUS_POOL_TAG); 449 | RtlCopyMemory(fdoCtx->sofTplg, &sofTplg, sofTplg.length); 450 | fdoCtx->sofTplgSz = sofTplg.length; 451 | } 452 | } 453 | 454 | status = STATUS_SUCCESS; 455 | 456 | return status; 457 | } 458 | 459 | NTSTATUS 460 | Fdo_EvtDeviceReleaseHardware( 461 | _In_ WDFDEVICE Device, 462 | _In_ WDFCMRESLIST ResourcesTranslated 463 | ) 464 | { 465 | PFDO_CONTEXT fdoCtx; 466 | 467 | UNREFERENCED_PARAMETER(ResourcesTranslated); 468 | 469 | fdoCtx = Fdo_GetContext(Device); 470 | 471 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 472 | "%s\n", __func__); 473 | 474 | if (fdoCtx->GraphicsDevicesCollection) { 475 | for (ULONG i = 0; i < WdfCollectionGetCount(fdoCtx->GraphicsDevicesCollection); i++) { 476 | WDFIOTARGET ioTarget = (WDFIOTARGET)WdfCollectionGetItem(fdoCtx->GraphicsDevicesCollection, i); 477 | PGRAPHICSIOTARGET_CONTEXT ioTargetContext = GraphicsIoTarget_GetContext(ioTarget); 478 | 479 | if (ioTargetContext->graphicsPowerRegisterOutput.DeviceHandle && ioTargetContext->graphicsPowerRegisterOutput.UnregisterCb) { 480 | NTSTATUS status = ioTargetContext->graphicsPowerRegisterOutput.UnregisterCb(ioTargetContext->graphicsPowerRegisterOutput.DeviceHandle, fdoCtx); 481 | if (!NT_SUCCESS(status)) { 482 | DbgPrint("Warning: unregister failed with status 0x%x\n", status); 483 | } 484 | } 485 | } 486 | } 487 | 488 | if (fdoCtx->GraphicsNotificationHandle) { 489 | IoUnregisterPlugPlayNotification(fdoCtx->GraphicsNotificationHandle); 490 | } 491 | 492 | if (fdoCtx->nhlt) 493 | MmUnmapIoSpace(fdoCtx->nhlt, fdoCtx->nhltSz); 494 | 495 | if (fdoCtx->sofTplg) 496 | ExFreePoolWithTag(fdoCtx->sofTplg, SKLHDAUDBUS_POOL_TAG); 497 | 498 | if (fdoCtx->posbuf) 499 | MmFreeContiguousMemory(fdoCtx->posbuf); 500 | if (fdoCtx->rb) 501 | MmFreeContiguousMemory(fdoCtx->rb); 502 | 503 | if (fdoCtx->streams) { 504 | for (UINT32 i = 0; i < fdoCtx->numStreams; i++) { 505 | PHDAC_STREAM stream = &fdoCtx->streams[i]; 506 | if (stream->bdl) { 507 | MmFreeContiguousMemory(stream->bdl); 508 | stream->bdl = NULL; 509 | } 510 | } 511 | 512 | ExFreePoolWithTag(fdoCtx->streams, SKLHDAUDBUS_POOL_TAG); 513 | } 514 | 515 | if (fdoCtx->m_BAR0.Base.Base) 516 | MmUnmapIoSpace(fdoCtx->m_BAR0.Base.Base, fdoCtx->m_BAR0.Len); 517 | if (fdoCtx->m_BAR4.Base.Base) 518 | MmUnmapIoSpace(fdoCtx->m_BAR4.Base.Base, fdoCtx->m_BAR4.Len); 519 | 520 | return STATUS_SUCCESS; 521 | } 522 | 523 | #define ENABLE_HDA 1 524 | 525 | NTSTATUS 526 | Fdo_EvtDeviceD0Entry( 527 | _In_ WDFDEVICE Device, 528 | _In_ WDF_POWER_DEVICE_STATE PreviousState 529 | ) 530 | { 531 | UNREFERENCED_PARAMETER(PreviousState); 532 | 533 | NTSTATUS status; 534 | PFDO_CONTEXT fdoCtx; 535 | 536 | fdoCtx = Fdo_GetContext(Device); 537 | 538 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 539 | "%s\n", __func__); 540 | 541 | status = STATUS_SUCCESS; 542 | 543 | if (fdoCtx->venId == VEN_INTEL) { 544 | UINT32 val; 545 | pci_read_cfg_dword(&fdoCtx->BusInterface, INTEL_HDA_CGCTL, &val); 546 | val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; 547 | pci_write_cfg_dword(&fdoCtx->BusInterface, INTEL_HDA_CGCTL, val); 548 | } 549 | 550 | //Reset unsolicited queue 551 | RtlZeroMemory(&fdoCtx->unsol_queue, sizeof(fdoCtx->unsol_queue)); 552 | fdoCtx->unsol_rp = 0; 553 | fdoCtx->unsol_wp = 0; 554 | fdoCtx->processUnsol = FALSE; 555 | 556 | //Reset CORB / RIRB 557 | RtlZeroMemory(&fdoCtx->corb, sizeof(fdoCtx->corb)); 558 | RtlZeroMemory(&fdoCtx->rirb, sizeof(fdoCtx->rirb)); 559 | 560 | status = StartHDAController(fdoCtx); 561 | 562 | if (fdoCtx->venId == VEN_INTEL) { 563 | UINT32 val; 564 | pci_read_cfg_dword(&fdoCtx->BusInterface, INTEL_HDA_CGCTL, &val); 565 | val = val | INTEL_HDA_CGCTL_MISCBDCGE; 566 | pci_write_cfg_dword(&fdoCtx->BusInterface, INTEL_HDA_CGCTL, val); 567 | 568 | hda_update32(fdoCtx, VS_EM2, HDA_VS_EM2_DUM, HDA_VS_EM2_DUM); 569 | } 570 | 571 | if (!NT_SUCCESS(status)) { 572 | return status; 573 | } 574 | 575 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 576 | "hda bus initialized\n"); 577 | 578 | return status; 579 | } 580 | 581 | NTSTATUS 582 | Fdo_EvtDeviceD0EntryPostInterrupts( 583 | _In_ WDFDEVICE Device, 584 | _In_ WDF_POWER_DEVICE_STATE PreviousState 585 | ) 586 | { 587 | UNREFERENCED_PARAMETER(PreviousState); 588 | 589 | NTSTATUS status; 590 | PFDO_CONTEXT fdoCtx; 591 | 592 | status = STATUS_SUCCESS; 593 | fdoCtx = Fdo_GetContext(Device); 594 | 595 | #if ENABLE_HDA 596 | for (UINT8 addr = 0; addr < HDA_MAX_CODECS; addr++) { 597 | KeInitializeEvent(&fdoCtx->rirb.xferEvent[addr], NotificationEvent, FALSE); 598 | if (((fdoCtx->codecMask >> addr) & 0x1) == 0) 599 | continue; 600 | 601 | if (fdoCtx->UseSGPCCodec && fdoCtx->GraphicsCodecAddress == addr) 602 | continue; 603 | 604 | UINT32 cmdTmpl = (addr << 28) | (AC_NODE_ROOT << 20) | 605 | (AC_VERB_PARAMETERS << 8); 606 | 607 | ULONG vendorDevice; 608 | if (!NT_SUCCESS(RunSingleHDACmd(fdoCtx, cmdTmpl | AC_PAR_VENDOR_ID, &vendorDevice))) { //Some codecs might need a kickstart 609 | //First attempt failed. Retry 610 | status = RunSingleHDACmd(fdoCtx, cmdTmpl | AC_PAR_VENDOR_ID, &vendorDevice); //If this fails, something is wrong. 611 | } 612 | } 613 | #endif 614 | 615 | return status; 616 | } 617 | 618 | NTSTATUS 619 | Fdo_EvtDeviceD0Exit( 620 | _In_ WDFDEVICE Device, 621 | _In_ WDF_POWER_DEVICE_STATE TargetState 622 | ) 623 | { 624 | UNREFERENCED_PARAMETER(TargetState); 625 | 626 | NTSTATUS status; 627 | PFDO_CONTEXT fdoCtx; 628 | 629 | fdoCtx = Fdo_GetContext(Device); 630 | 631 | status = StopHDAController(fdoCtx); 632 | 633 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 634 | "%s\n", __func__); 635 | 636 | return status; 637 | } 638 | 639 | void 640 | Fdo_EnumerateCodec( 641 | PFDO_CONTEXT fdoCtx, 642 | UINT8 addr 643 | ) 644 | { 645 | UINT32 cmdTmpl = (addr << 28) | (AC_NODE_ROOT << 20) | 646 | (AC_VERB_PARAMETERS << 8); 647 | ULONG funcType = 0, vendorDevice, subsysId, revId, nodeCount; 648 | if (!NT_SUCCESS(RunSingleHDACmd(fdoCtx, cmdTmpl | AC_PAR_VENDOR_ID, &vendorDevice))) { 649 | return; 650 | } 651 | if (!NT_SUCCESS(RunSingleHDACmd(fdoCtx, cmdTmpl | AC_PAR_REV_ID, &revId))) { 652 | return; 653 | } 654 | if (!NT_SUCCESS(RunSingleHDACmd(fdoCtx, cmdTmpl | AC_PAR_NODE_COUNT, &nodeCount))) { 655 | return; 656 | } 657 | 658 | fdoCtx->numCodecs += 1; 659 | 660 | UINT8 startID = (nodeCount >> 16) & 0xFF; 661 | nodeCount = (nodeCount & 0x7FFF); 662 | 663 | UINT16 mainFuncGrp = 0; 664 | { 665 | UINT16 nid = startID; 666 | for (UINT32 i = 0; i < nodeCount; i++, nid++) { 667 | UINT32 cmd = (addr << 28) | (nid << 20) | 668 | (AC_VERB_PARAMETERS << 8) | AC_PAR_FUNCTION_TYPE; 669 | if (!NT_SUCCESS(RunSingleHDACmd(fdoCtx, cmd, &funcType))) { 670 | continue; 671 | } 672 | switch (funcType & 0xFF) { 673 | case AC_GRP_AUDIO_FUNCTION: 674 | case AC_GRP_MODEM_FUNCTION: 675 | mainFuncGrp = nid; 676 | break; 677 | } 678 | } 679 | } 680 | 681 | UINT32 cmd = (addr << 28) | (mainFuncGrp << 20) | 682 | (AC_VERB_GET_SUBSYSTEM_ID << 8); 683 | RunSingleHDACmd(fdoCtx, cmd, &subsysId); 684 | 685 | PDO_IDENTIFICATION_DESCRIPTION description; 686 | // 687 | // Initialize the description with the information about the detected codec. 688 | // 689 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT( 690 | &description.Header, 691 | sizeof(description) 692 | ); 693 | 694 | description.FdoContext = fdoCtx; 695 | 696 | description.CodecIds.CtlrDevId = fdoCtx->devId; 697 | description.CodecIds.CtlrVenId = fdoCtx->venId; 698 | 699 | description.CodecIds.CodecAddress = addr; 700 | if (fdoCtx->UseSGPCCodec && addr == fdoCtx->GraphicsCodecAddress) 701 | description.CodecIds.IsGraphicsCodec = TRUE; 702 | else 703 | description.CodecIds.IsGraphicsCodec = FALSE; 704 | 705 | description.CodecIds.FunctionGroupStartNode = startID; 706 | 707 | description.CodecIds.IsDSP = FALSE; 708 | 709 | description.CodecIds.FuncId = funcType & 0xFF; 710 | description.CodecIds.VenId = (vendorDevice >> 16) & 0xFFFF; 711 | description.CodecIds.DevId = vendorDevice & 0xFFFF; 712 | description.CodecIds.SubsysId = subsysId; 713 | description.CodecIds.RevId = (revId >> 8) & 0xFFFF; 714 | 715 | // 716 | // Call the framework to add this child to the childlist. This call 717 | // will internaly call our DescriptionCompare callback to check 718 | // whether this device is a new device or existing device. If 719 | // it's a new device, the framework will call DescriptionDuplicate to create 720 | // a copy of this description in nonpaged pool. 721 | // The actual creation of the child device will happen when the framework 722 | // receives QUERY_DEVICE_RELATION request from the PNP manager in 723 | // response to InvalidateDeviceRelations call made as part of adding 724 | // a new child. 725 | // 726 | WdfChildListAddOrUpdateChildDescriptionAsPresent( 727 | WdfFdoGetDefaultChildList(fdoCtx->WdfDevice), &description.Header, 728 | NULL); // AddressDescription 729 | } 730 | 731 | NTSTATUS 732 | Fdo_EvtDeviceSelfManagedIoInit( 733 | _In_ WDFDEVICE Device 734 | ) 735 | { 736 | NTSTATUS status = STATUS_SUCCESS; 737 | PFDO_CONTEXT fdoCtx; 738 | 739 | fdoCtx = Fdo_GetContext(Device); 740 | 741 | WdfChildListBeginScan(WdfFdoGetDefaultChildList(Device)); 742 | 743 | fdoCtx->numCodecs = 0; 744 | #if ENABLE_HDA 745 | for (UINT8 addr = 0; addr < HDA_MAX_CODECS; addr++) { 746 | fdoCtx->codecs[addr] = NULL; 747 | if (((fdoCtx->codecMask >> addr) & 0x1) == 0) 748 | continue; 749 | 750 | if (fdoCtx->UseSGPCCodec && fdoCtx->GraphicsCodecAddress == addr) 751 | continue; 752 | 753 | Fdo_EnumerateCodec(fdoCtx, addr); 754 | } 755 | 756 | if (fdoCtx->mlcap) { 757 | IoRegisterPlugPlayNotification( 758 | EventCategoryDeviceInterfaceChange, 759 | PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 760 | (PVOID)&GUID_DEVINTERFACE_GRAPHICSPOWER, 761 | WdfDriverWdmGetDriverObject(WdfDeviceGetDriver(fdoCtx->WdfDevice)), 762 | HDAGraphicsPowerInterfaceCallback, 763 | (PVOID)fdoCtx, 764 | &fdoCtx->GraphicsNotificationHandle 765 | ); 766 | 767 | } 768 | #endif 769 | 770 | fdoCtx->dspInterruptCallback = NULL; 771 | if (fdoCtx->m_BAR4.Base.Base) { //Populate ADSP if present 772 | PDO_IDENTIFICATION_DESCRIPTION description; 773 | // 774 | // Initialize the description with the information about the detected codec. 775 | // 776 | WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT( 777 | &description.Header, 778 | sizeof(description) 779 | ); 780 | 781 | description.FdoContext = fdoCtx; 782 | 783 | description.CodecIds.CtlrDevId = fdoCtx->devId; 784 | description.CodecIds.CtlrVenId = fdoCtx->venId; 785 | 786 | description.CodecIds.CodecAddress = 0x10000000; 787 | description.CodecIds.IsDSP = TRUE; 788 | 789 | // 790 | // Call the framework to add this child to the childlist. This call 791 | // will internaly call our DescriptionCompare callback to check 792 | // whether this device is a new device or existing device. If 793 | // it's a new device, the framework will call DescriptionDuplicate to create 794 | // a copy of this description in nonpaged pool. 795 | // The actual creation of the child device will happen when the framework 796 | // receives QUERY_DEVICE_RELATION request from the PNP manager in 797 | // response to InvalidateDeviceRelations call made as part of adding 798 | // a new child. 799 | // 800 | status = WdfChildListAddOrUpdateChildDescriptionAsPresent( 801 | WdfFdoGetDefaultChildList(Device), &description.Header, 802 | NULL); // AddressDescription 803 | } 804 | 805 | WdfChildListEndScan(WdfFdoGetDefaultChildList(Device)); 806 | 807 | SklHdAudBusPrint(DEBUG_LEVEL_INFO, DBG_INIT, 808 | "hda scan complete\n"); 809 | return status; 810 | } --------------------------------------------------------------------------------