[KS]
[reactos.git] / reactos / drivers / ksfilter / ks / connectivity.c
index bdec7e3..bcc55cc 100644 (file)
@@ -1,6 +1,36 @@
+/*
+ * 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"
 
-KSDDKAPI NTSTATUS NTAPI
+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,
@@ -17,47 +47,316 @@ KsCreatePin(
     }
 
     return KspCreateObjectType(FilterHandle,
-                               L"{146F1A80-4791-11D0-A5D6-28DB04C10000}",
+                               KSSTRING_Pin,
                                (PVOID)Connect,
                                ConnectSize,
                                DesiredAccess,
                                ConnectionHandle);
 }
 
-KSDDKAPI NTSTATUS NTAPI
+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 STATUS_SUCCESS;
+    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 = ExAllocatePool(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 %S\n", Status, Path.Buffer);
+
+    /* free path buffer */
+    ExFreePool(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) ExAllocatePool(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 */
+        ExFreePool(KeyInfo);
+        return Status;
+    }
+
+    /* store key information */
+    *OutInformation = KeyInfo;
+    return Status;
 }
 
 KSDDKAPI
 NTSTATUS
 NTAPI
-KsPinPropertyHandler(
+KspPinPropertyHandler(
     IN  PIRP Irp,
     IN  PKSPROPERTY Property,
     IN  OUT PVOID Data,
     IN  ULONG DescriptorsCount,
-    IN  const KSPIN_DESCRIPTOR* Descriptor)
+    IN  const KSPIN_DESCRIPTOR* Descriptors,
+    IN  ULONG DescriptorSize)
 {
     KSP_PIN * Pin;
     KSMULTIPLE_ITEM * Item;
     PIO_STACK_LOCATION IoStack;
-    ULONG Size;
+    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;
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
     Buffer = Irp->UserBuffer;
 
-    if (Property->Flags != KSPROPERTY_TYPE_GET)
+    //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)
     {
-        Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
-        Irp->IoStatus.Information = 0;
-        return STATUS_NOT_IMPLEMENTED;
+        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)
@@ -65,182 +364,293 @@ KsPinPropertyHandler(
         case KSPROPERTY_PIN_CTYPES:
             (*(PULONG)Buffer) = DescriptorsCount;
             Irp->IoStatus.Information = sizeof(ULONG);
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             break;
         case KSPROPERTY_PIN_DATAFLOW:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
-            {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
-                break;
-            }
+
             Size = sizeof(KSPIN_DATAFLOW);
             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
             {
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_BUFFER_TOO_SMALL;
                 break;
             }
 
-            *((KSPIN_DATAFLOW*)Buffer) = Descriptor[Pin->PinId].DataFlow;
+            *((KSPIN_DATAFLOW*)Buffer) = Descriptor->DataFlow;
             Irp->IoStatus.Information = sizeof(KSPIN_DATAFLOW);
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             break;
 
         case KSPROPERTY_PIN_DATARANGES:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+        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)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
-                break;
+                DataRanges = Descriptor->DataRanges;
+                Count = Descriptor->DataRangesCount;
+            }
+            else
+            {
+                DataRanges = Descriptor->ConstrainedDataRanges;
+                Count = Descriptor->ConstrainedDataRangesCount;
             }
 
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATARANGE) * Descriptor[Pin->PinId].DataRangesCount;
+            for (Index = 0; Index < Count; Index++)
+            {
+                Size += ((DataRanges[Index]->FormatSize + 0x7) & ~0x7);
+            }
 
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0)
             {
+                /* buffer too small */
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_BUFFER_OVERFLOW;
                 break;
             }
 
             Item = (KSMULTIPLE_ITEM*)Buffer;
-            Item->Size = Size;
-            Item->Count = Descriptor[Pin->PinId].DataRangesCount;
-            RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].DataRanges, Descriptor[Pin->PinId].DataRangesCount * sizeof(KSDATARANGE));
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
-            break;
-        case KSPROPERTY_PIN_INTERFACES:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
+                /* store the result size */
+                Item->Size = Size;
+                Irp->IoStatus.Information = sizeof(ULONG);
+                Status = STATUS_SUCCESS;
                 break;
             }
 
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_INTERFACE) * Descriptor[Pin->PinId].InterfacesCount;
+            /* store descriptor size */
+            Item->Size = Size;
+            Item->Count = Count;
 
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
+                Status = STATUS_SUCCESS;
                 break;
             }
 
-            Item = (KSMULTIPLE_ITEM*)Buffer;
-            Item->Size = Size;
-            Item->Count = Descriptor[Pin->PinId].InterfacesCount;
-            RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].Interfaces, Descriptor[Pin->PinId].InterfacesCount * sizeof(KSDATARANGE));
+            /* now copy all dataranges */
+            Data = (PUCHAR)(Item +1);
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            /* 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_MEDIUMS:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+        case KSPROPERTY_PIN_INTERFACES:
+
+            if (Descriptor->Interfaces)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
-                break;
+                /* use mediums provided by driver */
+                return KsHandleSizedListQuery(Irp, Descriptor->InterfacesCount, sizeof(KSPIN_MEDIUM), Descriptor->Interfaces);
             }
-
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_MEDIUM) * Descriptor[Pin->PinId].MediumsCount;
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            else
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                break;
+                /* use standard medium */
+                return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_INTERFACE), &StandardPinInterface);
             }
+            break;
 
-            Item = (KSMULTIPLE_ITEM*)Buffer;
-            Item->Size = Size;
-            Item->Count = Descriptor[Pin->PinId].MediumsCount;
-            RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].Mediums, Descriptor[Pin->PinId].MediumsCount * sizeof(KSDATARANGE));
+        case KSPROPERTY_PIN_MEDIUMS:
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
+            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:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
-            {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
-                break;
-            }
 
             Size = sizeof(KSPIN_COMMUNICATION);
             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
             {
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_BUFFER_TOO_SMALL;
                 break;
             }
 
-            *((KSPIN_COMMUNICATION*)Buffer) = Descriptor[Pin->PinId].Communication;
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            *((KSPIN_COMMUNICATION*)Buffer) = Descriptor->Communication;
+
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
 
         case KSPROPERTY_PIN_CATEGORY:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
-            {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
-                break;
-            }
 
             Size = sizeof(GUID);
             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
             {
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_BUFFER_TOO_SMALL;
                 break;
             }
+            if (Descriptor->Category)
+            {
+                RtlMoveMemory(Buffer, Descriptor->Category, sizeof(GUID));
+            }
 
-            RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Category, sizeof(GUID));
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
 
         case KSPROPERTY_PIN_NAME:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+            if (!Descriptor->Name)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
+                Status = STATUS_SUCCESS;
                 break;
             }
 
-            Size = sizeof(GUID);
+            Status = KspReadMediaCategory((LPGUID)Descriptor->Name, &KeyInfo);
+            if (!NT_SUCCESS(Status))
+            {
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
+
+            if (KeyInfo->DataLength + sizeof(WCHAR) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+            {
+                Status = STATUS_BUFFER_OVERFLOW;
+                ExFreePool(KeyInfo);
+                break;
+            }
+
+            RtlMoveMemory(Irp->UserBuffer, &KeyInfo->Data, KeyInfo->DataLength);
+            ((LPWSTR)Irp->UserBuffer)[KeyInfo->DataLength / sizeof(WCHAR)] = L'\0';
+            ExFreePool(KeyInfo);
+            break;
+        case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
+            Size = sizeof(KSDATAFORMAT);
             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
             {
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(KSDATAFORMAT_WAVEFORMATEX))
+            {
+                UNIMPLEMENTED
+                Status = STATUS_NOT_IMPLEMENTED;
+                Irp->IoStatus.Information = 0;
                 break;
             }
 
-
-            RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Name, sizeof(GUID));
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
+            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);
-            Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+            Status = STATUS_NOT_IMPLEMENTED;
             Irp->IoStatus.Information = 0;
     }
 
-    return Irp->IoStatus.Status;
+    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
@@ -259,34 +669,42 @@ KsPinDataIntersection(
     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)
     {
-        Irp->IoStatus.Information = 0;
-        Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+        /* 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;
     }
 
-    Item = (KSMULTIPLE_ITEM*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+    /* 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 < sizeof(KSDATARANGE))
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < DataRange->FormatSize)
             {
-                Irp->IoStatus.Information = sizeof(KSDATARANGE);
+                /* buffer is too small */
+                Irp->IoStatus.Information = DataRange->FormatSize;
                 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
                 return STATUS_BUFFER_TOO_SMALL;
             }
@@ -303,14 +721,79 @@ KsPinDataIntersection(
     return STATUS_NO_MATCH;
 }
 
-/* Does this belong here? */
+/*
+    @implemented
+*/
 
-KSDDKAPI NTSTATUS NTAPI
+KSDDKAPI
+NTSTATUS
+NTAPI
 KsHandleSizedListQuery(
     IN  PIRP Irp,
     IN  ULONG DataItemsCount,
     IN  ULONG DataItemSize,
     IN  const VOID* DataItems)
 {
-    return STATUS_SUCCESS;
+    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;
+    }
 }
+