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