/* * Volmar SOF free driver - ADSP interface probe. * * ADSP bus interface layout is derived from coolstar/sklhdaudbus (BSD-3-Clause). * Copyright 2024 CoolStar. Redistribution conditions are preserved in the * project NOTICE file. Query-IRP pattern follows Microsoft Windows driver * samples (MS-PL). */ #include #include #include #include "volmaradsp.h" union VOLMAR_BASEADDR { PVOID Base; UINT8* baseptr; }; typedef struct _VOLMAR_PCI_BAR { union VOLMAR_BASEADDR Base; ULONG Len; } VOLMAR_PCI_BAR, *PVOLMAR_PCI_BAR; typedef struct _VOLMAR_NHLT_INFO { PVOID nhlt; UINT64 nhltSz; } VOLMAR_NHLT_INFO, *PVOLMAR_NHLT_INFO; typedef NTSTATUS(*PVOLMAR_GET_ADSP_RESOURCES)( PVOID, PVOLMAR_PCI_BAR, PVOLMAR_PCI_BAR, PVOID*, PVOLMAR_NHLT_INFO, BUS_INTERFACE_STANDARD*); typedef NTSTATUS(*PVOLMAR_DSP_SET_POWER_STATE)(PVOID, DEVICE_POWER_STATE); typedef BOOL(*PVOLMAR_ADSP_INTERRUPT_CALLBACK)(PVOID); typedef NTSTATUS(*PVOLMAR_REGISTER_ADSP_INTERRUPT)(PVOID, PVOLMAR_ADSP_INTERRUPT_CALLBACK, PVOID); typedef NTSTATUS(*PVOLMAR_UNREGISTER_ADSP_INTERRUPT)(PVOID); typedef NTSTATUS(*PVOLMAR_GET_STREAM)(PVOID, HDAUDIO_STREAM_FORMAT, PHANDLE, UINT8*); typedef NTSTATUS(*PVOLMAR_FREE_STREAM)(PVOID, HANDLE); typedef NTSTATUS(*PVOLMAR_DSP_PREPARE_STREAM)(PVOID, HANDLE, unsigned int, int, PVOID*); typedef NTSTATUS(*PVOLMAR_DSP_CLEANUP_STREAM)(PVOID, HANDLE); typedef UINT32(*PVOLMAR_DSP_STREAM_POSITION)(PVOID, HANDLE); typedef void(*PVOLMAR_DSP_START_STOP_STREAM)(PVOID, HANDLE, BOOL); typedef void(*PVOLMAR_DSP_ENABLE_SPIB)(PVOID, HANDLE, UINT32); typedef void(*PVOLMAR_DSP_DISABLE_SPIB)(PVOID, HANDLE); typedef struct _VOLMAR_ADSP_BUS_INTERFACE { USHORT Size; USHORT Version; PVOID Context; PINTERFACE_REFERENCE InterfaceReference; PINTERFACE_DEREFERENCE InterfaceDereference; UINT16 CtlrDevId; PVOLMAR_GET_ADSP_RESOURCES GetResources; PVOLMAR_DSP_SET_POWER_STATE SetDSPPowerState; PVOLMAR_REGISTER_ADSP_INTERRUPT RegisterInterrupt; PVOLMAR_UNREGISTER_ADSP_INTERRUPT UnregisterInterrupt; PVOLMAR_GET_STREAM GetRenderStream; PVOLMAR_GET_STREAM GetCaptureStream; PVOLMAR_FREE_STREAM FreeStream; PVOLMAR_DSP_PREPARE_STREAM PrepareDSP; PVOLMAR_DSP_CLEANUP_STREAM CleanupDSP; PVOLMAR_DSP_START_STOP_STREAM TriggerDSP; PVOLMAR_DSP_STREAM_POSITION StreamPosition; PVOLMAR_DSP_ENABLE_SPIB DSPEnableSPIB; PVOLMAR_DSP_DISABLE_SPIB DSPDisableSPIB; } VOLMAR_ADSP_BUS_INTERFACE, *PVOLMAR_ADSP_BUS_INTERFACE; static const GUID GUID_VOLMAR_ADSP_BUS_INTERFACE = { 0x752a2cae, 0x3455, 0x4d18, { 0xa1, 0x84, 0x8b, 0x34, 0xb2, 0x26, 0x32, 0xce } }; static NTSTATUS VolmarQueryInterfaceCompletion( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID Context ) { UNREFERENCED_PARAMETER(DeviceObject); if (Irp->PendingReturned) { KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); } return STATUS_MORE_PROCESSING_REQUIRED; } static NTSTATUS VolmarQueryAdspInterface( _In_ PDEVICE_OBJECT PhysicalDeviceObject, _Out_ PVOLMAR_ADSP_BUS_INTERFACE Interface ) { PIRP irp = NULL; PIO_STACK_LOCATION stack = NULL; KEVENT event; NTSTATUS status; if (PhysicalDeviceObject == NULL || Interface == NULL) { return STATUS_INVALID_PARAMETER; } RtlZeroMemory(Interface, sizeof(*Interface)); irp = IoAllocateIrp(PhysicalDeviceObject->StackSize, FALSE); if (irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(&event, NotificationEvent, FALSE); IoSetCompletionRoutine( irp, VolmarQueryInterfaceCompletion, &event, TRUE, TRUE, TRUE); irp->IoStatus.Status = STATUS_NOT_SUPPORTED; stack = IoGetNextIrpStackLocation(irp); stack->MajorFunction = IRP_MJ_PNP; stack->MinorFunction = IRP_MN_QUERY_INTERFACE; stack->Parameters.QueryInterface.Interface = reinterpret_cast(Interface); stack->Parameters.QueryInterface.InterfaceSpecificData = NULL; stack->Parameters.QueryInterface.Size = sizeof(*Interface); stack->Parameters.QueryInterface.Version = 1; stack->Parameters.QueryInterface.InterfaceType = const_cast(&GUID_VOLMAR_ADSP_BUS_INTERFACE); status = IoCallDriver(PhysicalDeviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL); status = irp->IoStatus.Status; } IoFreeIrp(irp); if (!NT_SUCCESS(status)) { RtlZeroMemory(Interface, sizeof(*Interface)); } return status; } NTSTATUS VolmarValidateAdspBus( _In_ PDEVICE_OBJECT DeviceObject ) { PDEVICE_OBJECT pdo = NULL; VOLMAR_ADSP_BUS_INTERFACE busInterface = {}; NTSTATUS status; PAGED_CODE(); status = PcGetPhysicalDeviceObject(DeviceObject, &pdo); if (!NT_SUCCESS(status) || pdo == NULL) { return NT_SUCCESS(status) ? STATUS_NO_SUCH_DEVICE : status; } status = VolmarQueryAdspInterface(pdo, &busInterface); if (!NT_SUCCESS(status)) { return status; } if (busInterface.Size < sizeof(VOLMAR_ADSP_BUS_INTERFACE) || busInterface.Version < 1 || busInterface.CtlrDevId != 0x51C8 || busInterface.GetResources == NULL || busInterface.GetRenderStream == NULL || busInterface.GetCaptureStream == NULL || busInterface.PrepareDSP == NULL || busInterface.TriggerDSP == NULL || busInterface.StreamPosition == NULL) { status = STATUS_DEVICE_CONFIGURATION_ERROR; } else { status = STATUS_SUCCESS; } if (busInterface.InterfaceDereference != NULL) { busInterface.InterfaceDereference(busInterface.Context); } return status; }