[KS]
[reactos.git] / reactos / drivers / ksfilter / ks / connectivity.c
index 7b79f51..bcc55cc 100644 (file)
@@ -9,6 +9,22 @@
 
 #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
 */
@@ -38,73 +54,151 @@ KsCreatePin(
                                ConnectionHandle);
 }
 
-/*
-    @unimplemented
-*/
-KSDDKAPI
 NTSTATUS
-NTAPI
-KsValidateConnectRequest(
-    IN  PIRP Irp,
-    IN  ULONG DescriptorsCount,
-    IN  KSPIN_DESCRIPTOR* Descriptor,
+KspValidateConnectRequest(
+    IN PIRP Irp,
+    IN ULONG DescriptorsCount,
+    IN PVOID Descriptors,
+    IN ULONG DescriptorSize,
     OUT PKSPIN_CONNECT* Connect)
 {
-    PIO_STACK_LOCATION IoStack;
     PKSPIN_CONNECT ConnectDetails;
-    LPWSTR PinName = L"{146F1A80-4791-11D0-A5D6-28DB04C10000}\\";
-    PKSDATAFORMAT DataFormat;
-    LPWSTR Offset;
+    PKSPIN_INTERFACE Interface;
+    PKSPIN_MEDIUM Medium;
+    ULONG Size;
+    NTSTATUS Status;
+    ULONG Index;
+    ULONG Count;
+    BOOLEAN Found;
+    PKSPIN_DESCRIPTOR Descriptor;
 
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    if (!IoStack->FileObject->FileName.Buffer)
+    /* did the caller miss the connect parameter */
+    if (!Connect)
         return STATUS_INVALID_PARAMETER;
 
-    if (IoStack->FileObject->FileName.Length < wcslen(PinName) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT))
+    /* 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;
 
-    Offset = wcsstr(IoStack->FileObject->FileName.Buffer, PinName);
-    if (!Offset)
+    if (DescriptorSize == sizeof(KSPIN_DESCRIPTOR))
     {
-        /* request is not targeted for a pin */
-        return STATUS_INVALID_PARAMETER;
+        /* 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;
     }
 
-    ConnectDetails = (PKSPIN_CONNECT)(Offset + wcslen(PinName));
 
-    if (ConnectDetails->PinToHandle != NULL)
+    /* 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
     {
-        UNIMPLEMENTED
-        return STATUS_NOT_IMPLEMENTED;
+        /* 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
+    {
+        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 0
-    if (!IsEqualGUIDAligned(&ConnectDetails->Interface.Set, &KSINTERFACESETID_Standard) &&
-         ConnectDetails->Interface.Id != KSINTERFACE_STANDARD_STREAMING)
+    if (!Found)
     {
-         //FIXME
-         // validate provided interface set
-         DPRINT1("FIXME\n");
+        /* pin doesnt support this interface */
+        return STATUS_NO_MATCH;
     }
 
-    if (!IsEqualGUIDAligned(&ConnectDetails->Medium.Set, &KSMEDIUMSETID_Standard) &&
-         ConnectDetails->Medium.Id != KSMEDIUM_TYPE_ANYINSTANCE)
+    /* 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
     {
-         //FIXME
-         // validate provided medium set
-         DPRINT1("FIXME\n");
+        /* 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;
     }
-#endif
 
     /// FIXME
     /// implement format checking
 
-    DataFormat = (PKSDATAFORMAT) (ConnectDetails + 1);
     *Connect = ConnectDetails;
-
     return STATUS_SUCCESS;
 }
 
@@ -114,12 +208,115 @@ KsValidateConnectRequest(
 KSDDKAPI
 NTSTATUS
 NTAPI
-KsPinPropertyHandler(
+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 = 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
+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;
@@ -128,223 +325,259 @@ KsPinPropertyHandler(
     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;
 
+    //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);
-            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;
             }
-            Size = sizeof(KSMULTIPLE_ITEM);
-            for (Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
+            else
             {
-                Size += Descriptor[Pin->PinId].DataRanges[Index]->FormatSize;
+                DataRanges = Descriptor->ConstrainedDataRanges;
+                Count = Descriptor->ConstrainedDataRangesCount;
             }
 
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            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;
-                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;
 
-            Data = (PUCHAR)(Item +1);
-            for (Index = 0; Index < Descriptor[Pin->PinId].DataRangesCount; Index++)
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
             {
-                RtlMoveMemory(Data, Descriptor[Pin->PinId].DataRanges[Index], Descriptor[Pin->PinId].DataRanges[Index]->FormatSize);
-                Data = ((PUCHAR)Data + Descriptor[Pin->PinId].DataRanges[Index]->FormatSize);
+                /* store the result size */
+                Item->Size = Size;
+                Irp->IoStatus.Information = sizeof(ULONG);
+                Status = STATUS_SUCCESS;
+                break;
             }
 
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
-            break;
-        case KSPROPERTY_PIN_INTERFACES:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+            /* store descriptor size */
+            Item->Size = Size;
+            Item->Count = Count;
+
+            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
+                Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
+                Status = STATUS_SUCCESS;
                 break;
             }
 
-            Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSPIN_INTERFACE) * Descriptor[Pin->PinId].InterfacesCount;
+            /* now copy all dataranges */
+            Data = (PUCHAR)(Item +1);
 
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            /* alignment assert */
+            ASSERT(((ULONG_PTR)Data & 0x7) == 0);
+
+            for (Index = 0; Index < Count; Index++)
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                break;
+                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);
             }
 
-            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;
+            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);
-            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+            Status = KspReadMediaCategory((LPGUID)Descriptor->Name, &KeyInfo);
+            if (!NT_SUCCESS(Status))
             {
-                Irp->IoStatus.Information = Size;
-                Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
                 break;
             }
 
+            Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
 
-            RtlMoveMemory(Buffer, &Descriptor[Pin->PinId].Name, sizeof(GUID));
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            Irp->IoStatus.Information = Size;
-            break;
-        case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
-            Pin = (KSP_PIN*)Property;
-            if (Pin->PinId >= DescriptorsCount)
+            if (KeyInfo->DataLength + sizeof(WCHAR) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
             {
-                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                Irp->IoStatus.Information = 0;
+                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
-                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)
+            if (!Descriptor->DataRanges || !Descriptor->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++)
+            WaveFormatOut = (PKSDATARANGE_AUDIO*)Descriptor->DataRanges;
+            for(Index = 0; Index < Descriptor->DataRangesCount; Index++)
             {
                 if (WaveFormatOut[Index]->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
                 {
@@ -369,16 +602,50 @@ 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;
+}
+
+/*
+    @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;
 }
 
 /*
@@ -402,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;
             }
@@ -447,7 +722,7 @@ KsPinDataIntersection(
 }
 
 /*
-    @unimplemented
+    @implemented
 */
 
 KSDDKAPI
@@ -459,5 +734,66 @@ KsHandleSizedListQuery(
     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;
+    }
 }
+