1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/api.cpp
5  * PURPOSE:         Port api functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "private.hpp"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 NTSTATUS
15 NTAPI
16 KsoDispatchCreateWithGenericFactory(
17     LONG Unknown,
18     PIRP Irp)
19 {
20     UNIMPLEMENTED;
21     return STATUS_NOT_IMPLEMENTED;
22 }
23 
24 IIrpTarget *
25 NTAPI
26 KsoGetIrpTargetFromFileObject(
27     PFILE_OBJECT FileObject)
28 {
29     PC_ASSERT(FileObject);
30 
31     // IrpTarget is stored in FsContext
32     return (IIrpTarget*)FileObject->FsContext;
33 }
34 
35 IIrpTarget *
36 NTAPI
37 KsoGetIrpTargetFromIrp(
38     PIRP Irp)
39 {
40     PIO_STACK_LOCATION IoStack;
41 
42     // get current irp stack location
43     IoStack = IoGetCurrentIrpStackLocation(Irp);
44 
45     // IIrpTarget is stored in Context member
46     return (IIrpTarget*)IoStack->FileObject->FsContext;
47 }
48 
49 NTSTATUS
50 NTAPI
51 PcHandleEnableEventWithTable(
52     IN PIRP Irp,
53     IN PSUBDEVICE_DESCRIPTOR Descriptor)
54 {
55     // store descriptor
56     KSEVENT_ITEM_IRP_STORAGE(Irp) = (PKSEVENT_ITEM)Descriptor;
57 
58     // FIXME seh probing
59     return KsEnableEvent(Irp, Descriptor->EventSetCount, Descriptor->EventSet, NULL, KSEVENTS_NONE, NULL);
60 }
61 
62 NTSTATUS
63 NTAPI
64 PcHandleDisableEventWithTable(
65     IN PIRP Irp,
66     IN PSUBDEVICE_DESCRIPTOR Descriptor)
67 {
68     // store descriptor
69     KSEVENT_ITEM_IRP_STORAGE(Irp) = (PKSEVENT_ITEM)Descriptor;
70 
71     // FIXME seh probing
72 
73     return KsDisableEvent(Irp, Descriptor->EventList, KSEVENTS_SPINLOCK, (PVOID)Descriptor->EventListLock);
74 }
75 
76 NTSTATUS
77 NTAPI
78 PcHandlePropertyWithTable(
79     IN PIRP Irp,
80     IN ULONG PropertySetCount,
81     IN PKSPROPERTY_SET PropertySet,
82     IN PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor)
83 {
84     PIO_STACK_LOCATION IoStack;
85 
86     // get current irp stack location
87     IoStack = IoGetCurrentIrpStackLocation(Irp);
88 
89     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
90     {
91         // certainly an invalid request
92         return STATUS_INVALID_PARAMETER;
93     }
94 
95     // store device descriptor
96     KSPROPERTY_ITEM_IRP_STORAGE(Irp) = (PKSPROPERTY_ITEM)SubDeviceDescriptor;
97 
98     // then try KsPropertyHandler
99     return KsPropertyHandler(Irp, PropertySetCount, PropertySet);
100 }
101 
102 VOID
103 NTAPI
104 PcAcquireFormatResources(
105     LONG Unknown,
106     LONG Unknown2,
107     LONG Unknown3,
108     LONG Unknown4)
109 {
110     UNIMPLEMENTED;
111 }
112 
113 NTSTATUS
114 PcAddToEventTable(
115     PVOID Ptr,
116     LONG Unknown2,
117     ULONG Length,
118     LONG Unknown3,
119     LONG Unknown4,
120     LONG Unknown5,
121     LONG Unknown6,
122     LONG Unknown7)
123 {
124     UNIMPLEMENTED;
125     return STATUS_NOT_IMPLEMENTED;
126 }
127 
128 NTSTATUS
129 NTAPI
130 PropertyItemDispatch(
131     IN PIRP Irp,
132     IN PKSIDENTIFIER  Request,
133     IN OUT PVOID  Data)
134 {
135     PPCPROPERTY_REQUEST PropertyRequest;
136     PSUBDEVICE_DESCRIPTOR Descriptor;
137     PKSPROPERTY Property;
138     PPCNODE_DESCRIPTOR NodeDescriptor;
139     PKSNODEPROPERTY NodeProperty;
140     PKSPROPERTY_SET PropertySet;
141     PPCPROPERTY_ITEM PropertyItem;
142     PPCAUTOMATION_TABLE NodeAutomation;
143     PIO_STACK_LOCATION IoStack;
144     ULONG InstanceSize, ValueSize, Index;
145     PVOID Instance;
146     NTSTATUS Status;
147 
148     // allocate a property request
149     PropertyRequest = (PPCPROPERTY_REQUEST)AllocateItem(NonPagedPool, sizeof(PCPROPERTY_REQUEST), TAG_PORTCLASS);
150     if (!PropertyRequest)
151         return STATUS_INSUFFICIENT_RESOURCES;
152 
153     // grab device descriptor
154     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
155 
156     // get current irp stack
157     IoStack = IoGetCurrentIrpStackLocation(Irp);
158 
159     // get input property request
160     Property = (PKSPROPERTY)Request;
161 
162     // get property set
163     PropertySet = (PKSPROPERTY_SET)KSPROPERTY_SET_IRP_STORAGE(Irp);
164 
165     // sanity check
166     PC_ASSERT(Descriptor);
167     PC_ASSERT(Descriptor->UnknownMiniport);
168 
169     // get instance / value size
170     InstanceSize = IoStack->Parameters.DeviceIoControl.InputBufferLength;
171     Instance = Request;
172     ValueSize = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
173 
174      // initialize property request
175      PropertyRequest->MajorTarget = Descriptor->UnknownMiniport;
176      PropertyRequest->MinorTarget = Descriptor->UnknownStream;
177      PropertyRequest->Irp = Irp;
178      PropertyRequest->Verb = Property->Flags;
179 
180     // check if this is filter / pin property request
181     if (!(Property->Flags & KSPROPERTY_TYPE_TOPOLOGY))
182     {
183         // adjust input buffer size
184         InstanceSize -= sizeof(KSPROPERTY);
185         Instance = (PVOID)((ULONG_PTR)Instance + sizeof(KSPROPERTY));
186 
187         // filter / pin property request dont use node field
188         PropertyRequest->Node = MAXULONG;
189     }
190     else if (InstanceSize >= sizeof(KSNODEPROPERTY))
191     {
192         // request is for a node
193         InstanceSize -= sizeof(KSNODEPROPERTY);
194         Instance = (PVOID)((ULONG_PTR)Instance + sizeof(KSNODEPROPERTY));
195 
196         // cast node property request
197         NodeProperty = (PKSNODEPROPERTY)Request;
198 
199         // store node id
200         PropertyRequest->Node = NodeProperty->NodeId;
201     }
202     else
203     {
204         // invalid buffer size
205         FreeItem(PropertyRequest, TAG_PORTCLASS);
206         return STATUS_INVALID_BUFFER_SIZE;
207     }
208 
209     // store instance size
210     PropertyRequest->InstanceSize = InstanceSize;
211     PropertyRequest->Instance = (InstanceSize != 0 ? Instance : NULL);
212 
213     // store value size
214     PropertyRequest->ValueSize = ValueSize;
215     PropertyRequest->Value = Data;
216 
217     // now scan the property set for the attached property set item stored in Relations member
218     if (PropertySet)
219     {
220         // sanity check
221         PC_ASSERT(IsEqualGUIDAligned(Property->Set, *PropertySet->Set));
222 
223         for(Index = 0; Index < PropertySet->PropertiesCount; Index++)
224         {
225             // check if they got the same property id
226             if (PropertySet->PropertyItem[Index].PropertyId == Property->Id)
227             {
228                 // found item
229                 PropertyRequest->PropertyItem = (const PCPROPERTY_ITEM*)PropertySet->PropertyItem[Index].Relations;
230 
231                 // done
232                 break;
233             }
234         }
235     }
236 
237     // check if there has been a property set item attached
238     if (!PropertyRequest->PropertyItem)
239     {
240         // is topology node id valid
241         if (PropertyRequest->Node < Descriptor->DeviceDescriptor->NodeCount)
242         {
243             // get node descriptor
244             NodeDescriptor = (PPCNODE_DESCRIPTOR) ((ULONG_PTR)Descriptor->DeviceDescriptor->Nodes + PropertyRequest->Node * Descriptor->DeviceDescriptor->NodeSize);
245 
246             // get node automation table
247             NodeAutomation = (PPCAUTOMATION_TABLE)NodeDescriptor->AutomationTable;
248 
249             // has it got a automation table
250             if (NodeAutomation)
251             {
252                 // now scan the properties and check if it supports this request
253                 PropertyItem = (PPCPROPERTY_ITEM)NodeAutomation->Properties;
254                 for(Index = 0; Index < NodeAutomation->PropertyCount; Index++)
255                 {
256                     // are they same property
257                     if (IsEqualGUIDAligned(*PropertyItem->Set, Property->Set))
258                     {
259                         if (PropertyItem->Id == Property->Id)
260                         {
261                             // found match
262                             PropertyRequest->PropertyItem = PropertyItem;
263                             DPRINT("Using property item %p\n", PropertyItem);
264                             // done
265                             break;
266                         }
267                     }
268 
269                     // move to next property item
270                     PropertyItem = (PPCPROPERTY_ITEM)((ULONG_PTR)PropertyItem + NodeAutomation->PropertyItemSize);
271                 }
272             }
273         }
274     }
275 
276     if (PropertyRequest->PropertyItem && PropertyRequest->PropertyItem->Handler)
277     {
278         // now call the handler
279         UNICODE_STRING GuidBuffer;
280         RtlStringFromGUID(Property->Set, &GuidBuffer);
281         DPRINT("Calling Node %lu MajorTarget %p MinorTarget %p PropertySet %S PropertyId %lu PropertyFlags %lx InstanceSize %lu ValueSize %lu Handler %p PropertyRequest %p PropertyItemFlags %lx PropertyItemId %lu\n",
282                 PropertyRequest->Node, PropertyRequest->MajorTarget, PropertyRequest->MinorTarget, GuidBuffer.Buffer, Property->Id, Property->Flags, PropertyRequest->InstanceSize, PropertyRequest->ValueSize,
283                 PropertyRequest->PropertyItem->Handler, PropertyRequest, PropertyRequest->PropertyItem->Flags, PropertyRequest->PropertyItem->Id);
284         RtlFreeUnicodeString(&GuidBuffer);
285         Status = PropertyRequest->PropertyItem->Handler(PropertyRequest);
286         DPRINT("Status %lx ValueSize %lu Information %lu\n", Status, PropertyRequest->ValueSize, Irp->IoStatus.Information);
287         Irp->IoStatus.Information = PropertyRequest->ValueSize;
288 
289         if (Status != STATUS_PENDING)
290         {
291             // free property request
292             FreeItem(PropertyRequest, TAG_PORTCLASS);
293         }
294     }
295     else
296     {
297         FreeItem(PropertyRequest, TAG_PORTCLASS);
298         Status = STATUS_NOT_FOUND;
299     }
300 
301     /* done */
302     return Status;
303 }
304 
305 NTSTATUS
306 PcAddToPropertyTable(
307     IN PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor,
308     IN PPCPROPERTY_ITEM PropertyItem,
309     IN ULONG bNode)
310 {
311     ULONG bFound = FALSE;
312     ULONG Index, PropertySetIndex, PropertySetItemIndex;
313     PKSPROPERTY_SET NewPropertySet;
314     PKSPROPERTY_ITEM FilterPropertyItem, NewFilterPropertyItem;
315     LPGUID Guid;
316     //UNICODE_STRING GuidBuffer;
317 
318 ASSERT(PropertyItem->Set);
319 	//	RtlStringFromGUID(*PropertyItem->Set, &GuidBuffer);
320    // DPRINT1("PcAddToPropertyTable Adding Item Set %S Id %lu Flags %lx\n", GuidBuffer.Buffer, PropertyItem->Id, PropertyItem->Flags);
321 
322     //DPRINT1("FilterPropertySetCount %lu\n", SubDeviceDescriptor->FilterPropertySetCount);
323     // first step check if the property set is present already
324     for(Index = 0; Index < SubDeviceDescriptor->FilterPropertySetCount; Index++)
325     {
326 
327 		//RtlStringFromGUID(*SubDeviceDescriptor->FilterPropertySet[Index].Set, &GuidBuffer);
328         //DPRINT1("FilterProperty Set %S PropertyCount %lu\n", GuidBuffer.Buffer, SubDeviceDescriptor->FilterPropertySet[Index].PropertiesCount);
329         if (IsEqualGUIDAligned(*SubDeviceDescriptor->FilterPropertySet[Index].Set, *PropertyItem->Set))
330         {
331             // property set is already present
332             bFound = TRUE;
333             PropertySetIndex = Index;
334 
335             // break out
336             break;
337         }
338     }
339 
340     // is the property set present
341     if (!bFound)
342     {
343         // need to allocate a property set
344         NewPropertySet = (PKSPROPERTY_SET)AllocateItem(NonPagedPool, (SubDeviceDescriptor->FilterPropertySetCount + 1) * sizeof(KSPROPERTY_SET), TAG_PORTCLASS);
345         if (!NewPropertySet)
346         {
347             // out of memory
348             return STATUS_INSUFFICIENT_RESOURCES;
349         }
350 
351         // need to allocate property set guid
352         Guid = (LPGUID)AllocateItem(NonPagedPool, sizeof(GUID), TAG_PORTCLASS);
353         if (!Guid)
354         {
355             // out of memory
356             FreeItem(NewPropertySet, TAG_PORTCLASS);
357             return STATUS_INSUFFICIENT_RESOURCES;
358         }
359 
360         // are any existing property sets
361         if (SubDeviceDescriptor->FilterPropertySetCount)
362         {
363             // copy property sets
364             RtlMoveMemory(NewPropertySet, SubDeviceDescriptor->FilterPropertySet, SubDeviceDescriptor->FilterPropertySetCount * sizeof(KSPROPERTY_SET));
365 
366             // release memory
367             FreeItem(SubDeviceDescriptor->FilterPropertySet, TAG_PORTCLASS);
368         }
369 
370         // store new property set descriptors
371         SubDeviceDescriptor->FilterPropertySet = NewPropertySet;
372 
373         // store index
374         PropertySetIndex = SubDeviceDescriptor->FilterPropertySetCount;
375 
376         // increment property set count
377         SubDeviceDescriptor->FilterPropertySetCount++;
378 
379         // copy property guid
380         RtlMoveMemory(Guid, PropertyItem->Set, sizeof(GUID));
381 
382         // initialize property set
383         SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].Set = Guid;
384         SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount = 0;
385     }
386 
387     // as the property set has been identified, now search for duplicate property set item entries
388     FilterPropertyItem = (PKSPROPERTY_ITEM)SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem;
389     bFound = FALSE;
390 
391     for(Index = 0; Index < SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount; Index++)
392     {
393         // now search for an equal property set item
394         if (FilterPropertyItem->PropertyId == PropertyItem->Id)
395         {
396             // found existing property set item
397             bFound = TRUE;
398             PropertySetItemIndex = Index;
399             break;
400         }
401 
402         // move to next entry
403         FilterPropertyItem++;
404     }
405 
406     if (!bFound)
407     {
408         // need to allocate memory for new property set item
409         NewFilterPropertyItem = (PKSPROPERTY_ITEM)AllocateItem(NonPagedPool, (SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount + 1) * sizeof(KSPROPERTY_ITEM), TAG_PORTCLASS);
410         if (!NewFilterPropertyItem)
411         {
412             // out of memory
413             return STATUS_INSUFFICIENT_RESOURCES;
414         }
415 
416         // are any existing property set items
417         if (SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount)
418         {
419             // copy property item sets
420             RtlMoveMemory(NewFilterPropertyItem,
421                           (PVOID)SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem,
422                           SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount * sizeof(KSPROPERTY_ITEM));
423 
424             // release old descriptors
425             FreeItem((PVOID)SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem, TAG_PORTCLASS);
426         }
427 
428         // store new descriptor
429         SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem = NewFilterPropertyItem;
430 
431         // store index
432         PropertySetItemIndex = SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount;
433 
434         // increment property item set count
435         SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertiesCount++;
436 
437         // now initialize property item
438         FilterPropertyItem = (PKSPROPERTY_ITEM)&SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem[PropertySetItemIndex];
439         FilterPropertyItem->PropertyId = PropertyItem->Id;
440         FilterPropertyItem->MinProperty = sizeof(KSPROPERTY);
441         FilterPropertyItem->MinData = 0;
442 
443         // are any set operations supported
444         if (PropertyItem->Flags & PCPROPERTY_ITEM_FLAG_SET)
445         {
446             // setup handler
447             FilterPropertyItem->SetPropertyHandler = PropertyItemDispatch;
448         }
449 
450         // are set operation supported
451         if (PropertyItem->Flags & PCPROPERTY_ITEM_FLAG_GET)
452         {
453             // setup handler
454             FilterPropertyItem->GetPropertyHandler = PropertyItemDispatch;
455         }
456 
457         // are get operations supported
458         if (PropertyItem->Flags & PCPROPERTY_ITEM_FLAG_GET)
459         {
460             // setup handler
461             FilterPropertyItem->GetPropertyHandler = PropertyItemDispatch;
462         }
463 
464         // are basic support operations supported
465         if (PropertyItem->Flags & PCPROPERTY_ITEM_FLAG_BASICSUPPORT)
466         {
467             // setup handler
468             FilterPropertyItem->SupportHandler = PropertyItemDispatch;
469         }
470 
471         if (!bNode)
472         {
473             // store property item in relations
474             // only store property item of filter properties / pin properties
475             // because filter & pin properties do not require a specific context
476             // on the other hand node properties are specifically bound to a node
477 
478             FilterPropertyItem->Relations = (const KSPROPERTY*)PropertyItem;
479         }
480     }
481     else
482     {
483         // property set item handler already present
484 
485         if (bNode)
486         {
487             // filter & pin properties should not be exposed on a node
488             ASSERT(SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem[PropertySetItemIndex].Relations == NULL);
489         }
490         else
491         {
492             // node properties should not be exposed on a filter & pin
493             ASSERT(SubDeviceDescriptor->FilterPropertySet[PropertySetIndex].PropertyItem[PropertySetItemIndex].Relations != NULL);
494         }
495     }
496 
497     // done
498     return STATUS_SUCCESS;
499 }
500 
501 NTSTATUS
502 PcCaptureFormat(
503     LONG Unknown,
504     LONG Unknown2,
505     LONG Unknown3,
506     LONG Unknown4)
507 {
508     UNIMPLEMENTED;
509     return STATUS_NOT_IMPLEMENTED;
510 }
511 
512 VOID
513 DumpAutomationTable(
514     IN PPCAUTOMATION_TABLE AutomationTable,
515     IN LPCWSTR DebugPrefix,
516     IN LPCWSTR DebugIndentation)
517 {
518     PPCPROPERTY_ITEM PropertyItem;
519     PPCEVENT_ITEM EventItem;
520     PPCMETHOD_ITEM MethodItem;
521     ULONG Index;
522     UNICODE_STRING GuidString;
523 
524     if (!AutomationTable)
525     {
526         // no table
527         return;
528     }
529 
530     DPRINT("=====================================================================\n");
531     DPRINT("%S%S AutomationTable %p\n", DebugIndentation, DebugPrefix, AutomationTable);
532     DPRINT("%S%S PropertyCount %lu\n", DebugIndentation, DebugPrefix, AutomationTable->PropertyCount);
533     DPRINT("%S%S EventCount %lu\n", DebugIndentation, DebugPrefix, AutomationTable->EventCount);
534     DPRINT("%S%S MethodCount %lu\n", DebugIndentation, DebugPrefix, AutomationTable->MethodCount);
535 
536     // print properties
537     if (AutomationTable->PropertyCount)
538     {
539         if (AutomationTable->PropertyItemSize >= sizeof(PCPROPERTY_ITEM))
540         {
541             // get property item
542             PropertyItem = (PPCPROPERTY_ITEM)AutomationTable->Properties;
543 
544             // sanity check
545             ASSERT(PropertyItem);
546 
547             // display all properties associated
548             for(Index = 0; Index < AutomationTable->PropertyCount; Index++)
549             {
550                 // convert to printable string
551                 RtlStringFromGUID(*PropertyItem->Set, &GuidString);
552                 DPRINT("%SPropertyItemIndex %lu %p GUID %S Id %u Flags %x\n", DebugIndentation, Index, PropertyItem, GuidString.Buffer, PropertyItem->Id, PropertyItem->Flags);
553                 RtlFreeUnicodeString(&GuidString);
554                 // move to next item
555                 PropertyItem = (PPCPROPERTY_ITEM)((ULONG_PTR)PropertyItem + AutomationTable->PropertyItemSize);
556             }
557 
558         }
559         else
560         {
561             DPRINT1("DRIVER BUG: property item must be at least %lu but got %lu\n", sizeof(PCPROPERTY_ITEM), AutomationTable->PropertyItemSize);
562         }
563     }
564 
565     // print events
566     if (AutomationTable->EventCount)
567     {
568         if (AutomationTable->EventItemSize >= sizeof(PCEVENT_ITEM))
569         {
570             // get first event item
571             EventItem = (PPCEVENT_ITEM)AutomationTable->Events;
572 
573             // sanity check
574             ASSERT(EventItem);
575 
576             for(Index = 0; Index < AutomationTable->EventCount; Index++)
577             {
578                 // convert to printable string
579                 RtlStringFromGUID(*EventItem->Set, &GuidString);
580                 DPRINT("%SEventItemIndex %lu %p GUID %S Id %u Flags %x\n", DebugIndentation, Index, EventItem, GuidString.Buffer, EventItem->Id, EventItem->Flags);
581                 RtlFreeUnicodeString(&GuidString);
582 
583                 // move to next item
584                 EventItem = (PPCEVENT_ITEM)((ULONG_PTR)EventItem + AutomationTable->EventItemSize);
585             }
586         }
587         else
588         {
589             DPRINT1("DRIVER BUG: event item must be at least %lu but got %lu\n", sizeof(PCEVENT_ITEM), AutomationTable->EventItemSize);
590         }
591     }
592 
593     // print methods
594     if (AutomationTable->MethodCount)
595     {
596        if (AutomationTable->MethodItemSize >= sizeof(PCMETHOD_ITEM))
597        {
598             // get first event item
599             MethodItem = (PPCMETHOD_ITEM)AutomationTable->Methods;
600 
601             // sanity check
602             ASSERT(MethodItem);
603 
604             for(Index = 0; Index < AutomationTable->MethodCount; Index++)
605             {
606                 // convert to printable string
607                 RtlStringFromGUID(*MethodItem->Set, &GuidString);
608                 DPRINT("%SMethodItemIndex %lu %p GUID %S Id %u Flags %x\n", DebugIndentation, Index, MethodItem, GuidString.Buffer, MethodItem->Id, MethodItem->Flags);
609                 RtlFreeUnicodeString(&GuidString);
610 
611                 // move to next item
612                 MethodItem = (PPCMETHOD_ITEM)((ULONG_PTR)MethodItem + AutomationTable->MethodItemSize);
613             }
614 
615        }
616        else
617        {
618            DPRINT1("DRIVER BUG: method item must be at least %lu but got %lu\n", sizeof(PCEVENT_ITEM), AutomationTable->MethodItemSize);
619        }
620     }
621     DPRINT("=====================================================================\n");
622 }
623 
624 VOID
625 DumpFilterDescriptor(
626     IN PPCFILTER_DESCRIPTOR FilterDescription)
627 {
628     ULONG Index;
629     WCHAR Buffer[30];
630     PPCPIN_DESCRIPTOR PinDescriptor;
631     PPCNODE_DESCRIPTOR NodeDescriptor;
632 
633     DPRINT("======================\n");
634     DPRINT("Descriptor Automation Table %p\n",FilterDescription->AutomationTable);
635     DPRINT("PinCount %lu PinSize %lu StandardSize %lu\n", FilterDescription->PinCount, FilterDescription->PinSize, sizeof(PCPIN_DESCRIPTOR));
636     DPRINT("NodeCount %lu NodeSize %lu StandardSize %lu\n", FilterDescription->NodeCount, FilterDescription->NodeSize, sizeof(PCNODE_DESCRIPTOR));
637 
638     // dump filter description table
639     DumpAutomationTable((PPCAUTOMATION_TABLE)FilterDescription->AutomationTable, L"Filter", L"");
640 
641     if (FilterDescription->PinCount)
642     {
643         if (FilterDescription->PinSize >= sizeof(PCPIN_DESCRIPTOR))
644         {
645             // get first pin
646             PinDescriptor = (PPCPIN_DESCRIPTOR)FilterDescription->Pins;
647 
648             // sanity check
649             ASSERT(PinDescriptor);
650 
651             for(Index = 0; Index < FilterDescription->PinCount; Index++)
652             {
653                // print prefix
654                swprintf(Buffer, L"PinIndex %lu", Index);
655 
656                // dump automation table
657                DumpAutomationTable((PPCAUTOMATION_TABLE)PinDescriptor->AutomationTable, Buffer, L"    ");
658 
659                // move to next pin descriptor
660                PinDescriptor = (PPCPIN_DESCRIPTOR)((ULONG_PTR)PinDescriptor + FilterDescription->PinSize);
661             }
662         }
663         else
664         {
665             DPRINT1("DRIVER BUG: pin size smaller than minimum size\n");
666         }
667     }
668 
669     if (FilterDescription->Nodes)
670     {
671         if (FilterDescription->NodeSize >= sizeof(PCNODE_DESCRIPTOR))
672         {
673             // get first descriptor
674             NodeDescriptor = (PPCNODE_DESCRIPTOR)FilterDescription->Nodes;
675 
676             // sanity check
677             ASSERT(NodeDescriptor);
678 
679             for(Index = 0; Index < FilterDescription->NodeCount; Index++)
680             {
681                 // print prefix
682                 swprintf(Buffer, L"NodeIndex %lu", Index);
683 
684                 // dump automation table
685                 DumpAutomationTable((PPCAUTOMATION_TABLE)NodeDescriptor->AutomationTable, Buffer, L"    ");
686 
687                 // move to next node descriptor
688                 NodeDescriptor = (PPCNODE_DESCRIPTOR)((ULONG_PTR)NodeDescriptor + FilterDescription->NodeSize);
689             }
690         }
691         else
692         {
693             DPRINT1("DRIVER BUG: node size smaller than standard descriptor size\n");
694         }
695     }
696 
697     DPRINT("ConnectionCount: %lu\n", FilterDescription->ConnectionCount);
698 
699     if (FilterDescription->ConnectionCount)
700     {
701         DPRINT("------ Start of Nodes Connections ----------------\n");
702         for(Index = 0; Index < FilterDescription->ConnectionCount; Index++)
703         {
704             DPRINT1("Index %ld FromPin %ld FromNode %ld -> ToPin %ld ToNode %ld\n", Index,
705                                                                                     FilterDescription->Connections[Index].FromNodePin,
706                                                                                     FilterDescription->Connections[Index].FromNode,
707                                                                                     FilterDescription->Connections[Index].ToNodePin,
708                                                                                     FilterDescription->Connections[Index].ToNode);
709         }
710         DPRINT("------ End of Nodes Connections----------------\n");
711     }
712     DPRINT1("======================\n");
713 }
714 
715 NTSTATUS
716 NTAPI
717 PcCreateSubdeviceDescriptor(
718     OUT SUBDEVICE_DESCRIPTOR ** OutSubdeviceDescriptor,
719     IN ULONG InterfaceCount,
720     IN GUID * InterfaceGuids,
721     IN ULONG IdentifierCount,
722     IN KSIDENTIFIER *Identifier,
723     IN ULONG FilterPropertiesCount,
724     IN KSPROPERTY_SET * FilterProperties,
725     IN ULONG Unknown1,
726     IN ULONG Unknown2,
727     IN ULONG PinPropertiesCount,
728     IN KSPROPERTY_SET * PinProperties,
729     IN ULONG EventSetCount,
730     IN KSEVENT_SET * EventSet,
731     IN PPCFILTER_DESCRIPTOR FilterDescription)
732 {
733     SUBDEVICE_DESCRIPTOR * Descriptor;
734     ULONG Index, SubIndex;
735     NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
736     PPCPIN_DESCRIPTOR SrcDescriptor;
737     PPCNODE_DESCRIPTOR NodeDescriptor;
738     PPCPROPERTY_ITEM PropertyItem;
739 
740     // allocate subdevice descriptor
741     Descriptor = (PSUBDEVICE_DESCRIPTOR)AllocateItem(NonPagedPool, sizeof(SUBDEVICE_DESCRIPTOR), TAG_PORTCLASS);
742     if (!Descriptor)
743         return STATUS_INSUFFICIENT_RESOURCES;
744 
745     // initialize physical / symbolic link connection list
746     InitializeListHead(&Descriptor->SymbolicLinkList);
747     InitializeListHead(&Descriptor->PhysicalConnectionList);
748 
749     //FIXME add driver category guids
750     Descriptor->Interfaces = (GUID*)AllocateItem(NonPagedPool, sizeof(GUID) * InterfaceCount, TAG_PORTCLASS);
751     if (!Descriptor->Interfaces)
752         goto cleanup;
753 
754     // copy interface guids
755     RtlCopyMemory(Descriptor->Interfaces, InterfaceGuids, sizeof(GUID) * InterfaceCount);
756     Descriptor->InterfaceCount = InterfaceCount;
757 
758     //DumpFilterDescriptor(FilterDescription);
759 
760     // are any property sets supported by the portcls
761     if (FilterPropertiesCount)
762     {
763        // first allocate filter properties set
764        Descriptor->FilterPropertySet = (PKSPROPERTY_SET)AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * FilterPropertiesCount, TAG_PORTCLASS);
765        if (! Descriptor->FilterPropertySet)
766            goto cleanup;
767 
768        // now copy all filter property sets
769        Descriptor->FilterPropertySetCount = FilterPropertiesCount;
770        for(Index = 0; Index < FilterPropertiesCount; Index++)
771        {
772            // copy property set
773            RtlMoveMemory(&Descriptor->FilterPropertySet[Index], &FilterProperties[Index], sizeof(KSPROPERTY_SET));
774 
775            if (Descriptor->FilterPropertySet[Index].PropertiesCount)
776            {
777                // copy property items to make sure they are dynamically allocated
778                Descriptor->FilterPropertySet[Index].PropertyItem = (PKSPROPERTY_ITEM)AllocateItem(NonPagedPool, FilterProperties[Index].PropertiesCount * sizeof(KSPROPERTY_ITEM), TAG_PORTCLASS);
779                if (!Descriptor->FilterPropertySet[Index].PropertyItem)
780                {
781                    // no memory
782                    goto cleanup;
783                }
784 
785                // copy filter property items
786                RtlMoveMemory((PVOID)Descriptor->FilterPropertySet[Index].PropertyItem, FilterProperties[Index].PropertyItem, FilterProperties[Index].PropertiesCount * sizeof(KSPROPERTY_ITEM));
787            }
788        }
789     }
790 
791     // now check if the filter descriptor supports filter properties
792     if (FilterDescription->AutomationTable)
793     {
794         // get first entry
795         PropertyItem = (PPCPROPERTY_ITEM)FilterDescription->AutomationTable->Properties;
796 
797         // copy driver filter property sets
798         for(Index = 0; Index < FilterDescription->AutomationTable->PropertyCount; Index++)
799         {
800             // add the property item
801             Status = PcAddToPropertyTable(Descriptor, PropertyItem, FALSE);
802 
803             // check for success
804             if (Status != STATUS_SUCCESS)
805             {
806                 // goto cleanup
807                 goto cleanup;
808             }
809 
810             // move to next entry
811             PropertyItem = (PPCPROPERTY_ITEM)((ULONG_PTR)PropertyItem + FilterDescription->AutomationTable->PropertyItemSize);
812         }
813     }
814 
815     // check if the filter has pins
816     if (FilterDescription->PinCount)
817     {
818         // allocate pin factory descriptors
819         Descriptor->Factory.KsPinDescriptor = (PKSPIN_DESCRIPTOR)AllocateItem(NonPagedPool, sizeof(KSPIN_DESCRIPTOR) * FilterDescription->PinCount, TAG_PORTCLASS);
820         if (!Descriptor->Factory.KsPinDescriptor)
821             goto cleanup;
822 
823         // allocate pin instance info
824         Descriptor->Factory.Instances = (PPIN_INSTANCE_INFO)AllocateItem(NonPagedPool, FilterDescription->PinCount * sizeof(PIN_INSTANCE_INFO), TAG_PORTCLASS);
825         if (!Descriptor->Factory.Instances)
826             goto cleanup;
827 
828         // initialize pin factory descriptor
829         Descriptor->Factory.PinDescriptorCount = FilterDescription->PinCount;
830         Descriptor->Factory.PinDescriptorSize = sizeof(KSPIN_DESCRIPTOR);
831 
832         // grab first entry
833         SrcDescriptor = (PPCPIN_DESCRIPTOR)FilterDescription->Pins;
834 
835         // copy pin factories
836         for(Index = 0; Index < FilterDescription->PinCount; Index++)
837         {
838             // copy pin descriptor
839             RtlMoveMemory(&Descriptor->Factory.KsPinDescriptor[Index], &SrcDescriptor->KsPinDescriptor, sizeof(KSPIN_DESCRIPTOR));
840 
841             // initialize pin factory instance data
842             Descriptor->Factory.Instances[Index].CurrentPinInstanceCount = 0;
843             Descriptor->Factory.Instances[Index].MaxFilterInstanceCount = SrcDescriptor->MaxFilterInstanceCount;
844             Descriptor->Factory.Instances[Index].MaxGlobalInstanceCount = SrcDescriptor->MaxGlobalInstanceCount;
845             Descriptor->Factory.Instances[Index].MinFilterInstanceCount = SrcDescriptor->MinFilterInstanceCount;
846 
847             // check if the descriptor has an automation table
848             if (SrcDescriptor->AutomationTable)
849             {
850                 // it has, grab first entry
851                 PropertyItem = (PPCPROPERTY_ITEM)SrcDescriptor->AutomationTable->Properties;
852 
853                 // now add all supported property items
854                 for(SubIndex = 0; SubIndex < SrcDescriptor->AutomationTable->PropertyCount; SubIndex++)
855                 {
856                     // add the property item to the table
857                     Status = PcAddToPropertyTable(Descriptor, PropertyItem, FALSE);
858 
859                     // check for success
860                     if (Status != STATUS_SUCCESS)
861                     {
862                         // goto cleanup
863                         goto cleanup;
864                     }
865 
866                     // move to next entry
867                     PropertyItem = (PPCPROPERTY_ITEM)((ULONG_PTR)PropertyItem + SrcDescriptor->AutomationTable->PropertyItemSize);
868                 }
869             }
870 
871             // move to next entry
872             SrcDescriptor = (PPCPIN_DESCRIPTOR)((ULONG_PTR)SrcDescriptor + FilterDescription->PinSize);
873         }
874     }
875 
876     // allocate topology descriptor
877     Descriptor->Topology = (PKSTOPOLOGY)AllocateItem(NonPagedPool, sizeof(KSTOPOLOGY), TAG_PORTCLASS);
878     if (!Descriptor->Topology)
879         goto cleanup;
880 
881     // are there any connections
882     if (FilterDescription->ConnectionCount)
883     {
884         // allocate connection descriptor
885         Descriptor->Topology->TopologyConnections = (PKSTOPOLOGY_CONNECTION)AllocateItem(NonPagedPool, sizeof(KSTOPOLOGY_CONNECTION) * FilterDescription->ConnectionCount, TAG_PORTCLASS);
886         if (!Descriptor->Topology->TopologyConnections)
887             goto cleanup;
888 
889         // copy connection descriptor
890         RtlMoveMemory((PVOID)Descriptor->Topology->TopologyConnections, FilterDescription->Connections, FilterDescription->ConnectionCount * sizeof(PCCONNECTION_DESCRIPTOR));
891 
892         // store connection count
893         Descriptor->Topology->TopologyConnectionsCount = FilterDescription->ConnectionCount;
894     }
895 
896     // does the filter have nodes
897     if (FilterDescription->NodeCount)
898     {
899         // allocate topology node types array
900         Descriptor->Topology->TopologyNodes = (const GUID *)AllocateItem(NonPagedPool, sizeof(GUID) * FilterDescription->NodeCount, TAG_PORTCLASS);
901         if (!Descriptor->Topology->TopologyNodes)
902             goto cleanup;
903 
904         // allocate topology node names array
905         Descriptor->Topology->TopologyNodesNames = (const GUID *)AllocateItem(NonPagedPool, sizeof(GUID) * FilterDescription->NodeCount, TAG_PORTCLASS);
906         if (!Descriptor->Topology->TopologyNodesNames)
907             goto cleanup;
908 
909         // grab first entry
910        NodeDescriptor = (PPCNODE_DESCRIPTOR)FilterDescription->Nodes;
911 
912        // iterate all nodes and copy node types / names and node properties
913         for(Index = 0; Index < FilterDescription->NodeCount; Index++)
914         {
915             // does it have a type
916             if (NodeDescriptor->Type)
917             {
918                 // copy node type
919                 RtlMoveMemory((PVOID)&Descriptor->Topology->TopologyNodes[Index], NodeDescriptor->Type, sizeof(GUID));
920             }
921 
922             // does it have a node name
923             if (NodeDescriptor->Name)
924             {
925                 // copy node name
926                 RtlMoveMemory((PVOID)&Descriptor->Topology->TopologyNodesNames[Index], NodeDescriptor->Name, sizeof(GUID));
927             }
928 
929             // check if has an automation table
930             if (NodeDescriptor->AutomationTable)
931             {
932                 // grab first entry
933                 PropertyItem = (PPCPROPERTY_ITEM)NodeDescriptor->AutomationTable->Properties;
934 
935                 // copy all node properties into the global property set
936                 for(SubIndex = 0; SubIndex < NodeDescriptor->AutomationTable->PropertyCount; SubIndex++)
937                 {
938                     // add to property set
939                     Status = PcAddToPropertyTable(Descriptor, PropertyItem, TRUE);
940 
941                     // check for success
942                     if (Status != STATUS_SUCCESS)
943                     {
944                         // failed
945                         goto cleanup;
946                     }
947 
948                     // move to next property item
949                     PropertyItem = (PPCPROPERTY_ITEM)((ULONG_PTR)PropertyItem + NodeDescriptor->AutomationTable->PropertyItemSize);
950                 }
951             }
952 
953             // move to next descriptor
954             NodeDescriptor = (PPCNODE_DESCRIPTOR)((ULONG_PTR)NodeDescriptor + FilterDescription->NodeSize);
955         }
956 
957         // now store the topology node count
958         Descriptor->Topology->TopologyNodesCount = FilterDescription->NodeCount;
959     }
960 
961     // store descriptor
962     Descriptor->DeviceDescriptor = FilterDescription;
963 
964     // store result
965     *OutSubdeviceDescriptor = Descriptor;
966     // done
967     return STATUS_SUCCESS;
968 
969 cleanup:
970     if (Descriptor)
971     {
972         if (Descriptor->Interfaces)
973             FreeItem(Descriptor->Interfaces, TAG_PORTCLASS);
974 
975         if (Descriptor->Factory.KsPinDescriptor)
976             FreeItem(Descriptor->Factory.KsPinDescriptor, TAG_PORTCLASS);
977 
978         FreeItem(Descriptor, TAG_PORTCLASS);
979     }
980     return Status;
981 }
982 
983 NTSTATUS
984 NTAPI
985 PcValidateConnectRequest(
986     IN PIRP Irp,
987     IN KSPIN_FACTORY * Factory,
988     OUT PKSPIN_CONNECT * Connect)
989 {
990     return KsValidateConnectRequest(Irp, Factory->PinDescriptorCount, Factory->KsPinDescriptor, Connect);
991 }
992