├── .gitattributes ├── README.txt ├── max98357a ├── resource.h ├── gpiowrapper.h ├── max98357a.rc ├── trace.h ├── max98357a.inf ├── driver.h ├── gpio.c ├── max98357a.vcxproj ├── max98357a.c └── spb.cpp ├── LICENSE.txt ├── max98357a.sln ├── .gitignore └── max98357a Package └── max98357a Package.vcxproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | MAX98357A / MAX98360A / RT1015P / RT1019P Amp driver for Windows 2 | 3 | Requires CoolStar Audio 4 | 5 | Tested on Skylake, Kaby Lake, Kaby-Lake-R, Alder Lake, Ryzen, etc. -------------------------------------------------------------------------------- /max98357a/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by max98357a.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 2022 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. -------------------------------------------------------------------------------- /max98357a/gpiowrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define DEFAULT_SPB_BUFFER_SIZE 64 7 | #define RESHUB_USE_HELPER_ROUTINES 8 | 9 | // 10 | // SPB (I2C) context 11 | // 12 | 13 | typedef struct _GPIO_CONTEXT 14 | { 15 | WDFIOTARGET GpioIoTarget; 16 | LARGE_INTEGER GpioResHubId; 17 | WDFWAITLOCK GpioLock; 18 | } GPIO_CONTEXT; 19 | 20 | VOID 21 | GpioTargetDeinitialize( 22 | IN WDFDEVICE FxDevice, 23 | IN GPIO_CONTEXT *GpioContext 24 | ); 25 | 26 | NTSTATUS 27 | GpioTargetInitialize( 28 | IN WDFDEVICE FxDevice, 29 | IN GPIO_CONTEXT *GpioContext 30 | ); 31 | 32 | NTSTATUS 33 | GpioWriteDataSynchronously( 34 | _In_ GPIO_CONTEXT* GpioContext, 35 | _In_ PVOID Data 36 | ); -------------------------------------------------------------------------------- /max98357a/max98357a.rc: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation All Rights Reserved 4 | 5 | Module Name: 6 | 7 | max98357a.rc 8 | 9 | Abstract: 10 | 11 | --*/ 12 | 13 | #include 14 | 15 | #define VER_FILETYPE VFT_DRV 16 | #define VER_FILESUBTYPE VFT2_DRV_SOUND 17 | #define VER_FILEDESCRIPTION_STR "Maxim 98357a/98360a or Realtek ALC1015P/ALC1019P Amplifier" 18 | #define VER_INTERNALNAME_STR "max98357a.sys" 19 | #define VER_ORIGINALFILENAME_STR "max98357a.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,3,0 25 | #define VER_PRODUCTVERSION_STR "1.0.3.0" 26 | #define VER_PRODUCTVERSION 1,0,3,0 27 | #define LVER_PRODUCTVERSION_STR L"1.0.3.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 "Maxim 98357a/98360a or Realtek ALC1015P/ALC1019P Amplifier" 40 | 41 | #include "common.ver" -------------------------------------------------------------------------------- /max98357a/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 | -------------------------------------------------------------------------------- /max98357a/max98357a.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ;Copyright (c) CoolStar. All rights reserved. 4 | ; 5 | ;Module Name: 6 | ; max98357a.inf 7 | ; 8 | ;Abstract: 9 | ; INF file for installing the Maxim 98090 Driver 10 | ; 11 | ; 12 | ;--*/ 13 | 14 | [Version] 15 | Signature = "$WINDOWS NT$" 16 | Class = Media 17 | ClassGuid = {4d36e96c-e325-11ce-bfc1-08002be10318} 18 | Provider = CoolStar 19 | DriverVer = 05/01/2022,1.0.3 20 | CatalogFile = max98357a.cat 21 | PnpLockdown = 1 22 | 23 | [DestinationDirs] 24 | DefaultDestDir = 12 25 | 26 | ; ================= Class section ===================== 27 | 28 | [SourceDisksNames] 29 | 1 = %DiskId1%,,,"" 30 | 31 | [SourceDisksFiles] 32 | max98357a.sys = 1,, 33 | 34 | ;***************************************** 35 | ; MAX98357A Install Section 36 | ;***************************************** 37 | 38 | [Manufacturer] 39 | %StdMfg%=Standard,NT$ARCH$ 40 | 41 | ; Decorated model section take precedence over undecorated 42 | ; ones on XP and later. 43 | [Standard.NT$ARCH$] 44 | %MAX98357A.DeviceDesc%=MAX98357A_Device, ACPI\MX98357A 45 | %MAX98360A.DeviceDesc%=MAX98357A_Device, ACPI\MX98360A 46 | %RTL1015P.DeviceDesc%=MAX98357A_Device, ACPI\RTL1015 47 | %RTL1019P.DeviceDesc%=MAX98357A_Device, ACPI\RTL1019 48 | 49 | [MAX98357A_Device.NT] 50 | CopyFiles=Drivers_Dir 51 | 52 | [MAX98357A_Device.NT.HW] 53 | Include=pci.inf 54 | Needs=PciD3ColdSupported.HW 55 | 56 | [Drivers_Dir] 57 | max98357a.sys 58 | 59 | ;-------------- Service installation 60 | [MAX98357A_Device.NT.Services] 61 | AddService = MAX98357A,%SPSVCINST_ASSOCSERVICE%, MAX98357A_Service_Inst 62 | 63 | ; -------------- MAX98357A driver install sections 64 | [MAX98357A_Service_Inst] 65 | DisplayName = %MAX98357A.SVCDESC% 66 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 67 | StartType = 3 ; SERVICE_DEMAND_START 68 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 69 | ServiceBinary = %12%\max98357a.sys 70 | LoadOrderGroup = Base 71 | 72 | [Strings] 73 | SPSVCINST_ASSOCSERVICE= 0x00000002 74 | StdMfg = "CoolStar" 75 | DiskId1 = "Maxim 98357a Installation Disk #1" 76 | MAX98357A.DeviceDesc = "Maxim 98357a I2S Amplifier" 77 | MAX98360A.DeviceDesc = "Maxim 98360a I2S Amplifier" 78 | RTL1015P.DeviceDesc = "Realtek ALC1015P I2S Amplifier" 79 | RTL1019P.DeviceDesc = "Realtek ALC1019P I2S Amplifier" 80 | MAX98357A.SVCDESC = "GPIO Amplifier Service" 81 | -------------------------------------------------------------------------------- /max98357a.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}") = "max98357a", "max98357a\max98357a.vcxproj", "{B3E71397-9BE4-492B-AAED-4D056E59CB1F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "max98357a Package", "max98357a Package\max98357a 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 | -------------------------------------------------------------------------------- /max98357a/driver.h: -------------------------------------------------------------------------------- 1 | #if !defined(_MAXM_H_) 2 | #define _MAXM_H_ 3 | 4 | #pragma warning(disable:4200) // suppress nameless struct/union warning 5 | #pragma warning(disable:4201) // suppress nameless struct/union warning 6 | #pragma warning(disable:4214) // suppress bit field types other than int warning 7 | #include 8 | #include 9 | 10 | #pragma warning(default:4200) 11 | #pragma warning(default:4201) 12 | #pragma warning(default:4214) 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include "gpiowrapper.h" 19 | 20 | // 21 | // String definitions 22 | // 23 | 24 | #define DRIVERNAME "max98357a.sys: " 25 | 26 | #define MAXM_POOL_TAG (ULONG) 'mxaM' 27 | 28 | #define NTDEVICE_NAME_STRING L"\\Device\\MAX98357A" 29 | #define SYMBOLIC_NAME_STRING L"\\DosDevices\\MAX98357A" 30 | 31 | #define true 1 32 | #define false 0 33 | 34 | typedef enum { 35 | CSAudioEndpointTypeDSP, 36 | CSAudioEndpointTypeSpeaker, 37 | CSAudioEndpointTypeHeadphone, 38 | CSAudioEndpointTypeMicArray, 39 | CSAudioEndpointTypeMicJack 40 | } CSAudioEndpointType; 41 | 42 | typedef enum { 43 | CSAudioEndpointRegister, 44 | CSAudioEndpointStart, 45 | CSAudioEndpointStop, 46 | CSAudioEndpointOverrideFormat 47 | } CSAudioEndpointRequest; 48 | 49 | typedef struct CSAUDIOFORMATOVERRIDE { 50 | UINT16 channels; 51 | UINT16 frequency; 52 | UINT16 bitsPerSample; 53 | UINT16 validBitsPerSample; 54 | BOOL force32BitOutputContainer; 55 | } CsAudioFormatOverride; 56 | 57 | typedef struct CSAUDIOARG { 58 | UINT32 argSz; 59 | CSAudioEndpointType endpointType; 60 | CSAudioEndpointRequest endpointRequest; 61 | union { 62 | CsAudioFormatOverride formatOverride; 63 | }; 64 | } CsAudioArg, * PCsAudioArg; 65 | 66 | typedef struct _MAXM_CONTEXT 67 | { 68 | 69 | // 70 | // Handle back to the WDFDEVICE 71 | // 72 | 73 | WDFDEVICE FxDevice; 74 | 75 | WDFQUEUE ReportQueue; 76 | 77 | GPIO_CONTEXT SdmodeGpioContext; 78 | 79 | BOOLEAN DevicePoweredOn; 80 | 81 | WDFWORKITEM CSAudioWorkItem; 82 | PCALLBACK_OBJECT CSAudioAPICallback; 83 | PVOID CSAudioAPICallbackObj; 84 | 85 | BOOLEAN CSAudioRequestsOn; 86 | 87 | } MAXM_CONTEXT, *PMAXM_CONTEXT; 88 | 89 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MAXM_CONTEXT, GetDeviceContext) 90 | 91 | // 92 | // Function definitions 93 | // 94 | 95 | DRIVER_INITIALIZE DriverEntry; 96 | 97 | EVT_WDF_DRIVER_UNLOAD MaxmDriverUnload; 98 | 99 | EVT_WDF_DRIVER_DEVICE_ADD MaxmEvtDeviceAdd; 100 | 101 | EVT_WDFDEVICE_WDM_IRP_PREPROCESS MaxmEvtWdmPreprocessMnQueryId; 102 | 103 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL MaxmEvtInternalDeviceControl; 104 | 105 | // 106 | // Helper macros 107 | // 108 | 109 | #define DEBUG_LEVEL_ERROR 1 110 | #define DEBUG_LEVEL_INFO 2 111 | #define DEBUG_LEVEL_VERBOSE 3 112 | 113 | #define DBG_INIT 1 114 | #define DBG_PNP 2 115 | #define DBG_IOCTL 4 116 | 117 | #if 0 118 | #define MaxmPrint(dbglevel, dbgcatagory, fmt, ...) { \ 119 | if (MaxmDebugLevel >= dbglevel && \ 120 | (MaxmDebugCatagories && dbgcatagory)) \ 121 | { \ 122 | DbgPrint(DRIVERNAME); \ 123 | DbgPrint(fmt, __VA_ARGS__); \ 124 | } \ 125 | } 126 | #else 127 | #define MaxmPrint(dbglevel, fmt, ...) { \ 128 | } 129 | #endif 130 | #endif -------------------------------------------------------------------------------- /max98357a/gpio.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "gpiowrapper.h" 3 | #include 4 | #include 5 | 6 | static ULONG MaxmDebugLevel = 100; 7 | static ULONG MaxmDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 8 | 9 | NTSTATUS 10 | GpioWriteDataSynchronously( 11 | _In_ GPIO_CONTEXT *GpioContext, 12 | _In_ PVOID Data 13 | ) 14 | /*++ 15 | 16 | Routine Description: 17 | 18 | This helper routine abstracts creating and sending an I/O 19 | request (I2C Read) to the Spb I/O target. 20 | 21 | Arguments: 22 | 23 | SpbContext - Pointer to the current device context 24 | Data - A buffer to receive the data at at the above address 25 | Length - The amount of data to be read from the above address 26 | 27 | Return Value: 28 | 29 | NTSTATUS Status indicating success or failure 30 | 31 | --*/ 32 | { 33 | WDF_MEMORY_DESCRIPTOR inputDescriptor, outputDescriptor; 34 | NTSTATUS status; 35 | 36 | WdfWaitLockAcquire(GpioContext->GpioLock, NULL); 37 | 38 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, Data, 1); 39 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, Data, 1); 40 | 41 | status = WdfIoTargetSendIoctlSynchronously(GpioContext->GpioIoTarget, NULL, IOCTL_GPIO_WRITE_PINS, &inputDescriptor, &outputDescriptor, NULL, NULL); 42 | 43 | WdfWaitLockRelease(GpioContext->GpioLock); 44 | 45 | return status; 46 | } 47 | 48 | VOID 49 | GpioTargetDeinitialize( 50 | IN WDFDEVICE FxDevice, 51 | IN GPIO_CONTEXT *GpioContext 52 | ) 53 | /*++ 54 | 55 | Routine Description: 56 | 57 | This helper routine is used to free any members added to the SPB_CONTEXT, 58 | note the SPB I/O target is parented to the device and will be 59 | closed and free'd when the device is removed. 60 | 61 | Arguments: 62 | 63 | FxDevice - Handle to the framework device object 64 | SpbContext - Pointer to the current device context 65 | 66 | Return Value: 67 | 68 | NTSTATUS Status indicating success or failure 69 | 70 | --*/ 71 | { 72 | UNREFERENCED_PARAMETER(FxDevice); 73 | UNREFERENCED_PARAMETER(GpioContext); 74 | 75 | // 76 | // Free any SPB_CONTEXT allocations here 77 | // 78 | if (GpioContext->GpioLock != NULL) 79 | { 80 | WdfObjectDelete(GpioContext->GpioLock); 81 | } 82 | } 83 | 84 | NTSTATUS 85 | GpioTargetInitialize( 86 | IN WDFDEVICE FxDevice, 87 | IN GPIO_CONTEXT *GpioContext 88 | ) 89 | /*++ 90 | 91 | Routine Description: 92 | 93 | This helper routine opens the Spb I/O target and 94 | initializes a request object used for the lifetime 95 | of communication between this driver and Spb. 96 | 97 | Arguments: 98 | 99 | FxDevice - Handle to the framework device object 100 | SpbContext - Pointer to the current device context 101 | 102 | Return Value: 103 | 104 | NTSTATUS Status indicating success or failure 105 | 106 | --*/ 107 | { 108 | WDF_OBJECT_ATTRIBUTES objectAttributes; 109 | WDF_IO_TARGET_OPEN_PARAMS openParams; 110 | UNICODE_STRING gpioDeviceName; 111 | WCHAR gpioDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 112 | NTSTATUS status; 113 | 114 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 115 | objectAttributes.ParentObject = FxDevice; 116 | 117 | status = WdfIoTargetCreate( 118 | FxDevice, 119 | &objectAttributes, 120 | &GpioContext->GpioIoTarget); 121 | 122 | if (!NT_SUCCESS(status)) 123 | { 124 | MaxmPrint( 125 | DEBUG_LEVEL_ERROR, 126 | DBG_IOCTL, 127 | "Error creating IoTarget object - %!STATUS!", 128 | status); 129 | 130 | WdfObjectDelete(GpioContext->GpioIoTarget); 131 | goto exit; 132 | } 133 | 134 | RtlInitEmptyUnicodeString( 135 | &gpioDeviceName, 136 | gpioDeviceNameBuffer, 137 | sizeof(gpioDeviceNameBuffer)); 138 | 139 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 140 | &gpioDeviceName, 141 | GpioContext->GpioResHubId.LowPart, 142 | GpioContext->GpioResHubId.HighPart); 143 | 144 | if (!NT_SUCCESS(status)) 145 | { 146 | MaxmPrint( 147 | DEBUG_LEVEL_ERROR, 148 | DBG_IOCTL, 149 | "Error creating GPIO resource hub path string - %!STATUS!", 150 | status); 151 | goto exit; 152 | } 153 | 154 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 155 | &openParams, 156 | &gpioDeviceName, 157 | (FILE_GENERIC_WRITE)); 158 | 159 | status = WdfIoTargetOpen(GpioContext->GpioIoTarget, &openParams); 160 | 161 | if (!NT_SUCCESS(status)) 162 | { 163 | MaxmPrint( 164 | DEBUG_LEVEL_ERROR, 165 | DBG_IOCTL, 166 | "Error opening GPIO target for communication - %!STATUS!", 167 | status); 168 | goto exit; 169 | } 170 | 171 | // 172 | // Allocate a waitlock to guard access to the default buffers 173 | // 174 | status = WdfWaitLockCreate( 175 | WDF_NO_OBJECT_ATTRIBUTES, 176 | &GpioContext->GpioLock); 177 | 178 | if (!NT_SUCCESS(status)) 179 | { 180 | MaxmPrint( 181 | DEBUG_LEVEL_ERROR, 182 | DBG_IOCTL, 183 | "Error creating Spb Waitlock - %!STATUS!", 184 | status); 185 | goto exit; 186 | } 187 | 188 | exit: 189 | 190 | if (!NT_SUCCESS(status)) 191 | { 192 | GpioTargetDeinitialize(FxDevice, GpioContext); 193 | } 194 | 195 | return status; 196 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /max98357a Package/max98357a 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 | max98357a_Package 29 | $(LatestTargetPlatformVersion) 30 | max98357a 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 | -------------------------------------------------------------------------------- /max98357a/max98357a.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 | max98357a 29 | 30 | 31 | max98357a 32 | 33 | 34 | 35 | Windows10 36 | true 37 | WindowsKernelModeDriver10.0 38 | Driver 39 | KMDF 40 | 41 | 42 | Windows10 43 | false 44 | WindowsKernelModeDriver10.0 45 | Driver 46 | KMDF 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Driver 53 | KMDF 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | DbgengKernelDebugger 72 | 73 | 74 | DbgengKernelDebugger 75 | 76 | 77 | DbgengKernelDebugger 78 | 79 | 80 | DbgengKernelDebugger 81 | 82 | 83 | 84 | true 85 | trace.h 86 | true 87 | false 88 | 89 | 90 | 1.0.3 91 | 92 | 93 | SHA256 94 | 95 | 96 | 97 | 98 | true 99 | trace.h 100 | true 101 | false 102 | 103 | 104 | 1.0.3 105 | 106 | 107 | SHA256 108 | 109 | 110 | 111 | 112 | true 113 | trace.h 114 | true 115 | false 116 | 117 | 118 | 1.0.3 119 | 120 | 121 | SHA256 122 | 123 | 124 | 125 | 126 | true 127 | trace.h 128 | true 129 | false 130 | 131 | 132 | 1.0.3 133 | 134 | 135 | SHA256 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 | -------------------------------------------------------------------------------- /max98357a/max98357a.c: -------------------------------------------------------------------------------- 1 | #define DESCRIPTOR_DEF 2 | #include "driver.h" 3 | #include "stdint.h" 4 | 5 | #define bool int 6 | #define MHz 1000000 7 | 8 | static ULONG MaxmDebugLevel = 100; 9 | static ULONG MaxmDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 10 | 11 | NTSTATUS 12 | DriverEntry( 13 | __in PDRIVER_OBJECT DriverObject, 14 | __in PUNICODE_STRING RegistryPath 15 | ) 16 | { 17 | NTSTATUS status = STATUS_SUCCESS; 18 | WDF_DRIVER_CONFIG config; 19 | WDF_OBJECT_ATTRIBUTES attributes; 20 | 21 | MaxmPrint(DEBUG_LEVEL_INFO, DBG_INIT, 22 | "Driver Entry\n"); 23 | 24 | WDF_DRIVER_CONFIG_INIT(&config, MaxmEvtDeviceAdd); 25 | 26 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 27 | 28 | // 29 | // Create a framework driver object to represent our driver. 30 | // 31 | 32 | status = WdfDriverCreate(DriverObject, 33 | RegistryPath, 34 | &attributes, 35 | &config, 36 | WDF_NO_HANDLE 37 | ); 38 | 39 | if (!NT_SUCCESS(status)) 40 | { 41 | MaxmPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 42 | "WdfDriverCreate failed with status 0x%x\n", status); 43 | } 44 | 45 | return status; 46 | } 47 | 48 | int CsAudioArg2 = 1; 49 | 50 | VOID 51 | CsAudioWorkItemFunc( 52 | IN WDFWORKITEM WorkItem 53 | ) 54 | { 55 | WDFDEVICE Device = (WDFDEVICE)WdfWorkItemGetParentObject(WorkItem); 56 | PMAXM_CONTEXT pDevice = GetDeviceContext(Device); 57 | 58 | LARGE_INTEGER Interval; 59 | Interval.QuadPart = -10 * 1000 * 5; //5 ms delay to avoid popping on Intel SST (Only CSAudio can use this fix though) 60 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 61 | 62 | unsigned char gpio_data; 63 | gpio_data = 1; 64 | if (NT_SUCCESS(GpioWriteDataSynchronously(&pDevice->SdmodeGpioContext, &gpio_data))) { 65 | pDevice->DevicePoweredOn = TRUE; 66 | } 67 | 68 | WdfDeviceStopIdle(pDevice->FxDevice, TRUE); 69 | } 70 | 71 | VOID 72 | CSAudioRegisterEndpoint( 73 | PMAXM_CONTEXT pDevice 74 | ) { 75 | CsAudioArg arg; 76 | RtlZeroMemory(&arg, sizeof(CsAudioArg)); 77 | arg.argSz = sizeof(CsAudioArg); 78 | arg.endpointType = CSAudioEndpointTypeSpeaker; 79 | arg.endpointRequest = CSAudioEndpointRegister; 80 | ExNotifyCallback(pDevice->CSAudioAPICallback, &arg, &CsAudioArg2); 81 | 82 | RtlZeroMemory(&arg, sizeof(CsAudioArg)); 83 | arg.argSz = sizeof(CsAudioArg); 84 | arg.endpointType = CSAudioEndpointTypeSpeaker; 85 | arg.endpointRequest = CSAudioEndpointOverrideFormat; 86 | arg.formatOverride.bitsPerSample = 16; 87 | arg.formatOverride.validBitsPerSample = 16; 88 | arg.formatOverride.force32BitOutputContainer = TRUE; 89 | ExNotifyCallback(pDevice->CSAudioAPICallback, &arg, &CsAudioArg2); 90 | } 91 | 92 | VOID 93 | CsAudioCallbackFunction( 94 | IN WDFWORKITEM WorkItem, 95 | CsAudioArg* arg, 96 | PVOID Argument2 97 | ) { 98 | if (!WorkItem) { 99 | return; 100 | } 101 | WDFDEVICE Device = (WDFDEVICE)WdfWorkItemGetParentObject(WorkItem); 102 | PMAXM_CONTEXT pDevice = GetDeviceContext(Device); 103 | 104 | if (Argument2 == &CsAudioArg2) { 105 | return; 106 | } 107 | 108 | CsAudioArg localArg; 109 | RtlZeroMemory(&localArg, sizeof(CsAudioArg)); 110 | RtlCopyMemory(&localArg, arg, min(arg->argSz, sizeof(CsAudioArg))); 111 | 112 | if (localArg.endpointType == CSAudioEndpointTypeDSP && localArg.endpointRequest == CSAudioEndpointRegister) { 113 | CSAudioRegisterEndpoint(pDevice); 114 | } else if (localArg.endpointType != CSAudioEndpointTypeSpeaker) { 115 | return; 116 | } 117 | 118 | if (localArg.endpointRequest == CSAudioEndpointStop || localArg.endpointRequest == CSAudioEndpointStart) { 119 | if (pDevice->CSAudioRequestsOn) { 120 | WdfDeviceResumeIdle(pDevice->FxDevice); 121 | 122 | unsigned char gpio_data; 123 | gpio_data = 0; 124 | if (NT_SUCCESS(GpioWriteDataSynchronously(&pDevice->SdmodeGpioContext, &gpio_data))) { 125 | pDevice->DevicePoweredOn = FALSE; 126 | } 127 | 128 | pDevice->CSAudioRequestsOn = FALSE; 129 | } 130 | } 131 | if (localArg.endpointRequest == CSAudioEndpointStart) { 132 | if (!pDevice->CSAudioRequestsOn) { 133 | pDevice->CSAudioRequestsOn = TRUE; 134 | WdfWorkItemEnqueue(pDevice->CSAudioWorkItem); 135 | } 136 | } 137 | } 138 | 139 | NTSTATUS 140 | OnPrepareHardware( 141 | _In_ WDFDEVICE FxDevice, 142 | _In_ WDFCMRESLIST FxResourcesRaw, 143 | _In_ WDFCMRESLIST FxResourcesTranslated 144 | ) 145 | /*++ 146 | 147 | Routine Description: 148 | 149 | This routine caches the SPB resource connection ID. 150 | 151 | Arguments: 152 | 153 | FxDevice - a handle to the framework device object 154 | FxResourcesRaw - list of translated hardware resources that 155 | the PnP manager has assigned to the device 156 | FxResourcesTranslated - list of raw hardware resources that 157 | the PnP manager has assigned to the device 158 | 159 | Return Value: 160 | 161 | Status 162 | 163 | --*/ 164 | { 165 | PMAXM_CONTEXT pDevice = GetDeviceContext(FxDevice); 166 | BOOLEAN fSdmodeGpioResourceFound = FALSE; 167 | NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 168 | 169 | UNREFERENCED_PARAMETER(FxResourcesRaw); 170 | 171 | // 172 | // Parse the peripheral's resources. 173 | // 174 | 175 | ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); 176 | 177 | for (ULONG i = 0; i < resourceCount; i++) 178 | { 179 | PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 180 | UCHAR Class; 181 | UCHAR Type; 182 | 183 | pDescriptor = WdfCmResourceListGetDescriptor( 184 | FxResourcesTranslated, i); 185 | 186 | switch (pDescriptor->Type) 187 | { 188 | case CmResourceTypeConnection: 189 | // 190 | // Look for I2C or SPI resource and save connection ID. 191 | // 192 | Class = pDescriptor->u.Connection.Class; 193 | Type = pDescriptor->u.Connection.Type; 194 | if (Class == CM_RESOURCE_CONNECTION_CLASS_GPIO && Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO) { 195 | if (fSdmodeGpioResourceFound == FALSE) { 196 | pDevice->SdmodeGpioContext.GpioResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; 197 | pDevice->SdmodeGpioContext.GpioResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; 198 | fSdmodeGpioResourceFound = TRUE; 199 | } 200 | } 201 | break; 202 | default: 203 | // 204 | // Ignoring all other resource types. 205 | // 206 | break; 207 | } 208 | } 209 | 210 | // 211 | // An SPB resource is required. 212 | // 213 | 214 | if (fSdmodeGpioResourceFound == FALSE) 215 | { 216 | status = STATUS_NOT_FOUND; 217 | return status; 218 | } 219 | 220 | status = GpioTargetInitialize(FxDevice, &pDevice->SdmodeGpioContext); 221 | if (!NT_SUCCESS(status)) 222 | { 223 | return status; 224 | } 225 | 226 | WDF_OBJECT_ATTRIBUTES attributes; 227 | WDF_WORKITEM_CONFIG workitemConfig; 228 | 229 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 230 | WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, MAXM_CONTEXT); 231 | attributes.ParentObject = FxDevice; 232 | WDF_WORKITEM_CONFIG_INIT(&workitemConfig, CsAudioWorkItemFunc); 233 | status = WdfWorkItemCreate(&workitemConfig, 234 | &attributes, 235 | &pDevice->CSAudioWorkItem); 236 | if (!NT_SUCCESS(status)) 237 | { 238 | return status; 239 | } 240 | 241 | return status; 242 | } 243 | 244 | NTSTATUS 245 | OnReleaseHardware( 246 | _In_ WDFDEVICE FxDevice, 247 | _In_ WDFCMRESLIST FxResourcesTranslated 248 | ) 249 | /*++ 250 | 251 | Routine Description: 252 | 253 | Arguments: 254 | 255 | FxDevice - a handle to the framework device object 256 | FxResourcesTranslated - list of raw hardware resources that 257 | the PnP manager has assigned to the device 258 | 259 | Return Value: 260 | 261 | Status 262 | 263 | --*/ 264 | { 265 | PMAXM_CONTEXT pDevice = GetDeviceContext(FxDevice); 266 | NTSTATUS status = STATUS_SUCCESS; 267 | 268 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 269 | 270 | GpioTargetDeinitialize(FxDevice, &pDevice->SdmodeGpioContext); 271 | 272 | if (pDevice->CSAudioAPICallbackObj) { 273 | ExUnregisterCallback(pDevice->CSAudioAPICallbackObj); 274 | pDevice->CSAudioAPICallbackObj = NULL; 275 | } 276 | 277 | if (pDevice->CSAudioWorkItem) { 278 | WdfWorkItemFlush(pDevice->CSAudioWorkItem); 279 | WdfObjectDelete(pDevice->CSAudioWorkItem); 280 | pDevice->CSAudioWorkItem = NULL; 281 | } 282 | 283 | if (pDevice->CSAudioAPICallback) { 284 | ObfDereferenceObject(pDevice->CSAudioAPICallback); 285 | pDevice->CSAudioAPICallback = NULL; 286 | } 287 | 288 | return status; 289 | } 290 | 291 | NTSTATUS 292 | OnSelfManagedIoInit( 293 | _In_ 294 | WDFDEVICE FxDevice 295 | ) { 296 | PMAXM_CONTEXT pDevice = GetDeviceContext(FxDevice); 297 | NTSTATUS status = STATUS_SUCCESS; 298 | 299 | // CS Audio Callback 300 | 301 | UNICODE_STRING CSAudioCallbackAPI; 302 | RtlInitUnicodeString(&CSAudioCallbackAPI, L"\\CallBack\\CsAudioCallbackAPI"); 303 | 304 | 305 | OBJECT_ATTRIBUTES attributes; 306 | InitializeObjectAttributes(&attributes, 307 | &CSAudioCallbackAPI, 308 | OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 309 | NULL, 310 | NULL 311 | ); 312 | status = ExCreateCallback(&pDevice->CSAudioAPICallback, &attributes, TRUE, TRUE); 313 | if (!NT_SUCCESS(status)) { 314 | 315 | return status; 316 | } 317 | 318 | pDevice->CSAudioAPICallbackObj = ExRegisterCallback(pDevice->CSAudioAPICallback, 319 | CsAudioCallbackFunction, 320 | pDevice->CSAudioWorkItem 321 | ); 322 | if (!pDevice->CSAudioAPICallbackObj) { 323 | 324 | return STATUS_NO_CALLBACK_ACTIVE; 325 | } 326 | 327 | CSAudioRegisterEndpoint(pDevice); 328 | 329 | return status; 330 | } 331 | 332 | NTSTATUS 333 | OnD0Entry( 334 | _In_ WDFDEVICE FxDevice, 335 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 336 | ) 337 | /*++ 338 | 339 | Routine Description: 340 | 341 | This routine allocates objects needed by the driver. 342 | 343 | Arguments: 344 | 345 | FxDevice - a handle to the framework device object 346 | FxPreviousState - previous power state 347 | 348 | Return Value: 349 | 350 | Status 351 | 352 | --*/ 353 | { 354 | UNREFERENCED_PARAMETER(FxPreviousState); 355 | 356 | PMAXM_CONTEXT pDevice = GetDeviceContext(FxDevice); 357 | NTSTATUS status = STATUS_SUCCESS; 358 | 359 | unsigned char gpio_data; 360 | gpio_data = 1; 361 | status = GpioWriteDataSynchronously(&pDevice->SdmodeGpioContext, &gpio_data); 362 | if (!NT_SUCCESS(status)) { 363 | return status; 364 | } 365 | pDevice->DevicePoweredOn = TRUE; 366 | 367 | return status; 368 | } 369 | 370 | NTSTATUS 371 | OnD0Exit( 372 | _In_ WDFDEVICE FxDevice, 373 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 374 | ) 375 | /*++ 376 | 377 | Routine Description: 378 | 379 | This routine destroys objects needed by the driver. 380 | 381 | Arguments: 382 | 383 | FxDevice - a handle to the framework device object 384 | FxPreviousState - previous power state 385 | 386 | Return Value: 387 | 388 | Status 389 | 390 | --*/ 391 | { 392 | UNREFERENCED_PARAMETER(FxPreviousState); 393 | 394 | PMAXM_CONTEXT pDevice = GetDeviceContext(FxDevice); 395 | NTSTATUS status = STATUS_SUCCESS; 396 | 397 | unsigned char gpio_data; 398 | gpio_data = 0; 399 | status = GpioWriteDataSynchronously(&pDevice->SdmodeGpioContext, &gpio_data); 400 | if (!NT_SUCCESS(status)) { 401 | return status; 402 | } 403 | pDevice->DevicePoweredOn = FALSE; 404 | 405 | return STATUS_SUCCESS; 406 | } 407 | 408 | NTSTATUS 409 | MaxmEvtDeviceAdd( 410 | IN WDFDRIVER Driver, 411 | IN PWDFDEVICE_INIT DeviceInit 412 | ) 413 | { 414 | NTSTATUS status = STATUS_SUCCESS; 415 | WDF_IO_QUEUE_CONFIG queueConfig; 416 | WDF_OBJECT_ATTRIBUTES attributes; 417 | WDFDEVICE device; 418 | WDFQUEUE queue; 419 | PMAXM_CONTEXT devContext; 420 | 421 | UNREFERENCED_PARAMETER(Driver); 422 | 423 | PAGED_CODE(); 424 | 425 | MaxmPrint(DEBUG_LEVEL_INFO, DBG_PNP, 426 | "MaxmEvtDeviceAdd called\n"); 427 | 428 | { 429 | WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; 430 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); 431 | 432 | pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 433 | pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 434 | pnpCallbacks.EvtDeviceSelfManagedIoInit = OnSelfManagedIoInit; 435 | pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; 436 | pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; 437 | 438 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); 439 | } 440 | 441 | // 442 | // Setup the device context 443 | // 444 | 445 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, MAXM_CONTEXT); 446 | 447 | // 448 | // Create a framework device object.This call will in turn create 449 | // a WDM device object, attach to the lower stack, and set the 450 | // appropriate flags and attributes. 451 | // 452 | 453 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 454 | 455 | if (!NT_SUCCESS(status)) 456 | { 457 | MaxmPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 458 | "WdfDeviceCreate failed with status code 0x%x\n", status); 459 | 460 | return status; 461 | } 462 | 463 | { 464 | WDF_DEVICE_STATE deviceState; 465 | WDF_DEVICE_STATE_INIT(&deviceState); 466 | 467 | deviceState.NotDisableable = WdfFalse; 468 | WdfDeviceSetDeviceState(device, &deviceState); 469 | } 470 | 471 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); 472 | 473 | queueConfig.EvtIoInternalDeviceControl = MaxmEvtInternalDeviceControl; 474 | 475 | status = WdfIoQueueCreate(device, 476 | &queueConfig, 477 | WDF_NO_OBJECT_ATTRIBUTES, 478 | &queue 479 | ); 480 | 481 | if (!NT_SUCCESS(status)) 482 | { 483 | MaxmPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 484 | "WdfIoQueueCreate failed 0x%x\n", status); 485 | 486 | return status; 487 | } 488 | 489 | // 490 | // Create manual I/O queue to take care of hid report read requests 491 | // 492 | 493 | devContext = GetDeviceContext(device); 494 | 495 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 496 | 497 | queueConfig.PowerManaged = WdfTrue; 498 | 499 | status = WdfIoQueueCreate(device, 500 | &queueConfig, 501 | WDF_NO_OBJECT_ATTRIBUTES, 502 | &devContext->ReportQueue 503 | ); 504 | 505 | if (!NT_SUCCESS(status)) 506 | { 507 | MaxmPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 508 | "WdfIoQueueCreate failed 0x%x\n", status); 509 | 510 | return status; 511 | } 512 | 513 | devContext->FxDevice = device; 514 | 515 | WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS IdleSettings; 516 | 517 | WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&IdleSettings, IdleCannotWakeFromS0); 518 | IdleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; 519 | IdleSettings.IdleTimeout = 1000; 520 | IdleSettings.Enabled = WdfTrue; 521 | 522 | WdfDeviceAssignS0IdleSettings(devContext->FxDevice, &IdleSettings); 523 | 524 | return status; 525 | } 526 | 527 | VOID 528 | MaxmEvtInternalDeviceControl( 529 | IN WDFQUEUE Queue, 530 | IN WDFREQUEST Request, 531 | IN size_t OutputBufferLength, 532 | IN size_t InputBufferLength, 533 | IN ULONG IoControlCode 534 | ) 535 | { 536 | NTSTATUS status = STATUS_SUCCESS; 537 | WDFDEVICE device; 538 | PMAXM_CONTEXT devContext; 539 | 540 | UNREFERENCED_PARAMETER(OutputBufferLength); 541 | UNREFERENCED_PARAMETER(InputBufferLength); 542 | 543 | device = WdfIoQueueGetDevice(Queue); 544 | devContext = GetDeviceContext(device); 545 | 546 | switch (IoControlCode) 547 | { 548 | default: 549 | status = STATUS_NOT_SUPPORTED; 550 | break; 551 | } 552 | 553 | WdfRequestComplete(Request, status); 554 | 555 | return; 556 | } 557 | -------------------------------------------------------------------------------- /max98357a/spb.cpp: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | spb.c 8 | 9 | Abstract: 10 | 11 | Contains all I2C-specific functionality 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #include "internal.h" 22 | #include "hiddevice.h" 23 | #include "spb.h" 24 | 25 | static ULONG ElanPrintDebugLevel = 100; 26 | static ULONG ElanPrintDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 27 | 28 | NTSTATUS 29 | SpbDoWriteDataSynchronously16( 30 | IN SPB_CONTEXT *SpbContext, 31 | IN UINT16 Address, 32 | IN PVOID Data, 33 | IN ULONG Length 34 | ) 35 | /*++ 36 | 37 | Routine Description: 38 | 39 | This helper routine abstracts creating and sending an I/O 40 | request (I2C Write) to the Spb I/O target. 41 | 42 | Arguments: 43 | 44 | SpbContext - Pointer to the current device context 45 | Address - The I2C register address to write to 46 | Data - A buffer to receive the data at at the above address 47 | Length - The amount of data to be read from the above address 48 | 49 | Return Value: 50 | 51 | NTSTATUS Status indicating success or failure 52 | 53 | --*/ 54 | { 55 | PUCHAR buffer; 56 | ULONG length; 57 | WDFMEMORY memory; 58 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 59 | NTSTATUS status; 60 | 61 | // 62 | // The address pointer and data buffer must be combined 63 | // into one contiguous buffer representing the write transaction. 64 | // 65 | length = Length + 2; 66 | memory = NULL; 67 | 68 | if (length > DEFAULT_SPB_BUFFER_SIZE) 69 | { 70 | status = WdfMemoryCreate( 71 | WDF_NO_OBJECT_ATTRIBUTES, 72 | NonPagedPool, 73 | CYAPA_POOL_TAG, 74 | length, 75 | &memory, 76 | (PVOID *)&buffer); 77 | 78 | if (!NT_SUCCESS(status)) 79 | { 80 | ElanPrint( 81 | DEBUG_LEVEL_ERROR, 82 | DBG_IOCTL, 83 | "Error allocating memory for Spb write - %!STATUS!", 84 | status); 85 | goto exit; 86 | } 87 | 88 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 89 | &memoryDescriptor, 90 | memory, 91 | NULL); 92 | } 93 | else 94 | { 95 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 96 | 97 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 98 | &memoryDescriptor, 99 | (PVOID)buffer, 100 | length); 101 | } 102 | 103 | UINT16 AddressBuffer[] = { 104 | Address 105 | }; 106 | 107 | // 108 | // Transaction starts by specifying the address bytes 109 | // 110 | RtlCopyMemory(buffer, (UCHAR *)&AddressBuffer, sizeof(AddressBuffer)); 111 | 112 | // 113 | // Address is followed by the data payload 114 | // 115 | RtlCopyMemory((buffer + sizeof(AddressBuffer)), Data, length - sizeof(AddressBuffer)); 116 | 117 | status = WdfIoTargetSendWriteSynchronously( 118 | SpbContext->SpbIoTarget, 119 | NULL, 120 | &memoryDescriptor, 121 | NULL, 122 | NULL, 123 | NULL); 124 | 125 | if (!NT_SUCCESS(status)) 126 | { 127 | ElanPrint( 128 | DEBUG_LEVEL_ERROR, 129 | DBG_IOCTL, 130 | "Error writing to Spb - %!STATUS!", 131 | status); 132 | goto exit; 133 | } 134 | 135 | exit: 136 | 137 | if (NULL != memory) 138 | { 139 | WdfObjectDelete(memory); 140 | } 141 | 142 | return status; 143 | } 144 | 145 | NTSTATUS 146 | SpbDoWriteDataSynchronously( 147 | IN SPB_CONTEXT *SpbContext, 148 | IN UCHAR Address, 149 | IN PVOID Data, 150 | IN ULONG Length 151 | ) 152 | /*++ 153 | 154 | Routine Description: 155 | 156 | This helper routine abstracts creating and sending an I/O 157 | request (I2C Write) to the Spb I/O target. 158 | 159 | Arguments: 160 | 161 | SpbContext - Pointer to the current device context 162 | Address - The I2C register address to write to 163 | Data - A buffer to receive the data at at the above address 164 | Length - The amount of data to be read from the above address 165 | 166 | Return Value: 167 | 168 | NTSTATUS Status indicating success or failure 169 | 170 | --*/ 171 | { 172 | PUCHAR buffer; 173 | ULONG length; 174 | WDFMEMORY memory; 175 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 176 | NTSTATUS status; 177 | 178 | // 179 | // The address pointer and data buffer must be combined 180 | // into one contiguous buffer representing the write transaction. 181 | // 182 | length = Length + 1; 183 | memory = NULL; 184 | 185 | if (length > DEFAULT_SPB_BUFFER_SIZE) 186 | { 187 | status = WdfMemoryCreate( 188 | WDF_NO_OBJECT_ATTRIBUTES, 189 | NonPagedPool, 190 | CYAPA_POOL_TAG, 191 | length, 192 | &memory, 193 | (PVOID *)&buffer); 194 | 195 | if (!NT_SUCCESS(status)) 196 | { 197 | ElanPrint( 198 | DEBUG_LEVEL_ERROR, 199 | DBG_IOCTL, 200 | "Error allocating memory for Spb write - %!STATUS!", 201 | status); 202 | goto exit; 203 | } 204 | 205 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 206 | &memoryDescriptor, 207 | memory, 208 | NULL); 209 | } 210 | else 211 | { 212 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 213 | 214 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 215 | &memoryDescriptor, 216 | (PVOID)buffer, 217 | length); 218 | } 219 | 220 | // 221 | // Transaction starts by specifying the address bytes 222 | // 223 | RtlCopyMemory(buffer, &Address, sizeof(Address)); 224 | 225 | // 226 | // Address is followed by the data payload 227 | // 228 | RtlCopyMemory((buffer + sizeof(Address)), Data, length - sizeof(Address)); 229 | 230 | status = WdfIoTargetSendWriteSynchronously( 231 | SpbContext->SpbIoTarget, 232 | NULL, 233 | &memoryDescriptor, 234 | NULL, 235 | NULL, 236 | NULL); 237 | 238 | if (!NT_SUCCESS(status)) 239 | { 240 | ElanPrint( 241 | DEBUG_LEVEL_ERROR, 242 | DBG_IOCTL, 243 | "Error writing to Spb - %!STATUS!", 244 | status); 245 | goto exit; 246 | } 247 | 248 | exit: 249 | 250 | if (NULL != memory) 251 | { 252 | WdfObjectDelete(memory); 253 | } 254 | 255 | return status; 256 | } 257 | 258 | NTSTATUS 259 | SpbWriteDataSynchronously( 260 | IN SPB_CONTEXT *SpbContext, 261 | IN UCHAR Address, 262 | IN PVOID Data, 263 | IN ULONG Length 264 | ) 265 | /*++ 266 | 267 | Routine Description: 268 | 269 | This routine abstracts creating and sending an I/O 270 | request (I2C Write) to the Spb I/O target and utilizes 271 | a helper routine to do work inside of locked code. 272 | 273 | Arguments: 274 | 275 | SpbContext - Pointer to the current device context 276 | Address - The I2C register address to write to 277 | Data - A buffer to receive the data at at the above address 278 | Length - The amount of data to be read from the above address 279 | 280 | Return Value: 281 | 282 | NTSTATUS Status indicating success or failure 283 | 284 | --*/ 285 | { 286 | NTSTATUS status; 287 | 288 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 289 | 290 | status = SpbDoWriteDataSynchronously( 291 | SpbContext, 292 | Address, 293 | Data, 294 | Length); 295 | 296 | WdfWaitLockRelease(SpbContext->SpbLock); 297 | 298 | return status; 299 | } 300 | 301 | NTSTATUS 302 | SpbWriteDataSynchronously16( 303 | IN SPB_CONTEXT *SpbContext, 304 | IN UINT16 Address, 305 | IN PVOID Data, 306 | IN ULONG Length 307 | ) 308 | /*++ 309 | 310 | Routine Description: 311 | 312 | This routine abstracts creating and sending an I/O 313 | request (I2C Write) to the Spb I/O target and utilizes 314 | a helper routine to do work inside of locked code. 315 | 316 | Arguments: 317 | 318 | SpbContext - Pointer to the current device context 319 | Address - The I2C register address to write to 320 | Data - A buffer to receive the data at at the above address 321 | Length - The amount of data to be read from the above address 322 | 323 | Return Value: 324 | 325 | NTSTATUS Status indicating success or failure 326 | 327 | --*/ 328 | { 329 | NTSTATUS status; 330 | 331 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 332 | 333 | status = SpbDoWriteDataSynchronously16( 334 | SpbContext, 335 | Address, 336 | Data, 337 | Length); 338 | 339 | WdfWaitLockRelease(SpbContext->SpbLock); 340 | 341 | return status; 342 | } 343 | 344 | NTSTATUS 345 | SpbReadDataSynchronously( 346 | _In_ SPB_CONTEXT *SpbContext, 347 | _In_ UCHAR Address, 348 | _In_reads_bytes_(Length) PVOID Data, 349 | _In_ ULONG Length 350 | ) 351 | /*++ 352 | 353 | Routine Description: 354 | 355 | This helper routine abstracts creating and sending an I/O 356 | request (I2C Read) to the Spb I/O target. 357 | 358 | Arguments: 359 | 360 | SpbContext - Pointer to the current device context 361 | Address - The I2C register address to read from 362 | Data - A buffer to receive the data at at the above address 363 | Length - The amount of data to be read from the above address 364 | 365 | Return Value: 366 | 367 | NTSTATUS Status indicating success or failure 368 | 369 | --*/ 370 | { 371 | PUCHAR buffer; 372 | WDFMEMORY memory; 373 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 374 | NTSTATUS status; 375 | ULONG_PTR bytesRead; 376 | 377 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 378 | 379 | memory = NULL; 380 | status = STATUS_INVALID_PARAMETER; 381 | bytesRead = 0; 382 | 383 | // 384 | // Read transactions start by writing an address pointer 385 | // 386 | status = SpbDoWriteDataSynchronously( 387 | SpbContext, 388 | Address, 389 | NULL, 390 | 0); 391 | 392 | if (!NT_SUCCESS(status)) 393 | { 394 | ElanPrint( 395 | DEBUG_LEVEL_ERROR, 396 | DBG_IOCTL, 397 | "Error setting address pointer for Spb read - %!STATUS!", 398 | status); 399 | goto exit; 400 | } 401 | 402 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 403 | { 404 | status = WdfMemoryCreate( 405 | WDF_NO_OBJECT_ATTRIBUTES, 406 | NonPagedPool, 407 | CYAPA_POOL_TAG, 408 | Length, 409 | &memory, 410 | (PVOID *)&buffer); 411 | 412 | if (!NT_SUCCESS(status)) 413 | { 414 | ElanPrint( 415 | DEBUG_LEVEL_ERROR, 416 | DBG_IOCTL, 417 | "Error allocating memory for Spb read - %!STATUS!", 418 | status); 419 | goto exit; 420 | } 421 | 422 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 423 | &memoryDescriptor, 424 | memory, 425 | NULL); 426 | } 427 | else 428 | { 429 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 430 | 431 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 432 | &memoryDescriptor, 433 | (PVOID)buffer, 434 | Length); 435 | } 436 | 437 | 438 | status = WdfIoTargetSendReadSynchronously( 439 | SpbContext->SpbIoTarget, 440 | NULL, 441 | &memoryDescriptor, 442 | NULL, 443 | NULL, 444 | &bytesRead); 445 | 446 | if (!NT_SUCCESS(status) || 447 | bytesRead != Length) 448 | { 449 | ElanPrint( 450 | DEBUG_LEVEL_ERROR, 451 | DBG_IOCTL, 452 | "Error reading from Spb - %!STATUS!", 453 | status); 454 | goto exit; 455 | } 456 | 457 | // 458 | // Copy back to the caller's buffer 459 | // 460 | RtlCopyMemory(Data, buffer, Length); 461 | 462 | exit: 463 | if (NULL != memory) 464 | { 465 | WdfObjectDelete(memory); 466 | } 467 | 468 | WdfWaitLockRelease(SpbContext->SpbLock); 469 | 470 | return status; 471 | } 472 | 473 | NTSTATUS 474 | SpbReadDataSynchronously16( 475 | _In_ SPB_CONTEXT *SpbContext, 476 | _In_ UINT16 Address, 477 | _In_reads_bytes_(Length) PVOID Data, 478 | _In_ ULONG Length 479 | ) 480 | /*++ 481 | 482 | Routine Description: 483 | 484 | This helper routine abstracts creating and sending an I/O 485 | request (I2C Read) to the Spb I/O target. 486 | 487 | Arguments: 488 | 489 | SpbContext - Pointer to the current device context 490 | Address - The I2C register address to read from 491 | Data - A buffer to receive the data at at the above address 492 | Length - The amount of data to be read from the above address 493 | 494 | Return Value: 495 | 496 | NTSTATUS Status indicating success or failure 497 | 498 | --*/ 499 | { 500 | PUCHAR buffer; 501 | WDFMEMORY memory; 502 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 503 | NTSTATUS status; 504 | ULONG_PTR bytesRead; 505 | 506 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 507 | 508 | memory = NULL; 509 | status = STATUS_INVALID_PARAMETER; 510 | bytesRead = 0; 511 | 512 | // 513 | // Read transactions start by writing an address pointer 514 | // 515 | status = SpbDoWriteDataSynchronously16( 516 | SpbContext, 517 | Address, 518 | NULL, 519 | 0); 520 | 521 | if (!NT_SUCCESS(status)) 522 | { 523 | ElanPrint( 524 | DEBUG_LEVEL_ERROR, 525 | DBG_IOCTL, 526 | "Error setting address pointer for Spb read - %!STATUS!", 527 | status); 528 | goto exit; 529 | } 530 | 531 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 532 | { 533 | status = WdfMemoryCreate( 534 | WDF_NO_OBJECT_ATTRIBUTES, 535 | NonPagedPool, 536 | CYAPA_POOL_TAG, 537 | Length, 538 | &memory, 539 | (PVOID *)&buffer); 540 | 541 | if (!NT_SUCCESS(status)) 542 | { 543 | ElanPrint( 544 | DEBUG_LEVEL_ERROR, 545 | DBG_IOCTL, 546 | "Error allocating memory for Spb read - %!STATUS!", 547 | status); 548 | goto exit; 549 | } 550 | 551 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 552 | &memoryDescriptor, 553 | memory, 554 | NULL); 555 | } 556 | else 557 | { 558 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 559 | 560 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 561 | &memoryDescriptor, 562 | (PVOID)buffer, 563 | Length); 564 | } 565 | 566 | 567 | status = WdfIoTargetSendReadSynchronously( 568 | SpbContext->SpbIoTarget, 569 | NULL, 570 | &memoryDescriptor, 571 | NULL, 572 | NULL, 573 | &bytesRead); 574 | 575 | if (!NT_SUCCESS(status) || 576 | bytesRead != Length) 577 | { 578 | ElanPrint( 579 | DEBUG_LEVEL_ERROR, 580 | DBG_IOCTL, 581 | "Error reading from Spb - %!STATUS!", 582 | status); 583 | goto exit; 584 | } 585 | 586 | // 587 | // Copy back to the caller's buffer 588 | // 589 | RtlCopyMemory(Data, buffer, Length); 590 | 591 | exit: 592 | if (NULL != memory) 593 | { 594 | WdfObjectDelete(memory); 595 | } 596 | 597 | WdfWaitLockRelease(SpbContext->SpbLock); 598 | 599 | return status; 600 | } 601 | 602 | VOID 603 | SpbTargetDeinitialize( 604 | IN WDFDEVICE FxDevice, 605 | IN SPB_CONTEXT *SpbContext 606 | ) 607 | /*++ 608 | 609 | Routine Description: 610 | 611 | This helper routine is used to free any members added to the SPB_CONTEXT, 612 | note the SPB I/O target is parented to the device and will be 613 | closed and free'd when the device is removed. 614 | 615 | Arguments: 616 | 617 | FxDevice - Handle to the framework device object 618 | SpbContext - Pointer to the current device context 619 | 620 | Return Value: 621 | 622 | NTSTATUS Status indicating success or failure 623 | 624 | --*/ 625 | { 626 | UNREFERENCED_PARAMETER(FxDevice); 627 | UNREFERENCED_PARAMETER(SpbContext); 628 | 629 | // 630 | // Free any SPB_CONTEXT allocations here 631 | // 632 | if (SpbContext->SpbLock != NULL) 633 | { 634 | WdfObjectDelete(SpbContext->SpbLock); 635 | } 636 | 637 | if (SpbContext->ReadMemory != NULL) 638 | { 639 | WdfObjectDelete(SpbContext->ReadMemory); 640 | } 641 | 642 | if (SpbContext->WriteMemory != NULL) 643 | { 644 | WdfObjectDelete(SpbContext->WriteMemory); 645 | } 646 | } 647 | 648 | NTSTATUS 649 | SpbTargetInitialize( 650 | IN WDFDEVICE FxDevice, 651 | IN SPB_CONTEXT *SpbContext 652 | ) 653 | /*++ 654 | 655 | Routine Description: 656 | 657 | This helper routine opens the Spb I/O target and 658 | initializes a request object used for the lifetime 659 | of communication between this driver and Spb. 660 | 661 | Arguments: 662 | 663 | FxDevice - Handle to the framework device object 664 | SpbContext - Pointer to the current device context 665 | 666 | Return Value: 667 | 668 | NTSTATUS Status indicating success or failure 669 | 670 | --*/ 671 | { 672 | WDF_OBJECT_ATTRIBUTES objectAttributes; 673 | WDF_IO_TARGET_OPEN_PARAMS openParams; 674 | UNICODE_STRING spbDeviceName; 675 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 676 | NTSTATUS status; 677 | 678 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 679 | objectAttributes.ParentObject = FxDevice; 680 | 681 | status = WdfIoTargetCreate( 682 | FxDevice, 683 | &objectAttributes, 684 | &SpbContext->SpbIoTarget); 685 | 686 | if (!NT_SUCCESS(status)) 687 | { 688 | ElanPrint( 689 | DEBUG_LEVEL_ERROR, 690 | DBG_IOCTL, 691 | "Error creating IoTarget object - %!STATUS!", 692 | status); 693 | 694 | WdfObjectDelete(SpbContext->SpbIoTarget); 695 | goto exit; 696 | } 697 | 698 | RtlInitEmptyUnicodeString( 699 | &spbDeviceName, 700 | spbDeviceNameBuffer, 701 | sizeof(spbDeviceNameBuffer)); 702 | 703 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 704 | &spbDeviceName, 705 | SpbContext->I2cResHubId.LowPart, 706 | SpbContext->I2cResHubId.HighPart); 707 | 708 | if (!NT_SUCCESS(status)) 709 | { 710 | ElanPrint( 711 | DEBUG_LEVEL_ERROR, 712 | DBG_IOCTL, 713 | "Error creating Spb resource hub path string - %!STATUS!", 714 | status); 715 | goto exit; 716 | } 717 | 718 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 719 | &openParams, 720 | &spbDeviceName, 721 | (GENERIC_READ | GENERIC_WRITE)); 722 | 723 | openParams.ShareAccess = 0; 724 | openParams.CreateDisposition = FILE_OPEN; 725 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 726 | 727 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 728 | 729 | if (!NT_SUCCESS(status)) 730 | { 731 | ElanPrint( 732 | DEBUG_LEVEL_ERROR, 733 | DBG_IOCTL, 734 | "Error opening Spb target for communication - %!STATUS!", 735 | status); 736 | goto exit; 737 | } 738 | 739 | // 740 | // Allocate some fixed-size buffers from NonPagedPool for typical 741 | // Spb transaction sizes to avoid pool fragmentation in most cases 742 | // 743 | status = WdfMemoryCreate( 744 | WDF_NO_OBJECT_ATTRIBUTES, 745 | NonPagedPool, 746 | CYAPA_POOL_TAG, 747 | DEFAULT_SPB_BUFFER_SIZE, 748 | &SpbContext->WriteMemory, 749 | NULL); 750 | 751 | if (!NT_SUCCESS(status)) 752 | { 753 | ElanPrint( 754 | DEBUG_LEVEL_ERROR, 755 | DBG_IOCTL, 756 | "Error allocating default memory for Spb write - %!STATUS!", 757 | status); 758 | goto exit; 759 | } 760 | 761 | status = WdfMemoryCreate( 762 | WDF_NO_OBJECT_ATTRIBUTES, 763 | NonPagedPool, 764 | CYAPA_POOL_TAG, 765 | DEFAULT_SPB_BUFFER_SIZE, 766 | &SpbContext->ReadMemory, 767 | NULL); 768 | 769 | if (!NT_SUCCESS(status)) 770 | { 771 | ElanPrint( 772 | DEBUG_LEVEL_ERROR, 773 | DBG_IOCTL, 774 | "Error allocating default memory for Spb read - %!STATUS!", 775 | status); 776 | goto exit; 777 | } 778 | 779 | // 780 | // Allocate a waitlock to guard access to the default buffers 781 | // 782 | status = WdfWaitLockCreate( 783 | WDF_NO_OBJECT_ATTRIBUTES, 784 | &SpbContext->SpbLock); 785 | 786 | if (!NT_SUCCESS(status)) 787 | { 788 | ElanPrint( 789 | DEBUG_LEVEL_ERROR, 790 | DBG_IOCTL, 791 | "Error creating Spb Waitlock - %!STATUS!", 792 | status); 793 | goto exit; 794 | } 795 | 796 | exit: 797 | 798 | if (!NT_SUCCESS(status)) 799 | { 800 | SpbTargetDeinitialize(FxDevice, SpbContext); 801 | } 802 | 803 | return status; 804 | } --------------------------------------------------------------------------------