From ecb5424b97ea7bd66927c7cdf5cd8d2cb8a6ffca Mon Sep 17 00:00:00 2001 From: CoolStar Date: Fri, 24 Nov 2023 15:45:11 -0800 Subject: [PATCH] Add ES8323/ES8388 codec driver (#12) * Add ES8323/ES8388 codec driver --- build/RockchipDrivers.sln | 8 + drivers/audio/codecs/es8323/LICENSE.txt | 13 + drivers/audio/codecs/es8323/README.md | 8 + drivers/audio/codecs/es8323/driver.h | 98 +++ drivers/audio/codecs/es8323/es8323.c | 797 ++++++++++++++++++ drivers/audio/codecs/es8323/es8323.h | 144 ++++ drivers/audio/codecs/es8323/es8323.inx | 78 ++ drivers/audio/codecs/es8323/es8323.rc | 41 + drivers/audio/codecs/es8323/es8323.vcxproj | 104 +++ .../codecs/es8323/es8323.vcxproj.Filters | 50 ++ drivers/audio/codecs/es8323/spb.c | 493 +++++++++++ drivers/audio/codecs/es8323/spb.h | 68 ++ 12 files changed, 1902 insertions(+) create mode 100644 drivers/audio/codecs/es8323/LICENSE.txt create mode 100644 drivers/audio/codecs/es8323/README.md create mode 100644 drivers/audio/codecs/es8323/driver.h create mode 100644 drivers/audio/codecs/es8323/es8323.c create mode 100644 drivers/audio/codecs/es8323/es8323.h create mode 100644 drivers/audio/codecs/es8323/es8323.inx create mode 100644 drivers/audio/codecs/es8323/es8323.rc create mode 100644 drivers/audio/codecs/es8323/es8323.vcxproj create mode 100644 drivers/audio/codecs/es8323/es8323.vcxproj.Filters create mode 100644 drivers/audio/codecs/es8323/spb.c create mode 100644 drivers/audio/codecs/es8323/spb.h diff --git a/build/RockchipDrivers.sln b/build/RockchipDrivers.sln index 0fa6bdb..29d2de2 100644 --- a/build/RockchipDrivers.sln +++ b/build/RockchipDrivers.sln @@ -11,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rk3xgpio", "..\drivers\gpio EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pl330dma", "..\drivers\dma\pl330dma\pl330.vcxproj", "{58434B4F-EE73-4D1E-A78D-9FEC5CEC83C7}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "es8323", "..\drivers\audio\codecs\es8323\es8323.vcxproj", "{15D34676-980D-4406-8C05-AB95AA5B43CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -41,6 +43,12 @@ Global {58434B4F-EE73-4D1E-A78D-9FEC5CEC83C7}.Release|ARM64.ActiveCfg = Release|ARM64 {58434B4F-EE73-4D1E-A78D-9FEC5CEC83C7}.Release|ARM64.Build.0 = Release|ARM64 {58434B4F-EE73-4D1E-A78D-9FEC5CEC83C7}.Release|ARM64.Deploy.0 = Release|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Debug|ARM64.Build.0 = Debug|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Release|ARM64.ActiveCfg = Release|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Release|ARM64.Build.0 = Release|ARM64 + {15D34676-980D-4406-8C05-AB95AA5B43CA}.Release|ARM64.Deploy.0 = Release|ARM64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/drivers/audio/codecs/es8323/LICENSE.txt b/drivers/audio/codecs/es8323/LICENSE.txt new file mode 100644 index 0000000..3880e06 --- /dev/null +++ b/drivers/audio/codecs/es8323/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2023 CoolStar + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/README.md b/drivers/audio/codecs/es8323/README.md new file mode 100644 index 0000000..6722bfa --- /dev/null +++ b/drivers/audio/codecs/es8323/README.md @@ -0,0 +1,8 @@ +# es8323 +Everest 8323 I2C Codec driver + +Supports: +* 3.5mm output +* 3.5mm input + +Tested on Orange Pi 5 \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/driver.h b/drivers/audio/codecs/es8323/driver.h new file mode 100644 index 0000000..c0c0092 --- /dev/null +++ b/drivers/audio/codecs/es8323/driver.h @@ -0,0 +1,98 @@ +#if !defined(_ES8323_H_) +#define _ES8323_H_ + +#pragma warning(disable:4200) // suppress nameless struct/union warning +#pragma warning(disable:4201) // suppress nameless struct/union warning +#pragma warning(disable:4214) // suppress bit field types other than int warning +#include +#include + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) +#include + +#pragma warning(disable:4201) // suppress nameless struct/union warning +#pragma warning(disable:4214) // suppress bit field types other than int warning +#include + +#include "es8323.h" +#include "spb.h" + +// +// String definitions +// + +#define DRIVERNAME "es8323.sys: " + +#define ES8323_POOL_TAG (ULONG) '8323' +#define ES8323_HARDWARE_IDS L"CoolStar\\ES8323\0\0" +#define ES8323_HARDWARE_IDS_LENGTH sizeof(ES8323_HARDWARE_IDS) + +#define NTDEVICE_NAME_STRING L"\\Device\\ES8323" +#define SYMBOLIC_NAME_STRING L"\\DosDevices\\ES8323" + +#define true 1 +#define false 0 + +typedef struct _ES8323_CONTEXT +{ + + // + // Handle back to the WDFDEVICE + // + + WDFDEVICE FxDevice; + + WDFQUEUE ReportQueue; + + SPB_CONTEXT I2CContext; + + BOOLEAN ConnectInterrupt; + + WDFINTERRUPT Interrupt; + +} ES8323_CONTEXT, *PES8323_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ES8323_CONTEXT, GetDeviceContext) + +// +// Function definitions +// + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_UNLOAD Es8323DriverUnload; + +EVT_WDF_DRIVER_DEVICE_ADD Es8323EvtDeviceAdd; + +EVT_WDFDEVICE_WDM_IRP_PREPROCESS Es8323EvtWdmPreprocessMnQueryId; + +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL Es8323EvtInternalDeviceControl; + +// +// Helper macros +// + +#define DEBUG_LEVEL_ERROR 1 +#define DEBUG_LEVEL_INFO 2 +#define DEBUG_LEVEL_VERBOSE 3 + +#define DBG_INIT 1 +#define DBG_PNP 2 +#define DBG_IOCTL 4 + +#if 0 +#define Es8323Print(dbglevel, dbgcatagory, fmt, ...) { \ + if (Es8323DebugLevel >= dbglevel && \ + (Es8323DebugCatagories && dbgcatagory)) \ + { \ + DbgPrint(DRIVERNAME); \ + DbgPrint(fmt, __VA_ARGS__); \ + } \ +} +#else +#define Es8323Print(dbglevel, fmt, ...) { \ +} +#endif +#endif \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/es8323.c b/drivers/audio/codecs/es8323/es8323.c new file mode 100644 index 0000000..32bb219 --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.c @@ -0,0 +1,797 @@ +#define DESCRIPTOR_DEF +#include "driver.h" +#include "stdint.h" + +#define bool int +#define MS_IN_US 1000 + +static ULONG Es8323DebugLevel = 100; +static ULONG Es8323DebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; + +struct _coeff_div { + UINT32 mclk; + UINT32 rate; + UINT16 fs; + UINT8 sr : 4; + UINT8 usb : 1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + {2048000, 8000, 256, 0x2, 0x0}, + {4096000, 8000, 512, 0x4, 0x0}, + {12288000, 8000, 1536, 0xa, 0x0}, + {11289600, 8000, 1408, 0x9, 0x0}, + {18432000, 8000, 2304, 0xc, 0x0}, + {16934400, 8000, 2112, 0xb, 0x0}, + {12000000, 8000, 1500, 0xb, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x7, 0x0}, + {16934400, 11025, 1536, 0xa, 0x0}, + {12000000, 11025, 1088, 0x9, 0x1}, + + /* 16k */ + {4096000, 16000, 256, 0x2, 0x0}, + {8192000, 16000, 512, 0x4, 0x0}, + {12288000, 16000, 768, 0x6, 0x0}, + {18432000, 16000, 1152, 0x8, 0x0}, + {12000000, 16000, 750, 0x7, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x4, 0x0}, + {16934400, 22050, 768, 0x6, 0x0}, + {12000000, 22050, 544, 0x6, 0x1}, + + /* 32k */ + {8192000, 32000, 256, 0x2, 0x0}, + {16384000, 32000, 512, 0x4, 0x0}, + {12288000, 32000, 384, 0x3, 0x0}, + {18432000, 32000, 576, 0x5, 0x0}, + {12000000, 32000, 375, 0x4, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x2, 0x0}, + {16934400, 44100, 384, 0x3, 0x0}, + {12000000, 44100, 272, 0x3, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x2, 0x0}, + {18432000, 48000, 384, 0x3, 0x0}, + {12000000, 48000, 250, 0x2, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x0, 0x0}, + {16934400, 88200, 192, 0x1, 0x0}, + {12000000, 88200, 136, 0x1, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x0, 0x0}, + {18432000, 96000, 192, 0x1, 0x0}, + {12000000, 96000, 125, 0x0, 0x1}, +}; + +NTSTATUS +DriverEntry( +__in PDRIVER_OBJECT DriverObject, +__in PUNICODE_STRING RegistryPath +) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attributes; + + Es8323Print(DEBUG_LEVEL_INFO, DBG_INIT, + "Driver Entry\n"); + + WDF_DRIVER_CONFIG_INIT(&config, Es8323EvtDeviceAdd); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + // + // Create a framework driver object to represent our driver. + // + + status = WdfDriverCreate(DriverObject, + RegistryPath, + &attributes, + &config, + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status 0x%x\n", status); + } + + return status; +} + +void udelay(ULONG usec) { + LARGE_INTEGER Interval; + Interval.QuadPart = -10 * (LONGLONG)usec; + KeDelayExecutionThread(KernelMode, FALSE, &Interval); +} + +/* ES8288 has 8-bit register addresses, and 8-bit register data */ +struct es8323_init_reg { + uint8_t reg; + uint8_t val; +}; + +NTSTATUS es8323_reg_read( + _In_ PES8323_CONTEXT pDevice, + uint8_t reg, + uint8_t* data +) { + uint8_t raw_data = 0; + NTSTATUS status = SpbXferDataSynchronously(&pDevice->I2CContext, ®, sizeof(reg), &raw_data, sizeof(raw_data)); + *data = raw_data; + return status; +} + +NTSTATUS es8323_reg_write( + _In_ PES8323_CONTEXT pDevice, + uint8_t reg, + uint8_t data +) { + uint8_t buf[2]; + buf[0] = reg; + buf[1] = data; + return SpbWriteDataSynchronously(&pDevice->I2CContext, buf, sizeof(buf)); +} + +NTSTATUS es8323_reg_update( + _In_ PES8323_CONTEXT pDevice, + uint8_t reg, + uint8_t mask, + uint8_t val +) { + uint8_t tmp = 0, orig = 0; + + NTSTATUS status = es8323_reg_read(pDevice, reg, &orig); + if (!NT_SUCCESS(status)) { + return status; + } + + tmp = orig & ~mask; + tmp |= val & mask; + + if (tmp != orig) { + status = es8323_reg_write(pDevice, reg, tmp); + } + return status; +} + +/*static void debug_dump_regs(PES8323_CONTEXT pDevice) +{ + uint8_t i, reg_byte; + // Show all codec regs + for (i = 0; i <= ES8323_DACCONTROL30; i += 16) { + uint32_t regs[16]; + for (int j = 0; j < 16; j++) { + es8323_reg_read(pDevice, (uint8_t)(i + j), ®_byte); + regs[j] = reg_byte; + } + DbgPrint("%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n", i, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], + regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]); + } +}*/ + +NTSTATUS BOOTCODEC( + _In_ PES8323_CONTEXT pDevice + ) +{ + NTSTATUS status = 0; + + pDevice->ConnectInterrupt = false; + + Es8323Print(DEBUG_LEVEL_INFO, DBG_PNP, + "Initializing ES8323!\n"); + + //Reset + + es8323_reg_write(pDevice, ES8323_CONTROL1, 0x80); + es8323_reg_write(pDevice, ES8323_CONTROL1, 0x00); + + //Enable + + es8323_reg_write(pDevice, 0x01, 0x60); + es8323_reg_write(pDevice, 0x02, 0xF3); + es8323_reg_write(pDevice, 0x02, 0xF0); + es8323_reg_write(pDevice, 0x2B, 0x80); + es8323_reg_write(pDevice, 0x00, 0x36); + es8323_reg_write(pDevice, 0x08, 0x00); + es8323_reg_write(pDevice, 0x04, 0x00); + es8323_reg_write(pDevice, 0x06, 0xC3); + es8323_reg_write(pDevice, 0x19, 0x02); + es8323_reg_write(pDevice, 0x09, 0x00); + es8323_reg_write(pDevice, 0x0A, 0x00); + es8323_reg_write(pDevice, 0x0B, 0x02); + es8323_reg_write(pDevice, 0x0C, 0x4C); + es8323_reg_write(pDevice, 0x0D, 0x02); + es8323_reg_write(pDevice, 0x10, 0x00); + es8323_reg_write(pDevice, 0x11, 0x00); + es8323_reg_write(pDevice, 0x12, 0xea); + es8323_reg_write(pDevice, 0x13, 0xc0); + es8323_reg_write(pDevice, 0x14, 0x05); + es8323_reg_write(pDevice, 0x15, 0x06); + es8323_reg_write(pDevice, 0x16, 0x53); + + es8323_reg_write(pDevice, 0x17, 0x18); + es8323_reg_write(pDevice, 0x18, 0x02); + es8323_reg_write(pDevice, 0x1A, 0x00); + es8323_reg_write(pDevice, 0x1B, 0x00); + es8323_reg_write(pDevice, 0x27, 0xB8); + es8323_reg_write(pDevice, 0x2A, 0xB8); + es8323_reg_write(pDevice, 0x35, 0xA0); + + udelay(18000); + + es8323_reg_write(pDevice, 0x2E, 0x1E); + es8323_reg_write(pDevice, 0x2F, 0x1E); + es8323_reg_write(pDevice, 0x30, 0x1E); + es8323_reg_write(pDevice, 0x31, 0x1E); + es8323_reg_write(pDevice, 0x03, 0x09); + es8323_reg_write(pDevice, 0x02, 0x00); + + udelay(18000); + + es8323_reg_write(pDevice, 0x04, 0x3C); + + //standby / prepare bias + + es8323_reg_write(pDevice, ES8323_ANAVOLMANAG, 0x7C); + es8323_reg_write(pDevice, ES8323_CHIPLOPOW1, 0x00); + es8323_reg_write(pDevice, ES8323_CHIPLOPOW2, 0x00); + es8323_reg_write(pDevice, ES8323_CHIPPOWER, 0x00); + es8323_reg_write(pDevice, ES8323_ADCPOWER, 0x59); + + //Hw Params + + { + UINT32 coeff = 0x17; + UINT8 val; + es8323_reg_read(pDevice, ES8323_IFACE, &val); + UINT16 srate = val & 0x80; + es8323_reg_read(pDevice, ES8323_ADC_IFACE, &val); + UINT16 adciface = val & 0xE3; + es8323_reg_read(pDevice, ES8323_DAC_IFACE, &val); + UINT16 daciface = val & 0xC7; + + //16-bit + adciface |= 0x000C; + daciface |= 0x0018; + + es8323_reg_write(pDevice, ES8323_DAC_IFACE, daciface & 0xff); + es8323_reg_write(pDevice, ES8323_ADC_IFACE, adciface & 0xff); + + //coeff + es8323_reg_write(pDevice, ES8323_IFACE, srate & 0xff); + es8323_reg_write(pDevice, ES8323_ADCCONTROL5, + coeff_div[coeff].sr | + coeff_div[coeff].usb << 4); + es8323_reg_write(pDevice, ES8323_DACCONTROL2, + coeff_div[coeff].sr | + coeff_div[coeff].usb << 4); + } + + + es8323_reg_write(pDevice, ES8323_ADCPOWER, 0x09); + + //Set ALC Capture + es8323_reg_write(pDevice, ES8323_ADCCONTROL10, 0xfa); //max / min pga + es8323_reg_write(pDevice, ES8323_ADCCONTROL11, 0xf0); //target volume / hold time + es8323_reg_write(pDevice, ES8323_ADCCONTROL12, 0x05); //decay / attack time + es8323_reg_write(pDevice, ES8323_ADCCONTROL14, 0x4b); //threshold / ng switch + + es8323_reg_write(pDevice, ES8323_DACCONTROL7, 0x02); //dac stereo 3d + + //Output playback + es8323_reg_write(pDevice, ES8323_DACCONTROL16, 0x02); //maybe not needed? + + es8323_reg_write(pDevice, ES8323_DACCONTROL24, 0x21); //output 1 volume + es8323_reg_write(pDevice, ES8323_DACCONTROL25, 0x21); //output 1 volume + + es8323_reg_write(pDevice, ES8323_DACCONTROL26, 0x21); //output 2 volume + es8323_reg_write(pDevice, ES8323_DACCONTROL27, 0x21); //output 2 volume + + return status; +} + +NTSTATUS +OnPrepareHardware( +_In_ WDFDEVICE FxDevice, +_In_ WDFCMRESLIST FxResourcesRaw, +_In_ WDFCMRESLIST FxResourcesTranslated +) +/*++ + +Routine Description: + +This routine caches the SPB resource connection ID. + +Arguments: + +FxDevice - a handle to the framework device object +FxResourcesRaw - list of translated hardware resources that +the PnP manager has assigned to the device +FxResourcesTranslated - list of raw hardware resources that +the PnP manager has assigned to the device + +Return Value: + +Status + +--*/ +{ + PES8323_CONTEXT pDevice = GetDeviceContext(FxDevice); + BOOLEAN fSpbResourceFound = FALSE; + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + + UNREFERENCED_PARAMETER(FxResourcesRaw); + + // + // Parse the peripheral's resources. + // + + ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); + + for (ULONG i = 0; i < resourceCount; i++) + { + PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; + UCHAR Class; + UCHAR Type; + + pDescriptor = WdfCmResourceListGetDescriptor( + FxResourcesTranslated, i); + + switch (pDescriptor->Type) + { + case CmResourceTypeConnection: + // + // Look for I2C or SPI resource and save connection ID. + // + Class = pDescriptor->u.Connection.Class; + Type = pDescriptor->u.Connection.Type; + if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && + Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) + { + if (fSpbResourceFound == FALSE) + { + status = STATUS_SUCCESS; + pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; + pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; + fSpbResourceFound = TRUE; + } + else + { + } + } + break; + default: + // + // Ignoring all other resource types. + // + break; + } + } + + // + // An SPB resource is required. + // + + if (fSpbResourceFound == FALSE) + { + status = STATUS_NOT_FOUND; + return status; + } + + status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); + if (!NT_SUCCESS(status)) + { + return status; + } + + return status; +} + +NTSTATUS +OnReleaseHardware( +_In_ WDFDEVICE FxDevice, +_In_ WDFCMRESLIST FxResourcesTranslated +) +/*++ + +Routine Description: + +Arguments: + +FxDevice - a handle to the framework device object +FxResourcesTranslated - list of raw hardware resources that +the PnP manager has assigned to the device + +Return Value: + +Status + +--*/ +{ + PES8323_CONTEXT pDevice = GetDeviceContext(FxDevice); + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(FxResourcesTranslated); + + SpbTargetDeinitialize(FxDevice, &pDevice->I2CContext); + + return status; +} + +NTSTATUS +OnD0Entry( +_In_ WDFDEVICE FxDevice, +_In_ WDF_POWER_DEVICE_STATE FxPreviousState +) +/*++ + +Routine Description: + +This routine allocates objects needed by the driver. + +Arguments: + +FxDevice - a handle to the framework device object +FxPreviousState - previous power state + +Return Value: + +Status + +--*/ +{ + UNREFERENCED_PARAMETER(FxPreviousState); + + PES8323_CONTEXT pDevice = GetDeviceContext(FxDevice); + NTSTATUS status = STATUS_SUCCESS; + + BOOTCODEC(pDevice); + + return status; +} + +NTSTATUS +OnD0Exit( +_In_ WDFDEVICE FxDevice, +_In_ WDF_POWER_DEVICE_STATE FxPreviousState +) +/*++ + +Routine Description: + +This routine destroys objects needed by the driver. + +Arguments: + +FxDevice - a handle to the framework device object +FxPreviousState - previous power state + +Return Value: + +Status + +--*/ +{ + UNREFERENCED_PARAMETER(FxPreviousState); + + PES8323_CONTEXT pDevice = GetDeviceContext(FxDevice); + + es8323_reg_write(pDevice, ES8323_DACCONTROL3, 0x06); + es8323_reg_write(pDevice, ES8323_DACCONTROL26, 0x00); + es8323_reg_write(pDevice, ES8323_DACCONTROL27, 0x00); + es8323_reg_write(pDevice, ES8323_ADCPOWER, 0xFF); + es8323_reg_write(pDevice, ES8323_DACPOWER, 0xc0); + es8323_reg_write(pDevice, ES8323_CHIPPOWER, 0xF3); + es8323_reg_write(pDevice, ES8323_CONTROL1, 0x00); + es8323_reg_write(pDevice, ES8323_CONTROL2, 0x58); + es8323_reg_write(pDevice, ES8323_DACCONTROL21, 0x9c); + + pDevice->ConnectInterrupt = false; + + return STATUS_SUCCESS; +} + +BOOLEAN OnInterruptIsr( + WDFINTERRUPT Interrupt, + ULONG MessageID) { + UNREFERENCED_PARAMETER(Interrupt); + UNREFERENCED_PARAMETER(MessageID); + + //DbgPrint("Jack Interrupt!\n"); + return TRUE; +} + +NTSTATUS +Es8323EvtDeviceAdd( +IN WDFDRIVER Driver, +IN PWDFDEVICE_INIT DeviceInit +) +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDEVICE device; + WDF_INTERRUPT_CONFIG interruptConfig; + WDFQUEUE queue; + UCHAR minorFunction; + PES8323_CONTEXT devContext; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + Es8323Print(DEBUG_LEVEL_INFO, DBG_PNP, + "Es8323EvtDeviceAdd called\n"); + + { + WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); + + pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; + pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; + pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; + pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); + } + + // + // Because we are a virtual device the root enumerator would just put null values + // in response to IRP_MN_QUERY_ID. Lets override that. + // + + minorFunction = IRP_MN_QUERY_ID; + + status = WdfDeviceInitAssignWdmIrpPreprocessCallback( + DeviceInit, + Es8323EvtWdmPreprocessMnQueryId, + IRP_MJ_PNP, + &minorFunction, + 1 + ); + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_PNP, + "WdfDeviceInitAssignWdmIrpPreprocessCallback failed Status 0x%x\n", status); + + return status; + } + + // + // Setup the device context + // + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, ES8323_CONTEXT); + + // + // Create a framework device object.This call will in turn create + // a WDM device object, attach to the lower stack, and set the + // appropriate flags and attributes. + // + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with status code 0x%x\n", status); + + return status; + } + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); + + queueConfig.EvtIoInternalDeviceControl = Es8323EvtInternalDeviceControl; + + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue + ); + + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + + return status; + } + + // + // Create manual I/O queue to take care of hid report read requests + // + + devContext = GetDeviceContext(device); + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); + + queueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &devContext->ReportQueue + ); + + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + + return status; + } + + // + // Create an interrupt object for hardware notifications + // + WDF_INTERRUPT_CONFIG_INIT( + &interruptConfig, + OnInterruptIsr, + NULL); + interruptConfig.PassiveHandling = TRUE; + + status = WdfInterruptCreate( + device, + &interruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &devContext->Interrupt); + + if (!NT_SUCCESS(status)) + { + Es8323Print(DEBUG_LEVEL_ERROR, DBG_PNP, + "Error creating WDF interrupt object - %!STATUS!", + status); + + return status; + } + + devContext->FxDevice = device; + + return status; +} + +NTSTATUS +Es8323EvtWdmPreprocessMnQueryId( +WDFDEVICE Device, +PIRP Irp +) +{ + NTSTATUS status; + PIO_STACK_LOCATION IrpStack, previousSp; + PDEVICE_OBJECT DeviceObject; + PWCHAR buffer; + + PAGED_CODE(); + + // + // Get a pointer to the current location in the Irp + // + + IrpStack = IoGetCurrentIrpStackLocation(Irp); + + // + // Get the device object + // + DeviceObject = WdfDeviceWdmGetDeviceObject(Device); + + + Es8323Print(DEBUG_LEVEL_VERBOSE, DBG_PNP, + "Es8323EvtWdmPreprocessMnQueryId Entry\n"); + + // + // This check is required to filter out QUERY_IDs forwarded + // by the HIDCLASS for the parent FDO. These IDs are sent + // by PNP manager for the parent FDO if you root-enumerate this driver. + // + previousSp = ((PIO_STACK_LOCATION)((UCHAR *)(IrpStack)+ + sizeof(IO_STACK_LOCATION))); + + if (previousSp->DeviceObject == DeviceObject) + { + // + // Filtering out this basically prevents the Found New Hardware + // popup for the root-enumerated Es8323 on reboot. + // + status = Irp->IoStatus.Status; + } + else + { + switch (IrpStack->Parameters.QueryId.IdType) + { + case BusQueryDeviceID: + case BusQueryHardwareIDs: + // + // HIDClass is asking for child deviceid & hardwareids. + // Let us just make up some id for our child device. + // + buffer = (PWCHAR)ExAllocatePoolZero( + NonPagedPool, + ES8323_HARDWARE_IDS_LENGTH, + ES8323_POOL_TAG + ); + + if (buffer) + { + // + // Do the copy, store the buffer in the Irp + // + RtlCopyMemory(buffer, + ES8323_HARDWARE_IDS, + ES8323_HARDWARE_IDS_LENGTH + ); + + Irp->IoStatus.Information = (ULONG_PTR)buffer; + status = STATUS_SUCCESS; + } + else + { + // + // No memory + // + status = STATUS_INSUFFICIENT_RESOURCES; + } + + Irp->IoStatus.Status = status; + // + // We don't need to forward this to our bus. This query + // is for our child so we should complete it right here. + // fallthru. + // + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + break; + + default: + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + } + + Es8323Print(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, + "Es8323EvtWdmPreprocessMnQueryId Exit = 0x%x\n", status); + + return status; +} + +VOID +Es8323EvtInternalDeviceControl( +IN WDFQUEUE Queue, +IN WDFREQUEST Request, +IN size_t OutputBufferLength, +IN size_t InputBufferLength, +IN ULONG IoControlCode +) +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE device; + PES8323_CONTEXT devContext; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + device = WdfIoQueueGetDevice(Queue); + devContext = GetDeviceContext(device); + + switch (IoControlCode) + { + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + WdfRequestComplete(Request, status); + + return; +} diff --git a/drivers/audio/codecs/es8323/es8323.h b/drivers/audio/codecs/es8323/es8323.h new file mode 100644 index 0000000..e81887b --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.h @@ -0,0 +1,144 @@ +#ifndef __DRIVERS_SOUND_ES8323_H__ +#define __DRIVERS_SOUND_ES8323_H__ + +#define CONFIG_HHTECH_MINIPMP 1 + +/* ES8323 register space */ + +#define ES8323_CONTROL1 0x00 +#define ES8323_CONTROL2 0x01 +#define ES8323_CHIPPOWER 0x02 +#define ES8323_ADCPOWER 0x03 +#define ES8323_DACPOWER 0x04 +#define ES8323_CHIPLOPOW1 0x05 +#define ES8323_CHIPLOPOW2 0x06 +#define ES8323_ANAVOLMANAG 0x07 +#define ES8323_MASTERMODE 0x08 +#define ES8323_ADCCONTROL1 0x09 +#define ES8323_ADCCONTROL2 0x0a +#define ES8323_ADCCONTROL3 0x0b +#define ES8323_ADCCONTROL4 0x0c +#define ES8323_ADCCONTROL5 0x0d +#define ES8323_ADCCONTROL6 0x0e +#define ES8323_ADCCONTROL7 0x0f +#define ES8323_ADCCONTROL8 0x10 +#define ES8323_ADCCONTROL9 0x11 +#define ES8323_ADCCONTROL10 0x12 +#define ES8323_ADCCONTROL11 0x13 +#define ES8323_ADCCONTROL12 0x14 +#define ES8323_ADCCONTROL13 0x15 +#define ES8323_ADCCONTROL14 0x16 + +#define ES8323_DACCONTROL1 0x17 +#define ES8323_DACCONTROL2 0x18 +#define ES8323_DACCONTROL3 0x19 +#define ES8323_DACCONTROL4 0x1a +#define ES8323_DACCONTROL5 0x1b +#define ES8323_DACCONTROL6 0x1c +#define ES8323_DACCONTROL7 0x1d +#define ES8323_DACCONTROL8 0x1e +#define ES8323_DACCONTROL9 0x1f +#define ES8323_DACCONTROL10 0x20 +#define ES8323_DACCONTROL11 0x21 +#define ES8323_DACCONTROL12 0x22 +#define ES8323_DACCONTROL13 0x23 +#define ES8323_DACCONTROL14 0x24 +#define ES8323_DACCONTROL15 0x25 +#define ES8323_DACCONTROL16 0x26 +#define ES8323_DACCONTROL17 0x27 +#define ES8323_DACCONTROL18 0x28 +#define ES8323_DACCONTROL19 0x29 +#define ES8323_DACCONTROL20 0x2a +#define ES8323_DACCONTROL21 0x2b +#define ES8323_DACCONTROL22 0x2c +#define ES8323_DACCONTROL23 0x2d +#define ES8323_DACCONTROL24 0x2e +#define ES8323_DACCONTROL25 0x2f +#define ES8323_DACCONTROL26 0x30 +#define ES8323_DACCONTROL27 0x31 +#define ES8323_DACCONTROL28 0x32 +#define ES8323_DACCONTROL29 0x33 +#define ES8323_DACCONTROL30 0x34 + +#define ES8323_LADC_VOL ES8323_ADCCONTROL8 +#define ES8323_RADC_VOL ES8323_ADCCONTROL9 + +#define ES8323_LDAC_VOL ES8323_DACCONTROL4 +#define ES8323_RDAC_VOL ES8323_DACCONTROL5 + +#define ES8323_LOUT1_VOL ES8323_DACCONTROL24 +#define ES8323_ROUT1_VOL ES8323_DACCONTROL25 +#define ES8323_LOUT2_VOL ES8323_DACCONTROL26 +#define ES8323_ROUT2_VOL ES8323_DACCONTROL27 + +#define ES8323_ADC_MUTE ES8323_ADCCONTROL7 +#define ES8323_DAC_MUTE ES8323_DACCONTROL3 + + + +#define ES8323_IFACE ES8323_MASTERMODE + +#define ES8323_ADC_IFACE ES8323_ADCCONTROL4 +#define ES8323_ADC_SRATE ES8323_ADCCONTROL5 + +#define ES8323_DAC_IFACE ES8323_DACCONTROL1 +#define ES8323_DAC_SRATE ES8323_DACCONTROL2 + + + +#define ES8323_CACHEREGNUM 53 +#define ES8323_SYSCLK 0 + +struct es8323_setup_data { + int i2c_bus; + unsigned short i2c_address; +}; + +#if 1 //lzcx +#define ES8323_PLL1 0 +#define ES8323_PLL2 1 + +/* clock inputs */ +#define ES8323_MCLK 0 +#define ES8323_PCMCLK 1 + +/* clock divider id's */ +#define ES8323_PCMDIV 0 +#define ES8323_BCLKDIV 1 +#define ES8323_VXCLKDIV 2 + +/* PCM clock dividers */ +#define ES8323_PCM_DIV_1 (0 << 6) +#define ES8323_PCM_DIV_3 (2 << 6) +#define ES8323_PCM_DIV_5_5 (3 << 6) +#define ES8323_PCM_DIV_2 (4 << 6) +#define ES8323_PCM_DIV_4 (5 << 6) +#define ES8323_PCM_DIV_6 (6 << 6) +#define ES8323_PCM_DIV_8 (7 << 6) + +/* BCLK clock dividers */ +#define ES8323_BCLK_DIV_1 (0 << 7) +#define ES8323_BCLK_DIV_2 (1 << 7) +#define ES8323_BCLK_DIV_4 (2 << 7) +#define ES8323_BCLK_DIV_8 (3 << 7) + +/* VXCLK clock dividers */ +#define ES8323_VXCLK_DIV_1 (0 << 6) +#define ES8323_VXCLK_DIV_2 (1 << 6) +#define ES8323_VXCLK_DIV_4 (2 << 6) +#define ES8323_VXCLK_DIV_8 (3 << 6) +#define ES8323_VXCLK_DIV_16 (4 << 6) + +#define ES8323_DAI_HIFI 0 +#define ES8323_DAI_VOICE 1 + +#define ES8323_1536FS 1536 +#define ES8323_1024FS 1024 +#define ES8323_768FS 768 +#define ES8323_512FS 512 +#define ES8323_384FS 384 +#define ES8323_256FS 256 +#define ES8323_128FS 128 +#endif + +#endif \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/es8323.inx b/drivers/audio/codecs/es8323/es8323.inx new file mode 100644 index 0000000..6d39350 --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.inx @@ -0,0 +1,78 @@ +;/*++ +; +;Copyright (c) CoolStar. All rights reserved. +; +;Module Name: +; es8323.inf +; +;Abstract: +; INF file for installing the Everest 8323 Driver +; +; +;--*/ + +[Version] +Signature = "$WINDOWS NT$" +Class = Media +ClassGuid = {4d36e96c-e325-11ce-bfc1-08002be10318} +Provider = CoolStar +CatalogFile = es8323.cat +PnpLockdown = 1 + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +es8323.sys = 1,, + +;***************************************** +; Es8323 Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +; Decorated model section take precedence over undecorated +; ones on XP and later. +[Standard.NT$ARCH$] +%Es8323.DeviceDesc%=Es8323_Device, ACPI\ESSX8323 +%Es8388.DeviceDesc%=Es8323_Device, ACPI\ESSX8388 + +[Es8323_Device.NT] +CopyFiles=Drivers_Dir + +[Es8323_Device.NT.HW] +AddReg=Es8323_AddReg + +[Drivers_Dir] +es8323.sys + +[Es8323_AddReg] +; Set to 1 to connect the first interrupt resource found, 0 to leave disconnected +HKR,Settings,"ConnectInterrupt",0x00010001,0 + +;-------------- Service installation +[Es8323_Device.NT.Services] +AddService = Es8323,%SPSVCINST_ASSOCSERVICE%, Es8323_Service_Inst + +; -------------- Es8323 driver install sections +[Es8323_Service_Inst] +DisplayName = %Es8323.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\es8323.sys +LoadOrderGroup = Base + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +StdMfg = "CoolStar" +DiskId1 = "Everest 8323 Installation Disk #1" +Es8323.DeviceDesc = "Everest 8323 I2S Audio" +Es8388.DeviceDesc = "Everest 8388 I2S Audio" +Es8323.SVCDESC = "Everest 8323 Service" diff --git a/drivers/audio/codecs/es8323/es8323.rc b/drivers/audio/codecs/es8323/es8323.rc new file mode 100644 index 0000000..4ced062 --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.rc @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + es8323.rc + +Abstract: + +--*/ + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Everest 8323 I2S Audio" +#define VER_INTERNALNAME_STR "es8323.sys" +#define VER_ORIGINALFILENAME_STR "es8323.sys" + +#define VER_LEGALCOPYRIGHT_YEARS "2023" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." + +#define VER_FILEVERSION 1,0,0,0 +#define VER_PRODUCTVERSION_STR "1.0.0.0" +#define VER_PRODUCTVERSION 1,0,0,0 +#define LVER_PRODUCTVERSION_STR L"1.0.0.0" + +#define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) +#ifdef DEBUG +#define VER_FILEFLAGS (VS_FF_DEBUG) +#else +#define VER_FILEFLAGS (0) +#endif + +#define VER_FILEOS VOS_NT_WINDOWS32 + +#define VER_COMPANYNAME_STR "CoolStar" +#define VER_PRODUCTNAME_STR "Everest 8323 I2S Audio" + +#include "common.ver" \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/es8323.vcxproj b/drivers/audio/codecs/es8323/es8323.vcxproj new file mode 100644 index 0000000..38428d6 --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.vcxproj @@ -0,0 +1,104 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + + {15D34676-980D-4406-8C05-AB95AA5B43CA} + {1bc93793-694f-48fe-9372-81e2b05556fd} + v4.5 + 11.0 + Win8.1 Debug + Win32 + es8323 + $(LatestTargetPlatformVersion) + es8323 + + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + + + + + + + + + + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + + false + trace.h + true + false + + + 1.0.0 + + + SHA256 + + + + + false + trace.h + true + false + + + 1.0.0 + + + SHA256 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/es8323.vcxproj.Filters b/drivers/audio/codecs/es8323/es8323.vcxproj.Filters new file mode 100644 index 0000000..023e8dc --- /dev/null +++ b/drivers/audio/codecs/es8323/es8323.vcxproj.Filters @@ -0,0 +1,50 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {E10CB9FB-4852-4353-85F5-667D4D2A13DD} + + + h;hpp;hxx;hm;inl;inc;xsd + {EC8940D8-5E2B-49AB-AB85-7CABCAE698D1} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {42A1FDF4-6DB4-41B2-9423-8002A20D1B0D} + + + inf;inv;inx;mof;mc; + {FD9F921C-D1EF-421B-A692-F23423B32E64} + + + + + Driver Files + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/spb.c b/drivers/audio/codecs/es8323/spb.c new file mode 100644 index 0000000..9cfa3bc --- /dev/null +++ b/drivers/audio/codecs/es8323/spb.c @@ -0,0 +1,493 @@ +/*++ +Copyright (c) Microsoft Corporation. All Rights Reserved. +Sample code. Dealpoint ID #843729. + +Module Name: + +spb.c + +Abstract: + +Contains all I2C-specific functionality + +Environment: + +Kernel mode + +Revision History: + +--*/ + +#include "driver.h" +#include "spb.h" +#include + +static ULONG Es8323DebugLevel = 100; +static ULONG Es8323DebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; + +NTSTATUS +SpbDoWriteDataSynchronously( + IN SPB_CONTEXT* SpbContext, + IN PVOID Data, + IN ULONG Length +) +/*++ + +Routine Description: + +This helper routine abstracts creating and sending an I/O +request (I2C Write) to the Spb I/O target. + +Arguments: + +SpbContext - Pointer to the current device context +Address - The I2C register address to write to +Data - A buffer to receive the data at at the above address +Length - The amount of data to be read from the above address + +Return Value: + +NTSTATUS Status indicating success or failure + +--*/ +{ + PUCHAR buffer; + ULONG length; + WDFMEMORY memory; + WDF_MEMORY_DESCRIPTOR memoryDescriptor; + NTSTATUS status; + + length = Length; + memory = NULL; + + if (length > DEFAULT_SPB_BUFFER_SIZE) + { + status = WdfMemoryCreate( + WDF_NO_OBJECT_ATTRIBUTES, + NonPagedPool, + ES8323_POOL_TAG, + length, + &memory, + (PVOID*)&buffer); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error allocating memory for Spb write - %!STATUS!", + status); + goto exit; + } + + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( + &memoryDescriptor, + memory, + NULL); + } + else + { + buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &memoryDescriptor, + (PVOID)buffer, + length); + } + + RtlCopyMemory(buffer, Data, length); + + status = WdfIoTargetSendWriteSynchronously( + SpbContext->SpbIoTarget, + NULL, + &memoryDescriptor, + NULL, + NULL, + NULL); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error writing to Spb - %!STATUS!", + status); + goto exit; + } + +exit: + + if (NULL != memory) + { + WdfObjectDelete(memory); + } + + return status; +} + +NTSTATUS +SpbWriteDataSynchronously( + IN SPB_CONTEXT* SpbContext, + IN PVOID Data, + IN ULONG Length +) +/*++ + +Routine Description: + +This routine abstracts creating and sending an I/O +request (I2C Write) to the Spb I/O target and utilizes +a helper routine to do work inside of locked code. + +Arguments: + +SpbContext - Pointer to the current device context +Address - The I2C register address to write to +Data - A buffer to receive the data at at the above address +Length - The amount of data to be read from the above address + +Return Value: + +NTSTATUS Status indicating success or failure + +--*/ +{ + NTSTATUS status; + + WdfWaitLockAcquire(SpbContext->SpbLock, NULL); + + status = SpbDoWriteDataSynchronously( + SpbContext, + Data, + Length); + + WdfWaitLockRelease(SpbContext->SpbLock); + + return status; +} + +NTSTATUS +SpbXferDataSynchronously( + _In_ SPB_CONTEXT* SpbContext, + _In_ PVOID SendData, + _In_ ULONG SendLength, + _In_reads_bytes_(Length) PVOID Data, + _In_ ULONG Length +) +/*++ +Routine Description: +This helper routine abstracts creating and sending an I/O +request (I2C Read) to the Spb I/O target. +Arguments: +SpbContext - Pointer to the current device context +Address - The I2C register address to read from +Data - A buffer to receive the data at at the above address +Length - The amount of data to be read from the above address +Return Value: +NTSTATUS Status indicating success or failure +--*/ +{ + PUCHAR buffer; + WDFMEMORY memory; + WDF_MEMORY_DESCRIPTOR memoryDescriptor; + NTSTATUS status; + ULONG_PTR bytesRead; + + WdfWaitLockAcquire(SpbContext->SpbLock, NULL); + + memory = NULL; + status = STATUS_INVALID_PARAMETER; + bytesRead = 0; + + // + // Xfer transactions start by writing an address pointer + // + status = SpbDoWriteDataSynchronously( + SpbContext, + SendData, + SendLength); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error setting address pointer for Spb read - %!STATUS!", + status); + goto exit; + } + + if (Length > DEFAULT_SPB_BUFFER_SIZE) + { + status = WdfMemoryCreate( + WDF_NO_OBJECT_ATTRIBUTES, + NonPagedPool, + ES8323_POOL_TAG, + Length, + &memory, + (PVOID*)&buffer); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error allocating memory for Spb read - %!STATUS!", + status); + goto exit; + } + + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( + &memoryDescriptor, + memory, + NULL); + } + else + { + buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( + &memoryDescriptor, + (PVOID)buffer, + Length); + } + + + status = WdfIoTargetSendReadSynchronously( + SpbContext->SpbIoTarget, + NULL, + &memoryDescriptor, + NULL, + NULL, + &bytesRead); + + if (!NT_SUCCESS(status) || + bytesRead != Length) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error reading from Spb - %!STATUS!", + status); + goto exit; + } + + // + // Copy back to the caller's buffer + // + RtlCopyMemory(Data, buffer, Length); + +exit: + if (NULL != memory) + { + WdfObjectDelete(memory); + } + + WdfWaitLockRelease(SpbContext->SpbLock); + + return status; +} + +VOID +SpbTargetDeinitialize( + IN WDFDEVICE FxDevice, + IN SPB_CONTEXT* SpbContext +) +/*++ + +Routine Description: + +This helper routine is used to free any members added to the SPB_CONTEXT, +note the SPB I/O target is parented to the device and will be +closed and free'd when the device is removed. + +Arguments: + +FxDevice - Handle to the framework device object +SpbContext - Pointer to the current device context + +Return Value: + +NTSTATUS Status indicating success or failure + +--*/ +{ + UNREFERENCED_PARAMETER(FxDevice); + UNREFERENCED_PARAMETER(SpbContext); + + // + // Free any SPB_CONTEXT allocations here + // + if (SpbContext->SpbLock != NULL) + { + WdfObjectDelete(SpbContext->SpbLock); + } + + if (SpbContext->ReadMemory != NULL) + { + WdfObjectDelete(SpbContext->ReadMemory); + } + + if (SpbContext->WriteMemory != NULL) + { + WdfObjectDelete(SpbContext->WriteMemory); + } +} + +NTSTATUS +SpbTargetInitialize( + IN WDFDEVICE FxDevice, + IN SPB_CONTEXT* SpbContext +) +/*++ + +Routine Description: + +This helper routine opens the Spb I/O target and +initializes a request object used for the lifetime +of communication between this driver and Spb. + +Arguments: + +FxDevice - Handle to the framework device object +SpbContext - Pointer to the current device context + +Return Value: + +NTSTATUS Status indicating success or failure + +--*/ +{ + WDF_OBJECT_ATTRIBUTES objectAttributes; + WDF_IO_TARGET_OPEN_PARAMS openParams; + UNICODE_STRING spbDeviceName; + WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; + NTSTATUS status; + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = FxDevice; + + status = WdfIoTargetCreate( + FxDevice, + &objectAttributes, + &SpbContext->SpbIoTarget); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error creating IoTarget object - %!STATUS!", + status); + + WdfObjectDelete(SpbContext->SpbIoTarget); + goto exit; + } + + RtlInitEmptyUnicodeString( + &spbDeviceName, + spbDeviceNameBuffer, + sizeof(spbDeviceNameBuffer)); + + status = RESOURCE_HUB_CREATE_PATH_FROM_ID( + &spbDeviceName, + SpbContext->I2cResHubId.LowPart, + SpbContext->I2cResHubId.HighPart); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error creating Spb resource hub path string - %!STATUS!", + status); + goto exit; + } + + WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( + &openParams, + &spbDeviceName, + (GENERIC_READ | GENERIC_WRITE)); + + openParams.ShareAccess = 0; + openParams.CreateDisposition = FILE_OPEN; + openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; + + status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error opening Spb target for communication - %!STATUS!", + status); + goto exit; + } + + // + // Allocate some fixed-size buffers from NonPagedPool for typical + // Spb transaction sizes to avoid pool fragmentation in most cases + // + status = WdfMemoryCreate( + WDF_NO_OBJECT_ATTRIBUTES, + NonPagedPool, + ES8323_POOL_TAG, + DEFAULT_SPB_BUFFER_SIZE, + &SpbContext->WriteMemory, + NULL); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error allocating default memory for Spb write - %!STATUS!", + status); + goto exit; + } + + status = WdfMemoryCreate( + WDF_NO_OBJECT_ATTRIBUTES, + NonPagedPool, + ES8323_POOL_TAG, + DEFAULT_SPB_BUFFER_SIZE, + &SpbContext->ReadMemory, + NULL); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error allocating default memory for Spb read - %!STATUS!", + status); + goto exit; + } + + // + // Allocate a waitlock to guard access to the default buffers + // + status = WdfWaitLockCreate( + WDF_NO_OBJECT_ATTRIBUTES, + &SpbContext->SpbLock); + + if (!NT_SUCCESS(status)) + { + Es8323Print( + DEBUG_LEVEL_ERROR, + DBG_IOCTL, + "Error creating Spb Waitlock - %!STATUS!", + status); + goto exit; + } + +exit: + + if (!NT_SUCCESS(status)) + { + SpbTargetDeinitialize(FxDevice, SpbContext); + } + + return status; +} \ No newline at end of file diff --git a/drivers/audio/codecs/es8323/spb.h b/drivers/audio/codecs/es8323/spb.h new file mode 100644 index 0000000..76c9001 --- /dev/null +++ b/drivers/audio/codecs/es8323/spb.h @@ -0,0 +1,68 @@ +/*++ +Copyright (c) Microsoft Corporation. All Rights Reserved. +Sample code. Dealpoint ID #843729. + +Module Name: + +spb.h + +Abstract: + +This module contains the touch driver I2C helper definitions. + +Environment: + +Kernel Mode + +Revision History: + +--*/ + +#pragma once + +#include +#include + +#define DEFAULT_SPB_BUFFER_SIZE 64 +#define RESHUB_USE_HELPER_ROUTINES + +// +// SPB (I2C) context +// + +typedef struct _SPB_CONTEXT +{ + WDFIOTARGET SpbIoTarget; + LARGE_INTEGER I2cResHubId; + WDFMEMORY WriteMemory; + WDFMEMORY ReadMemory; + WDFWAITLOCK SpbLock; +} SPB_CONTEXT; + +NTSTATUS +SpbXferDataSynchronously( + _In_ SPB_CONTEXT* SpbContext, + _In_ PVOID SendData, + _In_ ULONG SendLength, + _In_reads_bytes_(Length) PVOID Data, + _In_ ULONG Length +); + +VOID +SpbTargetDeinitialize( + IN WDFDEVICE FxDevice, + IN SPB_CONTEXT* SpbContext +); + +NTSTATUS +SpbTargetInitialize( + IN WDFDEVICE FxDevice, + IN SPB_CONTEXT* SpbContext +); + +NTSTATUS +SpbWriteDataSynchronously( + IN SPB_CONTEXT* SpbContext, + IN PVOID Data, + IN ULONG Length +); \ No newline at end of file