From b9027f2b8124f5853dac4355ff4d9e85379e0e56 Mon Sep 17 00:00:00 2001 From: Girish Pattabiraman Date: Wed, 3 May 2017 15:02:49 -0700 Subject: Audio Modules Example Delay APO Package Project Stream Position Bug Fix SAL --- audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp | 644 +++++++++++++++++++++ 1 file changed, 644 insertions(+) create mode 100644 audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp (limited to 'audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp') diff --git a/audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp b/audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp new file mode 100644 index 00000000..f93c2bff --- /dev/null +++ b/audio/sysvad/EndpointsCommon/AudioModuleHelper.cpp @@ -0,0 +1,644 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + AudioModuleHelper.cpp + +Abstract: + + Simple helper for Audio Modules logic. + +--*/ + +#pragma warning (disable : 4127) + +#include +#include +#include +#include "SysVadShared.h" +#include "AudioModuleHelper.h" + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +AudioModule_GenericHandler_BasicSupport( + _In_ PAUDIOMODULE_PARAMETER_INFO ParameterInfo, + _Out_writes_bytes_opt_(*BufferCb) PVOID Buffer, + _Inout_ ULONG * BufferCb + ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG cbFullProperty = 0; + ULONG cbDataListSize = 0; + + DPF_ENTER(("[AudioModule_GenericHandler_BasicSupport]")); + + PAGED_CODE(); + + ASSERT(ParameterInfo); + ASSERT(BufferCb); + + // + // Compute total size of property. + // + ntStatus = RtlULongMult(ParameterInfo->Size, + ParameterInfo->ValidSetCount, + &cbDataListSize); + if (!NT_SUCCESS(ntStatus)) + { + ASSERT(FALSE); + *BufferCb = 0; + return ntStatus; + } + + ntStatus = RtlULongAdd(cbDataListSize, + (ULONG)(sizeof(KSPROPERTY_DESCRIPTION) + + sizeof(KSPROPERTY_MEMBERSHEADER)), + &cbFullProperty); + + if (!NT_SUCCESS(ntStatus)) + { + ASSERT(FALSE); + *BufferCb = 0; + return ntStatus; + } + + // + // Return the info the caller is asking for. + // + if (*BufferCb == 0) + { + // caller wants to know the size of the buffer. + *BufferCb = cbFullProperty; + ntStatus = STATUS_BUFFER_OVERFLOW; + } + else if (*BufferCb >= (sizeof(KSPROPERTY_DESCRIPTION))) + { + PKSPROPERTY_DESCRIPTION propDesc = PKSPROPERTY_DESCRIPTION(Buffer); + + propDesc->AccessFlags = ParameterInfo->AccessFlags; + propDesc->DescriptionSize = cbFullProperty; + propDesc->PropTypeSet.Set = KSPROPTYPESETID_General; + propDesc->PropTypeSet.Id = ParameterInfo->VtType; + propDesc->PropTypeSet.Flags = 0; + propDesc->MembersListCount = 1; + propDesc->Reserved = 0; + + // if return buffer can also hold a list description, return it too + if(*BufferCb >= cbFullProperty) + { + // fill in the members header + PKSPROPERTY_MEMBERSHEADER members = + PKSPROPERTY_MEMBERSHEADER(propDesc + 1); + + members->MembersFlags = KSPROPERTY_MEMBER_VALUES; + members->MembersSize = ParameterInfo->Size; + members->MembersCount = ParameterInfo->ValidSetCount; + members->Flags = KSPROPERTY_MEMBER_FLAG_DEFAULT; + + // fill in valid array. + BYTE* array = (BYTE*)(members + 1); + + RtlCopyMemory(array, ParameterInfo->ValidSet, cbDataListSize); + + // set the return value size + *BufferCb = cbFullProperty; + } + else + { + *BufferCb = sizeof(KSPROPERTY_DESCRIPTION); + } + } + else if(*BufferCb >= sizeof(ULONG)) + { + // if return buffer can hold a ULONG, return the access flags + PULONG accessFlags = PULONG(Buffer); + + *BufferCb = sizeof(ULONG); + *accessFlags = ParameterInfo->AccessFlags; + } + else + { + *BufferCb = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} // PropertyHandlerBasicSupportVolume + +//============================================================================= +#pragma code_seg("PAGE") +BOOLEAN +IsAudioModuleParameterValid( + _In_ PAUDIOMODULE_PARAMETER_INFO ParameterInfo, + _In_reads_bytes_opt_(BufferCb) PVOID Buffer, + _In_ ULONG BufferCb + ) +{ + PAGED_CODE(); + + DPF_ENTER(("[IsAudioModuleParameterValid]")); + + ULONG i = 0; + ULONG j = 0; + BOOLEAN validParam = FALSE; + + // + // Validate buffer ptr and size. + // + if (Buffer == NULL || BufferCb == 0) + { + validParam = FALSE; + goto exit; + } + + // + // Check its size. + // + if (BufferCb < ParameterInfo->Size) + { + validParam = FALSE; + goto exit; + } + + // + // Check the valid list. + // + if (ParameterInfo->ValidSet && ParameterInfo->ValidSetCount) + { + BYTE* buffer = (BYTE*)ParameterInfo->ValidSet; + BYTE* pattern = (BYTE*)Buffer; + + // + // Scan the valid list. + // + for (i = 0; i < ParameterInfo->ValidSetCount; ++i) + { + for (j=0; j < ParameterInfo->Size; ++j) + { + if (buffer[j] != pattern[j]) + { + break; + } + } + + if (j == ParameterInfo->Size) + { + // got a match. + break; + } + + buffer += ParameterInfo->Size; + } + + // + // If end of list, we didn't find the value. + // + if (i == ParameterInfo->ValidSetCount) + { + validParam = FALSE; + goto exit; + } + } + else + { + // + // Negative-testing support. Fail request if value is -1. + // + BYTE* buffer = (BYTE*)Buffer; + + for (i = 0; i < ParameterInfo->Size; ++i) + { + if (buffer[i] != 0xFF) + { + break; + } + } + + // + // If value is -1, return error. + // + if (i == ParameterInfo->Size) + { + validParam = FALSE; + goto exit; + } + } + + validParam = TRUE; + +exit: + return validParam; +} + +//============================================================================= +#pragma code_seg("PAGE") +AUDIOMODULE * +AudioModule_FindModuleInList( + _In_ AUDIOMODULE * AudioModules, + _In_ ULONG AudioModuleCount, + _In_ GUID * ClassId, + _In_ ULONG InstanceId + ) +{ + for (ULONG i=0; iDescriptor->ClassId), *ClassId) && + module->InstanceId == InstanceId) + { + return module; + } + } + + return NULL; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +AudioModule_GenericHandler( + _In_ ULONG Verb, + _In_ ULONG ParameterId, + _In_ PAUDIOMODULE_PARAMETER_INFO ParameterInfo, + _Inout_updates_bytes_(ParameterInfo->Size) PVOID CurrentValue, + _In_reads_bytes_opt_(InBufferCb) PVOID InBuffer, + _In_ ULONG InBufferCb, + _Out_writes_bytes_opt_(*OutBufferCb) PVOID OutBuffer, + _Inout_ ULONG * OutBufferCb, + _In_ BOOL * ParameterChanged + ) +{ + PAGED_CODE(); + + DPF_ENTER(("[AudioModule_GenericHandler]")); + + UNREFERENCED_PARAMETER(ParameterId); + + *ParameterChanged = FALSE; + + // Handle KSPROPERTY_TYPE_BASICSUPPORT query + if (Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + return AudioModule_GenericHandler_BasicSupport(ParameterInfo, OutBuffer, OutBufferCb); + } + + ULONG cbMinSize = ParameterInfo->Size; + + if (Verb & KSPROPERTY_TYPE_GET) + { + // Verify module parameter supports 'get'. + if (!(ParameterInfo->AccessFlags & KSPROPERTY_TYPE_GET)) + { + *OutBufferCb = 0; + return STATUS_INVALID_DEVICE_REQUEST; + } + + // Verify value size + if (*OutBufferCb == 0) + { + *OutBufferCb = cbMinSize; + return STATUS_BUFFER_OVERFLOW; + } + if (*OutBufferCb < cbMinSize) + { + *OutBufferCb = 0; + return STATUS_BUFFER_TOO_SMALL; + } + else + { + RtlCopyMemory(OutBuffer, CurrentValue, ParameterInfo->Size); + *OutBufferCb = cbMinSize; + return STATUS_SUCCESS; + } + } + else if (Verb & KSPROPERTY_TYPE_SET) + { + *OutBufferCb = 0; + + // Verify it is a write prop. + if (!(ParameterInfo->AccessFlags & KSPROPERTY_TYPE_SET)) + { + return STATUS_INVALID_DEVICE_REQUEST; + } + + // Validate parameter. + if (!IsAudioModuleParameterValid(ParameterInfo, InBuffer, InBufferCb)) + { + return STATUS_INVALID_PARAMETER; + } + + if (ParameterInfo->Size != + RtlCompareMemory(CurrentValue, InBuffer, ParameterInfo->Size)) + { + RtlCopyMemory(CurrentValue, InBuffer, ParameterInfo->Size); + *ParameterChanged = TRUE; + } + + return STATUS_SUCCESS; + } + + return STATUS_INVALID_DEVICE_REQUEST; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +AudioModule_GenericHandler_ModulesListRequest( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ AUDIOMODULE * AudioModules, + _In_ ULONG AudioModuleCount + ) +{ + NTSTATUS ntStatus; + + // This specific APO->driver communication example is mainly added to show how this communication is done. + // The module list only lives on the wave filter and it can have modules that are for all pins and some that + // are only on specific pins. + + PAGED_CODE(); + + DPF_ENTER(("[AudioModule_PropertyHandlerModulesListRequest]")); + + // + // Note: return an empty list when no modules are present. + // + + // Handle KSPROPERTY_TYPE_BASICSUPPORT query + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ULONG flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT; + return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL); + } + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + PKSMULTIPLE_ITEM ksMultipleItem; + ULONG cbMinSize = 0; + PKSAUDIOMODULE_DESCRIPTOR modules = NULL; + + // + // Compute min value size requirements + // + ntStatus = RtlULongMult(AudioModuleCount, + (ULONG)sizeof(KSAUDIOMODULE_DESCRIPTOR), + &cbMinSize); + if (!NT_SUCCESS(ntStatus)) + { + ASSERT(FALSE); + return ntStatus; + } + + ntStatus = RtlULongAdd(cbMinSize, sizeof(KSMULTIPLE_ITEM), &cbMinSize); + if (!NT_SUCCESS(ntStatus)) + { + ASSERT(FALSE); + return ntStatus; + } + + // Verify value size + if (PropertyRequest->ValueSize == 0) + { + PropertyRequest->ValueSize = cbMinSize; + return STATUS_BUFFER_OVERFLOW; + } + if (PropertyRequest->ValueSize < cbMinSize) + { + return STATUS_BUFFER_TOO_SMALL; + } + + // Value is a KSMULTIPLE_ITEM followed by list of modules. + ksMultipleItem = (PKSMULTIPLE_ITEM)PropertyRequest->Value; + modules = (PKSAUDIOMODULE_DESCRIPTOR)(ksMultipleItem + 1); + + // Copy modules + for (ULONG i = 0; iClassId = *moduleDesc->ClassId; + modules->InstanceId = AudioModules[i].InstanceId; + + modules->VersionMajor = moduleDesc->VersionMajor; + modules->VersionMinor = moduleDesc->VersionMinor; + + + RtlStringCchCopyW(modules->Name, + AUDIOMODULE_MAX_NAME_CCH_SIZE, // includes null char + moduleDesc->Name); + } + + // Miniport filled in the list of modules. Fill in the KSMULTIPLE_ITEM header. + ksMultipleItem->Size = cbMinSize; + ksMultipleItem->Count = AudioModuleCount; + + PropertyRequest->ValueSize = ksMultipleItem->Size; + return STATUS_SUCCESS; + } + + return STATUS_INVALID_DEVICE_REQUEST; +} // AudioModule_GenericHandler_ModulesListRequest + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +AudioModule_GenericHandler_ModuleCommand( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ AUDIOMODULE * AudioModules, + _In_ ULONG AudioModuleCount + ) +{ + AUDIOMODULE * module = NULL; + + PAGED_CODE(); + + DPF_ENTER(("[AudioModule_GenericHandler_ModuleCommand]")); + + // + // Basic parameter validation. + // + if (AudioModules == NULL || AudioModuleCount == 0) + { + // endpoint/stream doesn't have any modules. + return STATUS_INVALID_DEVICE_REQUEST; + } + + // Verify instance data stores at least KSAUDIOMODULE_PROPERTY fields + // beyond KSPPROPERTY. + if (PropertyRequest->InstanceSize < (sizeof(KSAUDIOMODULE_PROPERTY) - + RTL_SIZEOF_THROUGH_FIELD(KSAUDIOMODULE_PROPERTY, Property))) + { + return STATUS_INVALID_PARAMETER; + } + + // Extract property descriptor from property request instance data + PKSAUDIOMODULE_PROPERTY moduleProperty = CONTAINING_RECORD( + PropertyRequest->Instance, KSAUDIOMODULE_PROPERTY, ClassId); + + // Get a ptr to the module. + module = AudioModule_FindModuleInList(AudioModules, + AudioModuleCount, + &moduleProperty->ClassId, + moduleProperty->InstanceId); + // + // Invoke the handler. + // + if (module == NULL || + module->Descriptor == NULL || + module->Descriptor->Handler == NULL) + { + return STATUS_INVALID_PARAMETER; + } + + // Handle KSPROPERTY_TYPE_BASICSUPPORT query + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ULONG flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT; + + return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL); + } + + // Only KS-get is supported. + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + NTSTATUS status; + ULONG inBufferCb = 0; + ULONG outBufferCb = 0; + PVOID inBuffer = NULL; + PVOID outBuffer = NULL; + + outBufferCb = PropertyRequest->ValueSize; + outBuffer = PropertyRequest->Value; + + ASSERT((outBufferCb != 0 && outBuffer != NULL) || + (outBufferCb == 0 && outBuffer == NULL)); + + // this is guaranteed to work b/c of the validation above. + inBufferCb = PropertyRequest->InstanceSize + + sizeof(KSPROPERTY) - + sizeof(KSAUDIOMODULE_PROPERTY); + + if (inBufferCb != 0) + { + inBuffer = (PVOID)(moduleProperty+1); + } + + status = module->Descriptor->Handler(module->Context, + inBuffer, + inBufferCb, + outBuffer, + &outBufferCb); + // + // Set the size of the returned output data, or in the case of + // buffer overflow error, return the expected buffer length. + // + PropertyRequest->ValueSize = outBufferCb; + return status; + } + + PropertyRequest->ValueSize = 0; + return STATUS_INVALID_DEVICE_REQUEST; +} // AudioModule_GenericHandler_ModuleCommand + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +AudioModule_GenericHandler_ModuleNotificationDeviceId( + _In_ PPCPROPERTY_REQUEST PropertyRequest, + _In_ const GUID * NotificationDeviceId + ) +{ + PAGED_CODE(); + + DPF_ENTER(("[AudioModule_GenericHandler_ModuleNotificationDeviceId]")); + + // + // Basic parameter validation. + // + if (NotificationDeviceId == NULL) + { + return STATUS_INVALID_DEVICE_REQUEST; + } + + // Handle KSPROPERTY_TYPE_BASICSUPPORT query + if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) + { + ULONG flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT; + + return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL); + } + + ULONG cbMinSize = sizeof(GUID); + GUID *dataPtr = static_cast(PropertyRequest->Value); + + if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) + { + // Verify value size + if (PropertyRequest->ValueSize == 0) + { + PropertyRequest->ValueSize = cbMinSize; + return STATUS_BUFFER_OVERFLOW; + } + if (PropertyRequest->ValueSize < cbMinSize) + { + return STATUS_BUFFER_TOO_SMALL; + } + else + { + *dataPtr = *NotificationDeviceId; + PropertyRequest->ValueSize = cbMinSize; + + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_DEVICE_REQUEST; +} + +//============================================================================= +#pragma code_seg("PAGE") +VOID +AudioModule_SendNotification( + _In_ PPORTCLSNOTIFICATIONS PortNotifications, + _In_ PVOID NotificationBuffer, + _In_ USHORT NotificationBufferCb + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PPCNOTIFICATION_BUFFER buffer = NULL; + + PAGED_CODE(); + + DPF_ENTER(("[AudioModule_SendNotification]")); + + // Allocate a notification buffer. + status = PortNotifications->AllocNotificationBuffer(PagedPool, + NotificationBufferCb, + &buffer); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + // Notification buffer is only guaranteed to be LONG aligned, + // it is received as ULONGLONG aligned on the receiving end. + RtlCopyMemory(buffer, NotificationBuffer, NotificationBufferCb); + + // + // Generate notification (async). + // + PortNotifications->SendNotification(&KSNOTIFICATIONID_AudioModule, buffer); + +exit: + if (buffer != NULL) + { + // Free notification buffer. + PortNotifications->FreeNotificationBuffer(buffer); + buffer = NULL; + } +} + + -- cgit v1.3.1