mirror of
https://github.com/reactos/reactos.git
synced 2024-09-17 16:20:20 +00:00
1fb94b1cb5
sync with trunk (r49230) svn path=/branches/cmake-bringup/; revision=49246
830 lines
25 KiB
C
830 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 "priv.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))
|
|
{
|
|
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;
|
|
|
|
/* 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)
|
|
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;
|
|
do
|
|
{
|
|
UNICODE_STRING GuidString, GuidString2;
|
|
RtlStringFromGUID(&Interface[Index].Set, &GuidString);
|
|
RtlStringFromGUID(&ConnectDetails->Interface.Set, &GuidString2);
|
|
|
|
DPRINT("Driver Interface %S Id %u\n", GuidString.Buffer, Interface[Index].Id);
|
|
DPRINT("Connect Interface %S Id %u\n", GuidString2.Buffer, ConnectDetails->Interface.Id);
|
|
|
|
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);
|
|
|
|
if (!Found)
|
|
{
|
|
/* pin doesnt support this interface */
|
|
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;
|
|
do
|
|
{
|
|
UNICODE_STRING GuidString, GuidString2;
|
|
RtlStringFromGUID(&Medium[Index].Set, &GuidString);
|
|
RtlStringFromGUID(&ConnectDetails->Medium.Set, &GuidString2);
|
|
|
|
DPRINT("Driver Medium %S Id %u\n", GuidString.Buffer, Medium[Index].Id);
|
|
DPRINT("Connect Medium %S Id %u\n", GuidString2.Buffer, ConnectDetails->Medium.Id);
|
|
|
|
|
|
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);
|
|
|
|
if (!Found)
|
|
{
|
|
/* pin doesnt support this medium */
|
|
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, 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 = Irp->UserBuffer;
|
|
|
|
//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;
|
|
}
|
|
}
|
|
|
|
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_CTYPES:
|
|
(*(PULONG)Buffer) = DescriptorsCount;
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
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->UserBuffer, &KeyInfo->Data, KeyInfo->DataLength);
|
|
|
|
/* null terminate name */
|
|
((LPWSTR)Irp->UserBuffer)[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->UserBuffer;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|