[KS]
[reactos.git] / reactos / drivers / ksfilter / ks / connectivity.c
index d2744ff..3e1e296 100644 (file)
@@ -1,5 +1,29 @@
+/*
+ * 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
+};
+
+
 /*
     @implemented
 */
@@ -22,7 +46,7 @@ KsCreatePin(
     }
 
     return KspCreateObjectType(FilterHandle,
-                               L"{146F1A80-4791-11D0-A5D6-28DB04C10000}", //KSNAME_Pin
+                               KSSTRING_Pin,
                                (PVOID)Connect,
                                ConnectSize,
                                DesiredAccess,
@@ -41,61 +65,206 @@ KsValidateConnectRequest(
     IN  KSPIN_DESCRIPTOR* Descriptor,
     OUT PKSPIN_CONNECT* Connect)
 {
-    PIO_STACK_LOCATION IoStack;
     PKSPIN_CONNECT ConnectDetails;
-    LPWSTR PinName = L"{146F1A80-4791-11D0-A5D6-28DB04C10000}\\";
-    PKSDATAFORMAT DataFormat;
+    PKSPIN_INTERFACE Interface;
+    PKSPIN_MEDIUM Medium;
+    ULONG Size;
+    NTSTATUS Status;
+    ULONG Index;
+    ULONG Count;
+    BOOLEAN Found;
 
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    if (!IoStack->FileObject->FileName.Buffer)
+    /* did the caller miss the connect parameter */
+    if (!Connect)
         return STATUS_INVALID_PARAMETER;
 
-    if (wcsncmp(IoStack->FileObject->FileName.Buffer, PinName, wcslen(PinName)))
-        return STATUS_INVALID_PARAMETER;
+    /* set create param  size */
+    Size = sizeof(KSPIN_CONNECT);
 
-    ConnectDetails = (PKSPIN_CONNECT)(IoStack->FileObject->FileName.Buffer + wcslen(PinName));
+    /* fetch create parameters */
+    Status = KspCopyCreateRequest(Irp,
+                                  KSSTRING_Pin,
+                                  &Size,
+                                  (PVOID*)&ConnectDetails);
 
-    if (ConnectDetails->PinToHandle != NULL)
-    {
-        UNIMPLEMENTED
-        return STATUS_NOT_IMPLEMENTED;
-    }
+    /* check for success */
+    if (!NT_SUCCESS(Status))
+        return Status;
 
-    if (IoStack->FileObject->FileName.Length < wcslen(PinName) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT))
+    /* is pin id out of bounds */
+    if (ConnectDetails->PinId >= DescriptorsCount)
         return STATUS_INVALID_PARAMETER;
 
-    ConnectDetails = (PKSPIN_CONNECT)(IoStack->FileObject->FileName.Buffer + wcslen(PinName));
+    /* does the pin have interface details filled in */
+    if (Descriptor[ConnectDetails->PinId].InterfacesCount && Descriptor[ConnectDetails->PinId].Interfaces)
+    {
+        /* use provided pin interface count */
+        Count = Descriptor[ConnectDetails->PinId].InterfacesCount;
+        Interface = (PKSPIN_INTERFACE)Descriptor[ConnectDetails->PinId].Interfaces;
+    }
+    else
+    {
+        /* use standard pin interface */
+        Count = 1;
+        Interface = &StandardPinInterface;
+    }
 
-    if (ConnectDetails->PinId >= DescriptorsCount)
-        return STATUS_INVALID_PARAMETER;
+    /* now check the interface */
+    Found = FALSE;
+    Index = 0;
+    do
+    {
+        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;
+    }
 
-#if 0
-    if (!IsEqualGUIDAligned(&ConnectDetails->Interface.Set, &KSINTERFACESETID_Standard) &&
-         ConnectDetails->Interface.Id != KSINTERFACE_STANDARD_STREAMING)
+    /* does the pin have medium details filled in */
+    if (Descriptor[ConnectDetails->PinId].MediumsCount && Descriptor[ConnectDetails->PinId].Mediums)
     {
-         //FIXME
-         // validate provided interface set
-         DPRINT1("FIXME\n");
+        /* use provided pin interface count */
+        Count = Descriptor[ConnectDetails->PinId].MediumsCount;
+        Medium = (PKSPIN_MEDIUM)Descriptor[ConnectDetails->PinId].Mediums;
     }
+    else
+    {
+        /* use standard pin interface */
+        Count = 1;
+        Medium = &StandardPinMedium;
+    }
+
+    /* now check the interface */
+    Found = FALSE;
+    Index = 0;
+    do
+    {
+        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 (!IsEqualGUIDAligned(&ConnectDetails->Medium.Set, &KSMEDIUMSETID_Standard) &&
-         ConnectDetails->Medium.Id != KSMEDIUM_TYPE_ANYINSTANCE)
+    if (!Found)
     {
-         //FIXME
-         // validate provided medium set
-         DPRINT1("FIXME\n");
+        /* pin doesnt support this medium */
+        return STATUS_NO_MATCH;
     }
-#endif
 
     /// FIXME
     /// implement format checking
 
-    DataFormat = (PKSDATAFORMAT) (ConnectDetails + 1);
     *Connect = ConnectDetails;
-
     return STATUS_SUCCESS;
 }
 
+
+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;
+}
+
 /*
     @implemented
 */
@@ -116,22 +285,26 @@ KsPinPropertyHandler(
     PVOID Buffer;
     PKSDATARANGE_AUDIO *WaveFormatOut;
     PKSDATAFORMAT_WAVEFORMATEX WaveFormatIn;
+    PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+    NTSTATUS Status = STATUS_NOT_SUPPORTED;
 
     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);
+
     switch(Property->Id)
     {
         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;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
@@ -139,20 +312,20 @@ KsPinPropertyHandler(
             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;
             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)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
@@ -162,17 +335,44 @@ KsPinPropertyHandler(
                 Size += Descriptor[Pin->PinId].DataRanges[Index]->FormatSize;
             }
 
-            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;
+
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
+            {
+                /* store the result size */
+                Item->Size = Size;
+                Irp->IoStatus.Information = sizeof(ULONG);
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSMULTIPLE_ITEM))
+            {
+                /* buffer too small */
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            /* store descriptor size */
             Item->Size = Size;
             Item->Count = Descriptor[Pin->PinId].DataRangesCount;
 
+            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);
             for (Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
             {
@@ -180,66 +380,72 @@ KsPinPropertyHandler(
                 Data = ((PUCHAR)Data + Descriptor[Pin->PinId].DataRanges[Index]->FormatSize);
             }
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
         case KSPROPERTY_PIN_INTERFACES:
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
 
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_INTERFACE) * Descriptor[Pin->PinId].InterfacesCount;
+            /* calculate size */
+            Size = sizeof(KSMULTIPLE_ITEM);
+            Size += max(1, Descriptor[Pin->PinId].InterfacesCount) * sizeof(KSPIN_INTERFACE);
 
             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
             {
                 Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Status = STATUS_MORE_ENTRIES;
                 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));
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            if (Descriptor[Pin->PinId].InterfacesCount)
+            {
+                Item->Count = Descriptor[Pin->PinId].InterfacesCount;
+                RtlMoveMemory((PVOID)(Item + 1), Descriptor[Pin->PinId].Interfaces, Descriptor[Pin->PinId].InterfacesCount * sizeof(KSPIN_INTERFACE));
+            }
+            else
+            {
+                Item->Count = 1;
+                RtlMoveMemory((PVOID)(Item + 1), &StandardPinInterface, sizeof(KSPIN_INTERFACE));
+            }
+
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
         case KSPROPERTY_PIN_MEDIUMS:
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
 
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_MEDIUM) * Descriptor[Pin->PinId].MediumsCount;
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            if (Descriptor[Pin->PinId].MediumsCount)
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                break;
+                /* use mediums provided by driver */
+                return KsHandleSizedListQuery(Irp, Descriptor[Pin->PinId].MediumsCount, sizeof(KSPIN_MEDIUM), Descriptor[Pin->PinId].Mediums);
+            }
+            else
+            {
+                /* use standard medium */
+                return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_MEDIUM), &StandardPinMedium);
             }
-
-            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));
-
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
             break;
 
         case KSPROPERTY_PIN_COMMUNICATION:
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
@@ -248,12 +454,12 @@ KsPinPropertyHandler(
             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;
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
 
@@ -261,7 +467,7 @@ KsPinPropertyHandler(
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
@@ -270,12 +476,15 @@ KsPinPropertyHandler(
             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[Pin->PinId].Category)
+            {
+                RtlMoveMemory(Buffer, Descriptor[Pin->PinId].Category, sizeof(GUID));
+            }
 
-            RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Category, sizeof(GUID));
-            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             Irp->IoStatus.Information = Size;
             break;
 
@@ -283,29 +492,45 @@ KsPinPropertyHandler(
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
 
-            Size = sizeof(GUID);
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            if (!Descriptor[Pin->PinId].Name)
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                Status = STATUS_SUCCESS;
                 break;
             }
 
+            Status = KspReadMediaCategory((LPGUID)Descriptor[Pin->PinId].Name, &KeyInfo);
+            if (!NT_SUCCESS(Status))
+            {
+                Irp->IoStatus.Information = 0;
+                break;
+            }
 
-            RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Name, sizeof(GUID));
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
+            Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
+
+
+            if (KeyInfo->DataLength + sizeof(WCHAR) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+            {
+                Status = STATUS_MORE_ENTRIES;
+                ExFreePool(KeyInfo);
+                break;
+            }
+
+            RtlMoveMemory(Irp->UserBuffer, &KeyInfo->Data, KeyInfo->DataLength);
+            ((LPWSTR)Irp->UserBuffer)[KeyInfo->DataLength / sizeof(WCHAR)] = L'\0';
+            Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
+            ExFreePool(KeyInfo);
             break;
         case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
             Pin = (KSP_PIN*)Property;
             if (Pin->PinId >= DescriptorsCount)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                Status = STATUS_INVALID_PARAMETER;
                 Irp->IoStatus.Information = 0;
                 break;
             }
@@ -313,23 +538,23 @@ KsPinPropertyHandler(
             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
-                Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+                Status = STATUS_NOT_IMPLEMENTED;
                 Irp->IoStatus.Information = 0;
-                return STATUS_NOT_IMPLEMENTED;
+                break;
             }
 
             WaveFormatIn = (PKSDATAFORMAT_WAVEFORMATEX)Buffer;
             if (!Descriptor[Pin->PinId].DataRanges || !Descriptor[Pin->PinId].DataRangesCount)
             {
-                Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+                Status = STATUS_UNSUCCESSFUL;
                 Irp->IoStatus.Information = 0;
-                return STATUS_UNSUCCESSFUL;
+                break;
             }
             WaveFormatOut = (PKSDATARANGE_AUDIO*)Descriptor[Pin->PinId].DataRanges;
             for(Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
@@ -357,16 +582,34 @@ KsPinPropertyHandler(
                     return STATUS_SUCCESS;
                 }
             }
-            Irp->IoStatus.Status = STATUS_NO_MATCH;
+            Status = STATUS_NO_MATCH;
             Irp->IoStatus.Information = 0;
-            return STATUS_NO_MATCH;
+            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;
+}
+
+/*
+    @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;
 }
 
 /*
@@ -390,34 +633,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;
             }
@@ -434,14 +685,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;
+    }
 }
+