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