xref: /reactos/drivers/ksfilter/ks/connectivity.c (revision 1734f297)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/connectivity.c
5  * PURPOSE:         KS Pin functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 KSPIN_INTERFACE StandardPinInterface =
15 {
16     {STATIC_KSINTERFACESETID_Standard},
17     KSINTERFACE_STANDARD_STREAMING,
18     0
19 };
20 
21 KSPIN_MEDIUM StandardPinMedium =
22 {
23     {STATIC_KSMEDIUMSETID_Standard},
24     KSMEDIUM_TYPE_ANYINSTANCE,
25     0
26 };
27 
28 const GUID KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT = {0xf4aeb342, 0x0329, 0x4fdd, {0xa8, 0xfd, 0x4a, 0xff, 0x49, 0x26, 0xc9, 0x78}};
29 
30 /*
31     @implemented
32 */
33 KSDDKAPI
34 NTSTATUS
35 NTAPI
36 KsCreatePin(
37     IN  HANDLE FilterHandle,
38     IN  PKSPIN_CONNECT Connect,
39     IN  ACCESS_MASK DesiredAccess,
40     OUT PHANDLE ConnectionHandle)
41 {
42     UINT ConnectSize = sizeof(KSPIN_CONNECT);
43 
44     PKSDATAFORMAT_WAVEFORMATEX Format = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1);
45     if (Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) ||
46         Format->DataFormat.FormatSize == sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX))
47     {
48         ConnectSize += Format->DataFormat.FormatSize;
49     }
50 
51     return KspCreateObjectType(FilterHandle,
52                                KSSTRING_Pin,
53                                (PVOID)Connect,
54                                ConnectSize,
55                                DesiredAccess,
56                                ConnectionHandle);
57 }
58 
59 NTSTATUS
60 KspValidateConnectRequest(
61     IN PIRP Irp,
62     IN ULONG DescriptorsCount,
63     IN PVOID Descriptors,
64     IN ULONG DescriptorSize,
65     OUT PKSPIN_CONNECT* Connect)
66 {
67     PKSPIN_CONNECT ConnectDetails;
68     PKSPIN_INTERFACE Interface;
69     PKSPIN_MEDIUM Medium;
70     ULONG Size;
71     NTSTATUS Status;
72     ULONG Index;
73     ULONG Count;
74     BOOLEAN Found;
75     PKSPIN_DESCRIPTOR Descriptor;
76     UNICODE_STRING GuidString2;
77 
78     /* did the caller miss the connect parameter */
79     if (!Connect)
80         return STATUS_INVALID_PARAMETER;
81 
82     /* set create param  size */
83     Size = sizeof(KSPIN_CONNECT);
84 
85     /* fetch create parameters */
86     Status = KspCopyCreateRequest(Irp,
87                                   KSSTRING_Pin,
88                                   &Size,
89                                   (PVOID*)&ConnectDetails);
90 
91     /* check for success */
92     if (!NT_SUCCESS(Status))
93         return Status;
94 
95     /* is pin id out of bounds */
96     if (ConnectDetails->PinId >= DescriptorsCount)
97     {
98         FreeItem(ConnectDetails);
99         return STATUS_INVALID_PARAMETER;
100     }
101 
102     if (DescriptorSize == sizeof(KSPIN_DESCRIPTOR))
103     {
104         /* standard pin descriptor */
105         Descriptor = (PKSPIN_DESCRIPTOR)((ULONG_PTR)Descriptors + sizeof(KSPIN_DESCRIPTOR) * ConnectDetails->PinId);
106     }
107     else
108     {
109         /* extended / variable pin descriptor */
110         Descriptor = &((PKSPIN_DESCRIPTOR_EX)((ULONG_PTR)Descriptors + DescriptorSize * ConnectDetails->PinId))->PinDescriptor;
111     }
112 
113 
114     /* does the pin have interface details filled in */
115     if (Descriptor->InterfacesCount && Descriptor->Interfaces)
116     {
117         /* use provided pin interface count */
118         Count = Descriptor->InterfacesCount;
119         Interface = (PKSPIN_INTERFACE)Descriptor->Interfaces;
120     }
121     else
122     {
123         /* use standard pin interface */
124         Count = 1;
125         Interface = &StandardPinInterface;
126     }
127 
128     /* now check the interface */
129     Found = FALSE;
130     Index = 0;
131     RtlStringFromGUID(&ConnectDetails->Interface.Set, &GuidString2);
132     do
133     {
134         UNICODE_STRING GuidString;
135         RtlStringFromGUID(&Interface[Index].Set, &GuidString);
136 
137         DPRINT("Driver Interface %S Id %u\n", GuidString.Buffer, Interface[Index].Id);
138         DPRINT("Connect Interface %S Id %u\n", GuidString2.Buffer, ConnectDetails->Interface.Id);
139 
140         RtlFreeUnicodeString(&GuidString);
141 
142         if (IsEqualGUIDAligned(&Interface[Index].Set, &ConnectDetails->Interface.Set) &&
143                                Interface[Index].Id == ConnectDetails->Interface.Id)
144         {
145             /* found a matching interface */
146             Found = TRUE;
147             break;
148         }
149         /* iterate to next interface */
150         Index++;
151     }while(Index < Count);
152     RtlFreeUnicodeString(&GuidString2);
153 
154     if (!Found)
155     {
156         /* pin doesnt support this interface */
157         FreeItem(ConnectDetails);
158         return STATUS_NO_MATCH;
159     }
160 
161     /* does the pin have medium details filled in */
162     if (Descriptor->MediumsCount && Descriptor->Mediums)
163     {
164         /* use provided pin interface count */
165         Count = Descriptor->MediumsCount;
166         Medium = (PKSPIN_MEDIUM)Descriptor->Mediums;
167     }
168     else
169     {
170         /* use standard pin interface */
171         Count = 1;
172         Medium = &StandardPinMedium;
173     }
174 
175     /* now check the interface */
176     Found = FALSE;
177     Index = 0;
178     RtlStringFromGUID(&ConnectDetails->Medium.Set, &GuidString2);
179     do
180     {
181         UNICODE_STRING GuidString;
182         RtlStringFromGUID(&Medium[Index].Set, &GuidString);
183 
184         DPRINT("Driver Medium %S Id %u\n", GuidString.Buffer, Medium[Index].Id);
185         DPRINT("Connect Medium %S Id %u\n", GuidString2.Buffer, ConnectDetails->Medium.Id);
186 
187         RtlFreeUnicodeString(&GuidString);
188 
189         if (IsEqualGUIDAligned(&Medium[Index].Set, &ConnectDetails->Medium.Set) &&
190                                Medium[Index].Id == ConnectDetails->Medium.Id)
191         {
192             /* found a matching interface */
193             Found = TRUE;
194             break;
195         }
196 
197         /* iterate to next medium */
198         Index++;
199     }while(Index < Count);
200     RtlFreeUnicodeString(&GuidString2);
201 
202     if (!Found)
203     {
204         /* pin doesnt support this medium */
205         FreeItem(ConnectDetails);
206         return STATUS_NO_MATCH;
207     }
208 
209     /// FIXME
210     /// implement format checking
211 
212     *Connect = ConnectDetails;
213     return STATUS_SUCCESS;
214 }
215 
216 /*
217     @implemented
218 */
219 KSDDKAPI
220 NTSTATUS
221 NTAPI
222 KsValidateConnectRequest(
223     IN  PIRP Irp,
224     IN  ULONG DescriptorsCount,
225     IN  KSPIN_DESCRIPTOR* Descriptor,
226     OUT PKSPIN_CONNECT* Connect)
227 {
228     return KspValidateConnectRequest(Irp, DescriptorsCount, Descriptor, sizeof(KSPIN_DESCRIPTOR), Connect);
229 }
230 
231 NTSTATUS
232 KspReadMediaCategory(
233     IN LPGUID Category,
234     PKEY_VALUE_PARTIAL_INFORMATION *OutInformation)
235 {
236     UNICODE_STRING MediaPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
237     UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Name");
238     UNICODE_STRING GuidString, Path;
239     NTSTATUS Status;
240     OBJECT_ATTRIBUTES ObjectAttributes;
241     HANDLE hKey;
242     ULONG Size;
243     PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
244 
245     /* convert the guid to string */
246     Status = RtlStringFromGUID(Category, &GuidString);
247     if (!NT_SUCCESS(Status))
248         return Status;
249 
250     /* allocate buffer for the registry key */
251     Path.Length = 0;
252     Path.MaximumLength = MediaPath.MaximumLength + GuidString.MaximumLength;
253     Path.Buffer = AllocateItem(NonPagedPool, Path.MaximumLength);
254     if (!Path.Buffer)
255     {
256         /* not enough memory */
257         RtlFreeUnicodeString(&GuidString);
258         return STATUS_INSUFFICIENT_RESOURCES;
259     }
260 
261     RtlAppendUnicodeStringToString(&Path, &MediaPath);
262     RtlAppendUnicodeStringToString(&Path, &GuidString);
263 
264     /* free guid string */
265     RtlFreeUnicodeString(&GuidString);
266 
267     /* initialize object attributes */
268     InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
269 
270     /* open the key */
271     Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
272 
273     DPRINT("ZwOpenKey() status 0x%08lx %wZ\n", Status, &Path);
274 
275     /* free path buffer */
276     FreeItem(Path.Buffer);
277 
278     /* check for success */
279     if (!NT_SUCCESS(Status))
280     {
281         DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
282         return Status;
283     }
284 
285     /* query the name size */
286     Status = ZwQueryValueKey(hKey, &Name, KeyValuePartialInformation, NULL, 0, &Size);
287     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
288     {
289         /* failed to query for name key */
290         ZwClose(hKey);
291         return Status;
292     }
293 
294     /* allocate buffer to read key info */
295     KeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION) AllocateItem(NonPagedPool, Size);
296     if (!KeyInfo)
297     {
298         /* not enough memory */
299         ZwClose(hKey);
300         return STATUS_INSUFFICIENT_RESOURCES;
301     }
302 
303     /* now read the info */
304     Status = ZwQueryValueKey(hKey, &Name, KeyValuePartialInformation, (PVOID)KeyInfo, Size, &Size);
305 
306     /* close the key */
307     ZwClose(hKey);
308 
309     if (!NT_SUCCESS(Status))
310     {
311         /* failed to read key */
312         FreeItem(KeyInfo);
313         return Status;
314     }
315 
316     /* store key information */
317     *OutInformation = KeyInfo;
318     return Status;
319 }
320 
321 KSDDKAPI
322 NTSTATUS
323 NTAPI
324 KspPinPropertyHandler(
325     IN  PIRP Irp,
326     IN  PKSPROPERTY Property,
327     IN  OUT PVOID Data,
328     IN  ULONG DescriptorsCount,
329     IN  const KSPIN_DESCRIPTOR* Descriptors,
330     IN  ULONG DescriptorSize)
331 {
332     KSP_PIN * Pin;
333     KSMULTIPLE_ITEM * Item;
334     PIO_STACK_LOCATION IoStack;
335     ULONG Size, Index;
336     PVOID Buffer;
337     PKSDATARANGE_AUDIO *WaveFormatOut;
338     PKSDATAFORMAT_WAVEFORMATEX WaveFormatIn;
339     PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
340     const KSPIN_DESCRIPTOR *Descriptor;
341     NTSTATUS Status = STATUS_NOT_SUPPORTED;
342     ULONG Count;
343     const PKSDATARANGE* DataRanges;
344     LPGUID Guid;
345 
346     IoStack = IoGetCurrentIrpStackLocation(Irp);
347     Buffer = Data;
348 
349     //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);
350 
351     /* convert to PKSP_PIN */
352     Pin = (KSP_PIN*)Property;
353 
354     if (Property->Id != KSPROPERTY_PIN_CTYPES)
355     {
356         if (Pin->PinId >= DescriptorsCount)
357         {
358             /* invalid parameter */
359             return STATUS_INVALID_PARAMETER;
360         }
361     }
362     else
363     {
364         (*(PULONG)Buffer) = DescriptorsCount;
365         Irp->IoStatus.Information = sizeof(ULONG);
366         return STATUS_SUCCESS;
367     }
368 
369 
370     if (DescriptorSize == sizeof(KSPIN_DESCRIPTOR))
371     {
372         /* it is simple pin descriptor */
373         Descriptor = &Descriptors[Pin->PinId];
374     }
375     else
376     {
377         /* get offset to pin descriptor */
378         Descriptor = &(((PKSPIN_DESCRIPTOR_EX)((ULONG_PTR)Descriptors + Pin->PinId * DescriptorSize))->PinDescriptor);
379     }
380 
381     switch(Property->Id)
382     {
383         case KSPROPERTY_PIN_DATAFLOW:
384 
385             Size = sizeof(KSPIN_DATAFLOW);
386             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
387             {
388                 Irp->IoStatus.Information = Size;
389                 Status = STATUS_BUFFER_TOO_SMALL;
390                 break;
391             }
392 
393             *((KSPIN_DATAFLOW*)Buffer) = Descriptor->DataFlow;
394             Irp->IoStatus.Information = sizeof(KSPIN_DATAFLOW);
395             Status = STATUS_SUCCESS;
396             break;
397 
398         case KSPROPERTY_PIN_DATARANGES:
399         case KSPROPERTY_PIN_CONSTRAINEDDATARANGES:
400 
401             Size = sizeof(KSMULTIPLE_ITEM);
402             DPRINT("Id %lu PinId %lu DataRangesCount %lu ConstrainedDataRangesCount %lu\n", Property->Id, Pin->PinId, Descriptor->DataRangesCount, Descriptor->ConstrainedDataRangesCount);
403 
404             if (Property->Id == KSPROPERTY_PIN_DATARANGES || Descriptor->ConstrainedDataRangesCount == 0)
405             {
406                 DataRanges = Descriptor->DataRanges;
407                 Count = Descriptor->DataRangesCount;
408             }
409             else
410             {
411                 DataRanges = Descriptor->ConstrainedDataRanges;
412                 Count = Descriptor->ConstrainedDataRangesCount;
413             }
414 
415             for (Index = 0; Index < Count; Index++)
416             {
417                 Size += ((DataRanges[Index]->FormatSize + 0x7) & ~0x7);
418             }
419 
420             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0)
421             {
422                 /* buffer too small */
423                 Irp->IoStatus.Information = Size;
424                 Status = STATUS_BUFFER_OVERFLOW;
425                 break;
426             }
427 
428             Item = (KSMULTIPLE_ITEM*)Buffer;
429 
430             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
431             {
432                 /* store the result size */
433                 Item->Size = Size;
434                 Irp->IoStatus.Information = sizeof(ULONG);
435                 Status = STATUS_SUCCESS;
436                 break;
437             }
438 
439             /* store descriptor size */
440             Item->Size = Size;
441             Item->Count = Count;
442 
443             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
444             {
445                 Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
446                 Status = STATUS_SUCCESS;
447                 break;
448             }
449 
450             /* now copy all dataranges */
451             Data = (PUCHAR)(Item +1);
452 
453             /* alignment assert */
454             ASSERT(((ULONG_PTR)Data & 0x7) == 0);
455 
456             for (Index = 0; Index < Count; Index++)
457             {
458                 UNICODE_STRING GuidString;
459                 /* convert the guid to string */
460                 RtlStringFromGUID(&DataRanges[Index]->MajorFormat, &GuidString);
461                 DPRINT("Index %lu MajorFormat %S\n", Index, GuidString.Buffer);
462                 RtlStringFromGUID(&DataRanges[Index]->SubFormat, &GuidString);
463                 DPRINT("Index %lu SubFormat %S\n", Index, GuidString.Buffer);
464                 RtlStringFromGUID(&DataRanges[Index]->Specifier, &GuidString);
465                 DPRINT("Index %lu Specifier %S\n", Index, GuidString.Buffer);
466                 RtlStringFromGUID(&DataRanges[Index]->Specifier, &GuidString);
467                 DPRINT("Index %lu FormatSize %lu Flags %lu SampleSize %lu Reserved %lu KSDATAFORMAT %lu\n", Index,
468                        DataRanges[Index]->FormatSize, DataRanges[Index]->Flags, DataRanges[Index]->SampleSize, DataRanges[Index]->Reserved, sizeof(KSDATAFORMAT));
469 
470                 RtlMoveMemory(Data, DataRanges[Index], DataRanges[Index]->FormatSize);
471                 Data = ((PUCHAR)Data + DataRanges[Index]->FormatSize);
472                 /* alignment assert */
473                 ASSERT(((ULONG_PTR)Data & 0x7) == 0);
474                 Data = (PVOID)(((ULONG_PTR)Data + 0x7) & ~0x7);
475             }
476 
477             Status = STATUS_SUCCESS;
478             Irp->IoStatus.Information = Size;
479             break;
480         case KSPROPERTY_PIN_INTERFACES:
481 
482             if (Descriptor->Interfaces)
483             {
484                 /* use mediums provided by driver */
485                 return KsHandleSizedListQuery(Irp, Descriptor->InterfacesCount, sizeof(KSPIN_MEDIUM), Descriptor->Interfaces);
486             }
487             else
488             {
489                 /* use standard medium */
490                 return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_INTERFACE), &StandardPinInterface);
491             }
492             break;
493 
494         case KSPROPERTY_PIN_MEDIUMS:
495 
496             if (Descriptor->MediumsCount)
497             {
498                 /* use mediums provided by driver */
499                 return KsHandleSizedListQuery(Irp, Descriptor->MediumsCount, sizeof(KSPIN_MEDIUM), Descriptor->Mediums);
500             }
501             else
502             {
503                 /* use standard medium */
504                 return KsHandleSizedListQuery(Irp, 1, sizeof(KSPIN_MEDIUM), &StandardPinMedium);
505             }
506             break;
507 
508         case KSPROPERTY_PIN_COMMUNICATION:
509 
510             Size = sizeof(KSPIN_COMMUNICATION);
511             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
512             {
513                 Irp->IoStatus.Information = Size;
514                 Status = STATUS_BUFFER_TOO_SMALL;
515                 break;
516             }
517 
518             *((KSPIN_COMMUNICATION*)Buffer) = Descriptor->Communication;
519 
520             Status = STATUS_SUCCESS;
521             Irp->IoStatus.Information = Size;
522             break;
523 
524         case KSPROPERTY_PIN_CATEGORY:
525 
526             if (!Descriptor->Category)
527             {
528                 /* no pin category */
529                 return STATUS_NOT_FOUND;
530             }
531 
532             /* check size */
533             Size = sizeof(GUID);
534             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
535             {
536                 /* buffer too small */
537                 Irp->IoStatus.Information = Size;
538                 Status = STATUS_BUFFER_TOO_SMALL;
539                 break;
540             }
541 
542             /* copy category guid */
543             RtlMoveMemory(Buffer, Descriptor->Category, sizeof(GUID));
544 
545             /* save result */
546             Status = STATUS_SUCCESS;
547             Irp->IoStatus.Information = Size;
548             break;
549 
550         case KSPROPERTY_PIN_NAME:
551 
552             if (Descriptor->Name)
553             {
554                 /* use pin name */
555                 Guid = (LPGUID)Descriptor->Name;
556             }
557             else
558             {
559                 /* use pin category as fallback */
560                 Guid = (LPGUID)Descriptor->Category;
561             }
562 
563             if (!Guid)
564             {
565                 /* no friendly name available */
566                 return STATUS_NOT_FOUND;
567             }
568 
569             /* read friendly name category name */
570             Status = KspReadMediaCategory(Guid, &KeyInfo);
571             if (!NT_SUCCESS(Status))
572             {
573                 /* failed to read category */
574                 Irp->IoStatus.Information = 0;
575                 break;
576             }
577 
578             /* store required length */
579             Irp->IoStatus.Information = KeyInfo->DataLength + sizeof(WCHAR);
580 
581             /* check if buffer is too small */
582             if (KeyInfo->DataLength + sizeof(WCHAR) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
583             {
584                 /* buffer too small */
585                 Status = STATUS_BUFFER_OVERFLOW;
586                 FreeItem(KeyInfo);
587                 break;
588             }
589 
590             /* copy result */
591             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, &KeyInfo->Data, KeyInfo->DataLength);
592 
593             /* null terminate name */
594             ((LPWSTR)Irp->AssociatedIrp.SystemBuffer)[KeyInfo->DataLength / sizeof(WCHAR)] = L'\0';
595 
596             /* free key info */
597             FreeItem(KeyInfo);
598             break;
599         case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
600             Size = sizeof(KSDATAFORMAT);
601             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
602             {
603                 Irp->IoStatus.Information = Size;
604                 Status = STATUS_BUFFER_TOO_SMALL;
605                 break;
606             }
607             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(KSDATAFORMAT_WAVEFORMATEX))
608             {
609                 UNIMPLEMENTED;
610                 Status = STATUS_NOT_IMPLEMENTED;
611                 Irp->IoStatus.Information = 0;
612                 break;
613             }
614 
615             WaveFormatIn = (PKSDATAFORMAT_WAVEFORMATEX)Buffer;
616             if (!Descriptor->DataRanges || !Descriptor->DataRangesCount)
617             {
618                 Status = STATUS_UNSUCCESSFUL;
619                 Irp->IoStatus.Information = 0;
620                 break;
621             }
622             WaveFormatOut = (PKSDATARANGE_AUDIO*)Descriptor->DataRanges;
623             for(Index = 0; Index < Descriptor->DataRangesCount; Index++)
624             {
625                 if (WaveFormatOut[Index]->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
626                 {
627                     UNIMPLEMENTED;
628                     continue;
629                 }
630 
631                 if (WaveFormatOut[Index]->MinimumSampleFrequency > WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
632                     WaveFormatOut[Index]->MaximumSampleFrequency < WaveFormatIn->WaveFormatEx.nSamplesPerSec ||
633                     WaveFormatOut[Index]->MinimumBitsPerSample > WaveFormatIn->WaveFormatEx.wBitsPerSample ||
634                     WaveFormatOut[Index]->MaximumBitsPerSample < WaveFormatIn->WaveFormatEx.wBitsPerSample ||
635                     WaveFormatOut[Index]->MaximumChannels < WaveFormatIn->WaveFormatEx.nChannels)
636                 {
637                     Irp->IoStatus.Status = STATUS_NO_MATCH;
638                     Irp->IoStatus.Information = 0;
639                     return STATUS_NO_MATCH;
640                 }
641                 else
642                 {
643                     Irp->IoStatus.Status = STATUS_SUCCESS;
644                     Irp->IoStatus.Information = 0;
645                     return STATUS_SUCCESS;
646                 }
647             }
648             Status = STATUS_NO_MATCH;
649             Irp->IoStatus.Information = 0;
650             break;
651         default:
652             DPRINT1("Unhandled property request %x\n", Property->Id);
653             Status = STATUS_NOT_IMPLEMENTED;
654             Irp->IoStatus.Information = 0;
655     }
656 
657     return Status;
658 }
659 
660 /*
661     @implemented
662 */
663 KSDDKAPI
664 NTSTATUS
665 NTAPI
666 KsPinPropertyHandler(
667     IN  PIRP Irp,
668     IN  PKSPROPERTY Property,
669     IN  OUT PVOID Data,
670     IN  ULONG DescriptorsCount,
671     IN  const KSPIN_DESCRIPTOR* Descriptor)
672 {
673     return KspPinPropertyHandler(Irp, Property, Data, DescriptorsCount, Descriptor, sizeof(KSPIN_DESCRIPTOR));
674 }
675 
676 /*
677     @unimplemented
678 */
679 KSDDKAPI NTSTATUS NTAPI
680 KsPinDataIntersectionEx(
681     IN  PIRP Irp,
682     IN  PKSP_PIN Pin,
683     OUT PVOID Data,
684     IN  ULONG DescriptorsCount,
685     IN  const KSPIN_DESCRIPTOR* Descriptor,
686     IN  ULONG DescriptorSize,
687     IN  PFNKSINTERSECTHANDLEREX IntersectHandler OPTIONAL,
688     IN  PVOID HandlerContext OPTIONAL)
689 {
690     UNIMPLEMENTED;
691     return STATUS_UNSUCCESSFUL;
692 }
693 
694 /*
695     @implemented
696 */
697 KSDDKAPI
698 NTSTATUS
699 NTAPI
700 KsPinDataIntersection(
701     IN  PIRP Irp,
702     IN  PKSP_PIN Pin,
703     OUT PVOID Data,
704     IN  ULONG DescriptorsCount,
705     IN  const KSPIN_DESCRIPTOR* Descriptor,
706     IN  PFNKSINTERSECTHANDLER IntersectHandler)
707 {
708     KSMULTIPLE_ITEM * Item;
709     KSDATARANGE * DataRange;
710     PIO_STACK_LOCATION IoStack;
711     ULONG Size;
712     ULONG Index;
713     NTSTATUS Status;
714 
715     /* get current irp stack location */
716     IoStack = IoGetCurrentIrpStackLocation(Irp);
717 
718     /* calculate minimum data size */
719     Size = sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATARANGE);
720     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < Size)
721     {
722         /* buffer too small */
723         Irp->IoStatus.Information = Size;
724         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
725         return STATUS_BUFFER_TOO_SMALL;
726     }
727     /* is pin id out of bounds */
728     if (Pin->PinId >= DescriptorsCount)
729     {
730         /* it is */
731         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
732         Irp->IoStatus.Information = 0;
733         return STATUS_INVALID_PARAMETER;
734     }
735 
736     /* get start item */
737     Item = (KSMULTIPLE_ITEM*)(Pin + 1);
738     /* get first data range */
739     DataRange = (KSDATARANGE*)(Item + 1);
740     /* iterate through all data ranges */
741     for(Index = 0; Index < Item->Count; Index++, DataRange++)
742     {
743         /* call intersect handler */
744         Status = IntersectHandler(Irp, Pin, DataRange, Data);
745         if (NT_SUCCESS(Status))
746         {
747             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < DataRange->FormatSize)
748             {
749                 /* buffer is too small */
750                 Irp->IoStatus.Information = DataRange->FormatSize;
751                 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
752                 return STATUS_BUFFER_TOO_SMALL;
753             }
754             RtlMoveMemory(Irp->UserBuffer, DataRange, sizeof(KSDATARANGE));
755             Irp->IoStatus.Information = sizeof(KSDATARANGE);
756             Irp->IoStatus.Status = STATUS_SUCCESS;
757             return STATUS_SUCCESS;
758         }
759 
760     }
761 
762     Irp->IoStatus.Information = 0;
763     Irp->IoStatus.Status = STATUS_NO_MATCH;
764     return STATUS_NO_MATCH;
765 }
766 
767 /*
768     @implemented
769 */
770 
771 KSDDKAPI
772 NTSTATUS
773 NTAPI
774 KsHandleSizedListQuery(
775     IN  PIRP Irp,
776     IN  ULONG DataItemsCount,
777     IN  ULONG DataItemSize,
778     IN  const VOID* DataItems)
779 {
780     ULONG Size;
781     PIO_STACK_LOCATION IoStack;
782     PKSMULTIPLE_ITEM Item;
783 
784     /* get current irp stack location */
785     IoStack = IoGetCurrentIrpStackLocation(Irp);
786 
787     /* calculate size */
788     Size = DataItemSize * DataItemsCount + sizeof(KSMULTIPLE_ITEM);
789 
790     /* get multiple item */
791     Item = (PKSMULTIPLE_ITEM)Irp->AssociatedIrp.SystemBuffer;
792 
793     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == 0)
794     {
795         /* buffer too small */
796         Irp->IoStatus.Information = Size;
797 
798         return STATUS_BUFFER_OVERFLOW;
799     }
800 
801     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(ULONG))
802     {
803         /* store just the size */
804         Item->Size = Size;
805         Irp->IoStatus.Information = sizeof(ULONG);
806 
807         return STATUS_SUCCESS;
808     }
809 
810 
811     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSMULTIPLE_ITEM))
812     {
813         /* buffer too small */
814         return STATUS_BUFFER_TOO_SMALL;
815     }
816 
817     Item->Count = DataItemsCount;
818     Item->Size = DataItemSize;
819 
820     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KSMULTIPLE_ITEM))
821     {
822         /* buffer can only hold the length descriptor */
823         Irp->IoStatus.Information = sizeof(KSMULTIPLE_ITEM);
824         return STATUS_SUCCESS;
825     }
826 
827     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= Size)
828     {
829         /* copy items */
830         RtlMoveMemory((PVOID)(Item + 1), DataItems, DataItemSize * DataItemsCount);
831         /* store result */
832         Irp->IoStatus.Information = Size;
833         /* done */
834         return STATUS_SUCCESS;
835     }
836     else
837     {
838         /* buffer too small */
839         return STATUS_BUFFER_TOO_SMALL;
840     }
841 }
842