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