reactos/drivers/ksfilter/ks/connectivity.c
Oleg Dubinskiy 12b3272d9e
[AUDIO] Implement support for WAVE_FORMAT_EXTENSIBLE audio format (#6686)
[MMIXER] Implement hadling WAVE_FORMAT_EXTENSIBLE audio format
Fix opening audio device error when trying to open it with WAVE_FORMAT_EXTENSIBLE format tag set in wFormatTag member of WAVEFORMATEX:
- Pass additional data size from WAVEFORMATEX.cbSize to pin data format.
- Append it to the whole size of pin data format (KSDATAFORMAT.FormatSize).
- Set additional fields in WAVEFORMATEXTENSIBLE structure (data format, BPS and channel mask) when WAVE_FORMAT_EXTENSIBLE is used. They are used by our inbuilt Intel AC97 miniport driver at least. It simply fails when these members are not set.
- Fix pin connect allocation size by appending an additional data size from WAVEFORMATEX.cbSize to KSPIN_CONNECT + KSDATAFORMAT + WAVEFORMATEX. This allows to proerly initialize additional extensible data and avoids kernel memory leakage when using extensible audio format.
- Remove format tag check which allowed WAVE_FORMAT_PCM to be opened correctly. So now all possible audio formats can be opened properly at least (although it does not mean they may work correctly).
This fixes the audio playback for all apps those are supporting extensible audio data and use it by default (e. g. AIMP 5.30, QMMP 0.12.17, all Chrome/Chromium-based browsers, GameDev Tycoon Demo game etc.).
CORE-10907, CORE-14783

* [KS] Allow passing additional extensible audio data when extensible audio format is used
- Append additional data size from WAVEFORMATEX.cbSize to pin connect size passed to KsCreatePin. If the tag is WAVE_FORMAT_PCM, then this member should always be zero. So in that case, no any additional data is passed to creation request, and the passed data size is correct for PCM too (KSDATAFORMAT + WAVEFORMATEX).
This fixes audio playback in several apps those are supporting extensibble audio and use it by default (e. g. AIMP 5.30, QMMP 0.12.17, all Chrome/Chromium based browsers, GameDev Tycoon Demo game etc.).
CORE-10907, CORE-14783.

* [WDMAUD.DRV] Pass the correct additional data size to I/O control request
Store a correct size of additional data in WAVEFORMATEX.cbSize when performing open of audio device, when WAVE_FORMAT_EXTENSIBLE audio format is used.
It allows to properly open audio device with Legacy APIs enabled too.
This fixes audio playback in several apps those are using extensible audio data (e. g. AIMP 5.30, QMMP 0.12.17, all Chrome/Chromium based browsers, GameDevTycoon Demo game etc.).
CORE-10907, CORE-14783
2024-04-11 11:59:14 +02:00

842 lines
25 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel Streaming
* FILE: drivers/ksfilter/ks/connectivity.c
* PURPOSE: KS Pin functions
* PROGRAMMER: Johannes Anderwald
*/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
KSPIN_INTERFACE StandardPinInterface =
{
{STATIC_KSINTERFACESETID_Standard},
KSINTERFACE_STANDARD_STREAMING,
0
};
KSPIN_MEDIUM StandardPinMedium =
{
{STATIC_KSMEDIUMSETID_Standard},
KSMEDIUM_TYPE_ANYINSTANCE,
0
};
const GUID KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT = {0xf4aeb342, 0x0329, 0x4fdd, {0xa8, 0xfd, 0x4a, 0xff, 0x49, 0x26, 0xc9, 0x78}};
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsCreatePin(
IN HANDLE FilterHandle,
IN PKSPIN_CONNECT Connect,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE ConnectionHandle)
{
UINT ConnectSize = sizeof(KSPIN_CONNECT);
PKSDATAFORMAT_WAVEFORMATEX Format = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1);
if (Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) ||
Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX) + Format->WaveFormatEx.cbSize)
{
ConnectSize += Format->DataFormat.FormatSize;
}
return KspCreateObjectType(FilterHandle,
KSSTRING_Pin,
(PVOID)Connect,
ConnectSize,
DesiredAccess,
ConnectionHandle);
}
NTSTATUS
KspValidateConnectRequest(
IN PIRP Irp,
IN ULONG DescriptorsCount,
IN PVOID Descriptors,
IN ULONG DescriptorSize,
OUT PKSPIN_CONNECT* Connect)
{
PKSPIN_CONNECT ConnectDetails;
PKSPIN_INTERFACE Interface;
PKSPIN_MEDIUM Medium;
ULONG Size;
NTSTATUS Status;
ULONG Index;
ULONG Count;
BOOLEAN Found;
PKSPIN_DESCRIPTOR Descriptor;
UNICODE_STRING GuidString2;
/* did the caller miss the connect parameter */
if (!Connect)
return STATUS_INVALID_PARAMETER;
/* set create param size */
Size = sizeof(KSPIN_CONNECT);
/* fetch create parameters */
Status = KspCopyCreateRequest(Irp,
KSSTRING_Pin,
&Size,
(PVOID*)&ConnectDetails);
/* check for success */
if (!NT_SUCCESS(Status))
return Status;
/* is pin id out of bounds */
if (ConnectDetails->PinId >= DescriptorsCount)
{
FreeItem(ConnectDetails);
return STATUS_INVALID_PARAMETER;
}
if (DescriptorSize == sizeof(KSPIN_DESCRIPTOR))
{
/* standard pin descriptor */
Descriptor = (PKSPIN_DESCRIPTOR)((ULONG_PTR)Descriptors + sizeof(KSPIN_DESCRIPTOR) * ConnectDetails->PinId);
}
else
{
/* extended / variable pin descriptor */
Descriptor = &((PKSPIN_DESCRIPTOR_EX)((ULONG_PTR)Descriptors + DescriptorSize * ConnectDetails->PinId))->PinDescriptor;
}
/* does the pin have interface details filled in */
if (Descriptor->InterfacesCount && Descriptor->Interfaces)
{
/* use provided pin interface count */
Count = Descriptor->InterfacesCount;
Interface = (PKSPIN_INTERFACE)Descriptor->Interfaces;
}
else
{
/* use standard pin interface */
Count = 1;
Interface = &StandardPinInterface;
}
/* now check the interface */
Found = FALSE;
Index = 0;
RtlStringFromGUID(&ConnectDetails->Interface.Set, &GuidString2);
do
{
UNICODE_STRING GuidString;
RtlStringFromGUID(&Interface[Index].Set, &GuidString);
DPRINT("Driver Interface %S Id %u\n", GuidString.Buffer, Interface[Index].Id);
DPRINT("Connect Interface %S Id %u\n", GuidString2.Buffer, ConnectDetails->Interface.Id);
RtlFreeUnicodeString(&GuidString);
if (IsEqualGUIDAligned(&Interface[Index].Set, &ConnectDetails->Interface.Set) &&
Interface[Index].Id == ConnectDetails->Interface.Id)
{
/* found a matching interface */
Found = TRUE;
break;
}
/* iterate to next interface */
Index++;
}while(Index < Count);
RtlFreeUnicodeString(&GuidString2);
if (!Found)
{
/* pin doesnt support this interface */
FreeItem(ConnectDetails);
return STATUS_NO_MATCH;
}
/* does the pin have medium details filled in */
if (Descriptor->MediumsCount && Descriptor->Mediums)
{
/* use provided pin interface count */
Count = Descriptor->MediumsCount;
Medium = (PKSPIN_MEDIUM)Descriptor->Mediums;
}
else
{
/* use standard pin interface */
Count = 1;
Medium = &StandardPinMedium;
}
/* now check the interface */
Found = FALSE;
Index = 0;
RtlStringFromGUID(&ConnectDetails->Medium.Set, &GuidString2);
do
{
UNICODE_STRING GuidString;
RtlStringFromGUID(&Medium[Index].Set, &GuidString);
DPRINT("Driver Medium %S Id %u\n", GuidString.Buffer, Medium[Index].Id);
DPRINT("Connect Medium %S Id %u\n", GuidString2.Buffer, ConnectDetails->Medium.Id);
RtlFreeUnicodeString(&GuidString);
if (IsEqualGUIDAligned(&Medium[Index].Set, &ConnectDetails->Medium.Set) &&
Medium[Index].Id == ConnectDetails->Medium.Id)
{
/* found a matching interface */
Found = TRUE;
break;
}
/* iterate to next medium */
Index++;
}while(Index < Count);
RtlFreeUnicodeString(&GuidString2);
if (!Found)
{
/* pin doesnt support this medium */
FreeItem(ConnectDetails);
return STATUS_NO_MATCH;
}
/// FIXME
/// implement format checking
*Connect = ConnectDetails;
return STATUS_SUCCESS;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsValidateConnectRequest(
IN PIRP Irp,
IN ULONG DescriptorsCount,
IN KSPIN_DESCRIPTOR* Descriptor,
OUT PKSPIN_CONNECT* Connect)
{
return KspValidateConnectRequest(Irp, DescriptorsCount, Descriptor, sizeof(KSPIN_DESCRIPTOR), Connect);
}
NTSTATUS
KspReadMediaCategory(
IN LPGUID Category,
PKEY_VALUE_PARTIAL_INFORMATION *OutInformation)
{
UNICODE_STRING MediaPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Name");
UNICODE_STRING GuidString, Path;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hKey;
ULONG Size;
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
/* convert the guid to string */
Status = RtlStringFromGUID(Category, &GuidString);
if (!NT_SUCCESS(Status))
return Status;
/* allocate buffer for the registry key */
Path.Length = 0;
Path.MaximumLength = MediaPath.MaximumLength + GuidString.MaximumLength;
Path.Buffer = AllocateItem(NonPagedPool, Path.MaximumLength);
if (!Path.Buffer)
{
/* not enough memory */
RtlFreeUnicodeString(&GuidString);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlAppendUnicodeStringToString(&Path, &MediaPath);
RtlAppendUnicodeStringToString(&Path, &GuidString);
/* free guid string */
RtlFreeUnicodeString(&GuidString);
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
/* open the key */
Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
DPRINT("ZwOpenKey() status 0x%08lx %wZ\n", Status, &Path);
/* free path buffer */
FreeItem(Path.Buffer);
/* check for success */
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
return Status;
}
/* query the name size */
Status = ZwQueryValueKey(hKey, &Name, KeyValuePartialInformation, NULL, 0, &Size);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
{
/* failed to query for name key */
ZwClose(hKey);
return Status;
}
/* allocate buffer to read key info */
KeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION) AllocateItem(NonPagedPool, Size);
if (!KeyInfo)
{
/* not enough memory */
ZwClose(hKey);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* now read the info */
Status = ZwQueryValueKey(hKey, &Name, KeyValuePartialInformation, (PVOID)KeyInfo, Size, &Size);
/* close the key */
ZwClose(hKey);
if (!NT_SUCCESS(Status))
{
/* failed to read key */
FreeItem(KeyInfo);
return Status;
}
/* store key information */
*OutInformation = KeyInfo;
return Status;
}
KSDDKAPI
NTSTATUS
NTAPI
KspPinPropertyHandler(
IN PIRP Irp,
IN PKSPROPERTY Property,
IN OUT PVOID Data,
IN ULONG DescriptorsCount,
IN const KSPIN_DESCRIPTOR* Descriptors,
IN ULONG DescriptorSize)
{
KSP_PIN * Pin;
KSMULTIPLE_ITEM * Item;
PIO_STACK_LOCATION IoStack;
ULONG Size, Index;
PVOID Buffer;
PKSDATARANGE_AUDIO *WaveFormatOut;
PKSDATAFORMAT_WAVEFORMATEX WaveFormatIn;
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
const KSPIN_DESCRIPTOR *Descriptor;
NTSTATUS Status = STATUS_NOT_SUPPORTED;
ULONG Count;
const PKSDATARANGE* DataRanges;
LPGUID Guid;
IoStack = IoGetCurrentIrpStackLocation(Irp);
Buffer = Data;
//DPRINT("KsPinPropertyHandler Irp %p Property %p Data %p DescriptorsCount %u Descriptor %p OutputLength %u Id %u\n", Irp, Property, Data, DescriptorsCount, Descriptor, IoStack->Parameters.DeviceIoControl.OutputBufferLength, Property->Id);
/* convert to PKSP_PIN */
Pin = (KSP_PIN*)Property;
if (Property->Id != KSPROPERTY_PIN_CTYPES)
{
if (Pin->PinId >= DescriptorsCount)
{
/* invalid parameter */
return STATUS_INVALID_PARAMETER;
}
}
else
{
(*(PULONG)Buffer) = DescriptorsCount;
Irp->IoStatus.Information = sizeof(ULONG);
return STATUS_SUCCESS;
}
if (DescriptorSize == sizeof(KSPIN_DESCRIPTOR))
{
/* it is simple pin descriptor */
Descriptor = &Descriptors[Pin->PinId];
}
else
{
/* get offset to pin descriptor */
Descriptor = &(((PKSPIN_DESCRIPTOR_EX)((ULONG_PTR)Descriptors + Pin->PinId * DescriptorSize))->PinDescriptor);
}
switch(Property->Id)
{
case KSPROPERTY_PIN_DATAFLOW:
Size = sizeof(KSPIN_DATAFLOW);
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
{
Irp->IoStatus.Information = Size;
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
*((KSPIN_DATAFLOW*)Buffer) = Descriptor->DataFlow;
Irp->IoStatus.Information = sizeof(KSPIN_DATAFLOW);
Status = STATUS_SUCCESS;
break;
case KSPROPERTY_PIN_DATARANGES:
case KSPROPERTY_PIN_CONSTRAINEDDATARANGES:
Size = sizeof(KSMULTIPLE_ITEM);
DPRINT("Id %lu PinId %lu DataRangesCount %lu ConstrainedDataRangesCount %lu\n", Property->Id, Pin->PinId, Descriptor->DataRangesCount, Descriptor->ConstrainedDataRangesCount);
if (Property->Id == KSPROPERTY_PIN_DATARANGES || Descriptor->ConstrainedDataRangesCount == 0)
{
DataRanges = Descriptor->DataRanges;
Count = Descriptor->DataRangesCount;
}
else
{
DataRanges = Descriptor->ConstrainedDataRanges;
Count = Descriptor->ConstrainedDataRangesCount;
}
for (Index = 0; Index < Count; Index++)
{
Size += ((DataRanges[Index]->FormatSize + 0x7) & ~0x7);
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0)
{
/* buffer too small */
Irp->IoStatus.Information = Size;
Status = STATUS_BUFFER_OVERFLOW;
break;
}
Item = (KSMULTIPLE_ITEM*)Buffer;
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
{
/* store the result size */
Item->Size = Size;
Irp->IoStatus.Information = sizeof(ULONG);
Status = STATUS_SUCCESS;
break;
}
/* store descriptor size */
Item->Size = Size;
Item->Count = Count;
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
{
Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
Status = STATUS_SUCCESS;
break;
}
/* now copy all dataranges */
Data = (PUCHAR)(Item +1);
/* alignment assert */
ASSERT(((ULONG_PTR)Data & 0x7) == 0);
for (Index = 0; Index < Count; Index++)
{
UNICODE_STRING GuidString;
/* convert the guid to string */
RtlStringFromGUID(&DataRanges[Index]->MajorFormat, &GuidString);
DPRINT("Index %lu MajorFormat %S\n", Index, GuidString.Buffer);
RtlStringFromGUID(&DataRanges[Index]->SubFormat, &GuidString);
DPRINT("Index %lu SubFormat %S\n", Index, GuidString.Buffer);
RtlStringFromGUID(&DataRanges[Index]->Specifier, &GuidString);
DPRINT("Index %lu Specifier %S\n", Index, GuidString.Buffer);
RtlStringFromGUID(&DataRanges[Index]->Specifier, &GuidString);
DPRINT("Index %lu FormatSize %lu Flags %lu SampleSize %lu Reserved %lu KSDATAFORMAT %lu\n", Index,
DataRanges[Index]->FormatSize, DataRanges[Index]->Flags, DataRanges[Index]->SampleSize, DataRanges[Index]->Reserved, sizeof(KSDATAFORMAT));
RtlMoveMemory(Data, DataRanges[Index], DataRanges[Index]->FormatSize);
Data = ((PUCHAR)Data + DataRanges[Index]->FormatSize);
/* alignment assert */
ASSERT(((ULONG_PTR)Data & 0x7) == 0);
Data = (PVOID)(((ULONG_PTR)Data + 0x7) & ~0x7);
}
Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Size;
break;
case KSPROPERTY_PIN_INTERFACES:
if (Descriptor->Interfaces)
{
/* use mediums provided by driver */
return KsHandleSizedListQuery(Irp, Descriptor->InterfacesCount, sizeof(KSPIN_MEDIUM), Descriptor->Interfaces);
}
else
{
/* use standard medium */
return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_INTERFACE), &StandardPinInterface);
}
break;
case KSPROPERTY_PIN_MEDIUMS:
if (Descriptor->MediumsCount)
{
/* use mediums provided by driver */
return KsHandleSizedListQuery(Irp, Descriptor->MediumsCount, sizeof(KSPIN_MEDIUM), Descriptor->Mediums);
}
else
{
/* use standard medium */
return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_MEDIUM), &StandardPinMedium);
}
break;
case KSPROPERTY_PIN_COMMUNICATION:
Size = sizeof(KSPIN_COMMUNICATION);
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
{
Irp->IoStatus.Information = Size;
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
*((KSPIN_COMMUNICATION*)Buffer) = Descriptor->Communication;
Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Size;
break;
case KSPROPERTY_PIN_CATEGORY:
if (!Descriptor->Category)
{
/* no pin category */
return STATUS_NOT_FOUND;
}
/* check size */
Size = sizeof(GUID);
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
{
/* buffer too small */
Irp->IoStatus.Information = Size;
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
/* copy category guid */
RtlMoveMemory(Buffer, Descriptor->Category, sizeof(GUID));
/* save result */
Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Size;
break;
case KSPROPERTY_PIN_NAME:
if (Descriptor->Name)
{
/* use pin name */
Guid = (LPGUID)Descriptor->Name;
}
else
{
/* use pin category as fallback */
Guid = (LPGUID)Descriptor->Category;
}
if (!Guid)
{
/* no friendly name available */
return STATUS_NOT_FOUND;
}
/* read friendly name category name */
Status = KspReadMediaCategory(Guid, &KeyInfo);
if (!NT_SUCCESS(Status))
{
/* failed to read category */
Irp->IoStatus.Information = 0;
break;
}
/* store required length */
Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
/* check if buffer is too small */
if (KeyInfo->DataLength + sizeof(WCHAR) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
{
/* buffer too small */
Status = STATUS_BUFFER_OVERFLOW;
FreeItem(KeyInfo);
break;
}
/* copy result */
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, &KeyInfo->Data, KeyInfo->DataLength);
/* null terminate name */
((LPWSTR)Irp->AssociatedIrp.SystemBuffer)[KeyInfo->DataLength / sizeof(WCHAR)] = L'\0';
/* free key info */
FreeItem(KeyInfo);
break;
case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
Size = sizeof(KSDATAFORMAT);
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
{
Irp->IoStatus.Information = Size;
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(KSDATAFORMAT_WAVEFORMATEX))
{
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
Irp->IoStatus.Information = 0;
break;
}
WaveFormatIn = (PKSDATAFORMAT_WAVEFORMATEX)Buffer;
if (!Descriptor->DataRanges || !Descriptor->DataRangesCount)
{
Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
break;
}
WaveFormatOut = (PKSDATARANGE_AUDIO*)Descriptor->DataRanges;
for(Index = 0; Index < Descriptor->DataRangesCount; Index++)
{
if (WaveFormatOut[Index]->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
{
UNIMPLEMENTED;
continue;
}
if (WaveFormatOut[Index]->MinimumSampleFrequency > WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
WaveFormatOut[Index]->MaximumSampleFrequency < WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
WaveFormatOut[Index]->MinimumBitsPerSample > WaveFormatIn->WaveFormatEx.wBitsPerSample ||
WaveFormatOut[Index]->MaximumBitsPerSample < WaveFormatIn->WaveFormatEx.wBitsPerSample ||
WaveFormatOut[Index]->MaximumChannels < WaveFormatIn->WaveFormatEx.nChannels)
{
Irp->IoStatus.Status = STATUS_NO_MATCH;
Irp->IoStatus.Information = 0;
return STATUS_NO_MATCH;
}
else
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
return STATUS_SUCCESS;
}
}
Status = STATUS_NO_MATCH;
Irp->IoStatus.Information = 0;
break;
default:
DPRINT1("Unhandled property request %x\n", Property->Id);
Status = STATUS_NOT_IMPLEMENTED;
Irp->IoStatus.Information = 0;
}
return Status;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsPinPropertyHandler(
IN PIRP Irp,
IN PKSPROPERTY Property,
IN OUT PVOID Data,
IN ULONG DescriptorsCount,
IN const KSPIN_DESCRIPTOR* Descriptor)
{
return KspPinPropertyHandler(Irp, Property, Data, DescriptorsCount, Descriptor, sizeof(KSPIN_DESCRIPTOR));
}
/*
@unimplemented
*/
KSDDKAPI NTSTATUS NTAPI
KsPinDataIntersectionEx(
IN PIRP Irp,
IN PKSP_PIN Pin,
OUT PVOID Data,
IN ULONG DescriptorsCount,
IN const KSPIN_DESCRIPTOR* Descriptor,
IN ULONG DescriptorSize,
IN PFNKSINTERSECTHANDLEREX IntersectHandler OPTIONAL,
IN PVOID HandlerContext OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_UNSUCCESSFUL;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsPinDataIntersection(
IN PIRP Irp,
IN PKSP_PIN Pin,
OUT PVOID Data,
IN ULONG DescriptorsCount,
IN const KSPIN_DESCRIPTOR* Descriptor,
IN PFNKSINTERSECTHANDLER IntersectHandler)
{
KSMULTIPLE_ITEM * Item;
KSDATARANGE * DataRange;
PIO_STACK_LOCATION IoStack;
ULONG Size;
ULONG Index;
NTSTATUS Status;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* calculate minimum data size */
Size = sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATARANGE);
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < Size)
{
/* buffer too small */
Irp->IoStatus.Information = Size;
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
return STATUS_BUFFER_TOO_SMALL;
}
/* is pin id out of bounds */
if (Pin->PinId >= DescriptorsCount)
{
/* it is */
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
return STATUS_INVALID_PARAMETER;
}
/* get start item */
Item = (KSMULTIPLE_ITEM*)(Pin + 1);
/* get first data range */
DataRange = (KSDATARANGE*)(Item + 1);
/* iterate through all data ranges */
for(Index = 0; Index < Item->Count; Index++, DataRange++)
{
/* call intersect handler */
Status = IntersectHandler(Irp, Pin, DataRange, Data);
if (NT_SUCCESS(Status))
{
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < DataRange->FormatSize)
{
/* buffer is too small */
Irp->IoStatus.Information = DataRange->FormatSize;
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
return STATUS_BUFFER_TOO_SMALL;
}
RtlMoveMemory(Irp->UserBuffer, DataRange, sizeof(KSDATARANGE));
Irp->IoStatus.Information = sizeof(KSDATARANGE);
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_NO_MATCH;
return STATUS_NO_MATCH;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsHandleSizedListQuery(
IN PIRP Irp,
IN ULONG DataItemsCount,
IN ULONG DataItemSize,
IN const VOID* DataItems)
{
ULONG Size;
PIO_STACK_LOCATION IoStack;
PKSMULTIPLE_ITEM Item;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* calculate size */
Size = DataItemSize * DataItemsCount + sizeof(KSMULTIPLE_ITEM);
/* get multiple item */
Item = (PKSMULTIPLE_ITEM)Irp->AssociatedIrp.SystemBuffer;
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0)
{
/* buffer too small */
Irp->IoStatus.Information = Size;
return STATUS_BUFFER_OVERFLOW;
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
{
/* store just the size */
Item->Size = Size;
Irp->IoStatus.Information = sizeof(ULONG);
return STATUS_SUCCESS;
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSMULTIPLE_ITEM))
{
/* buffer too small */
return STATUS_BUFFER_TOO_SMALL;
}
Item->Count = DataItemsCount;
Item->Size = DataItemSize;
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
{
/* buffer can only hold the length descriptor */
Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
return STATUS_SUCCESS;
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= Size)
{
/* copy items */
RtlMoveMemory((PVOID)(Item + 1), DataItems, DataItemSize * DataItemsCount);
/* store result */
Irp->IoStatus.Information = Size;
/* done */
return STATUS_SUCCESS;
}
else
{
/* buffer too small */
return STATUS_BUFFER_TOO_SMALL;
}
}