1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/port_topology.cpp
5  * PURPOSE:         Topology Port driver
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 class CPortTopology : public IPortTopology,
18                       public ISubdevice,
19                       public IPortEvents
20 {
21 public:
22     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
23 
24     STDMETHODIMP_(ULONG) AddRef()
25     {
26         InterlockedIncrement(&m_Ref);
27         return m_Ref;
28     }
29     STDMETHODIMP_(ULONG) Release()
30     {
31         InterlockedDecrement(&m_Ref);
32 
33         if (!m_Ref)
34         {
35             delete this;
36             return 0;
37         }
38         return m_Ref;
39     }
40     IMP_IPortTopology;
41     IMP_ISubdevice;
42     IMP_IPortEvents;
43     CPortTopology(IUnknown *OuterUnknown){}
44     virtual ~CPortTopology(){}
45 
46 protected:
47     BOOL m_bInitialized;
48 
49     PMINIPORTTOPOLOGY m_pMiniport;
50     PDEVICE_OBJECT m_pDeviceObject;
51     PPINCOUNT m_pPinCount;
52     PPOWERNOTIFY m_pPowerNotify;
53 
54     PPCFILTER_DESCRIPTOR m_pDescriptor;
55     PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor;
56     IPortFilterTopology * m_Filter;
57 
58     LONG m_Ref;
59 
60     friend PMINIPORTTOPOLOGY GetTopologyMiniport(PPORTTOPOLOGY Port);
61 
62 };
63 
64 static GUID InterfaceGuids[2] =
65 {
66     {
67         /// KS_CATEGORY_AUDIO
68         0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
69     },
70     {
71         /// KS_CATEGORY_TOPOLOGY
72         0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00}
73     }
74 };
75 
76 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterTopologyTopologySet, TopologyPropertyHandler);
77 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterTopologyPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
78 
79 KSPROPERTY_SET TopologyPropertySet[] =
80 {
81     {
82         &KSPROPSETID_Topology,
83         sizeof(PortFilterTopologyTopologySet) / sizeof(KSPROPERTY_ITEM),
84         (const KSPROPERTY_ITEM*)&PortFilterTopologyTopologySet,
85         0,
86         NULL
87     },
88     {
89         &KSPROPSETID_Pin,
90         sizeof(PortFilterTopologyPinSet) / sizeof(KSPROPERTY_ITEM),
91         (const KSPROPERTY_ITEM*)&PortFilterTopologyPinSet,
92         0,
93         NULL
94     }
95 };
96 
97 //---------------------------------------------------------------
98 // IPortEvents
99 //
100 
101 
102 void
103 NTAPI
104 CPortTopology::AddEventToEventList(
105     IN PKSEVENT_ENTRY EventEntry)
106 {
107     UNIMPLEMENTED;
108 }
109 
110 void
111 NTAPI
112 CPortTopology::GenerateEventList(
113     IN  GUID* Set OPTIONAL,
114     IN  ULONG EventId,
115     IN  BOOL PinEvent,
116     IN  ULONG PinId,
117     IN  BOOL NodeEvent,
118     IN  ULONG NodeId)
119 {
120     UNIMPLEMENTED;
121 }
122 
123 
124 //---------------------------------------------------------------
125 // IUnknown interface functions
126 //
127 
128 NTSTATUS
129 NTAPI
130 CPortTopology::QueryInterface(
131     IN  REFIID refiid,
132     OUT PVOID* Output)
133 {
134     UNICODE_STRING GuidString;
135 
136     DPRINT("IPortTopology_fnQueryInterface\n");
137 
138     if (IsEqualGUIDAligned(refiid, IID_IPortTopology) ||
139         IsEqualGUIDAligned(refiid, IID_IPort) ||
140         IsEqualGUIDAligned(refiid, IID_IUnknown))
141     {
142         *Output = PVOID(PUNKNOWN((IPortTopology*)this));
143         PUNKNOWN(*Output)->AddRef();
144         return STATUS_SUCCESS;
145     }
146     else if (IsEqualGUIDAligned(refiid, IID_IPortEvents))
147     {
148         *Output = PVOID(PPORTEVENTS(this));
149         PUNKNOWN(*Output)->AddRef();
150         return STATUS_SUCCESS;
151     }
152     else if (IsEqualGUIDAligned(refiid, IID_ISubdevice))
153     {
154         *Output = PVOID(PSUBDEVICE(this));
155         PUNKNOWN(*Output)->AddRef();
156         return STATUS_SUCCESS;
157     }
158     else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion))
159     {
160         return NewPortClsVersion((PPORTCLSVERSION*)Output);
161     }
162     else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) ||
163              IsEqualGUIDAligned(refiid, IID_IDrmPort2))
164     {
165         return NewIDrmPort((PDRMPORT2*)Output);
166     }
167     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice))
168     {
169         return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
170     }
171     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection))
172     {
173         return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
174     }
175 
176     if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
177     {
178         DPRINT1("IPortTopology_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
179         RtlFreeUnicodeString(&GuidString);
180     }
181     return STATUS_UNSUCCESSFUL;
182 }
183 
184 //---------------------------------------------------------------
185 // IPort interface functions
186 //
187 
188 NTSTATUS
189 NTAPI
190 CPortTopology::GetDeviceProperty(
191     IN DEVICE_REGISTRY_PROPERTY  DeviceRegistryProperty,
192     IN ULONG  BufferLength,
193     OUT PVOID  PropertyBuffer,
194     OUT PULONG  ReturnLength)
195 {
196     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
197 
198     if (!m_bInitialized)
199     {
200         DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n");
201         return STATUS_UNSUCCESSFUL;
202     }
203 
204     return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
205 }
206 
207 NTSTATUS
208 NTAPI
209 CPortTopology::Init(
210     IN PDEVICE_OBJECT  DeviceObject,
211     IN PIRP  Irp,
212     IN PUNKNOWN  UnknownMiniport,
213     IN PUNKNOWN  UnknownAdapter  OPTIONAL,
214     IN PRESOURCELIST  ResourceList)
215 {
216     IMiniportTopology * Miniport;
217     NTSTATUS Status;
218 
219     DPRINT("IPortTopology_fnInit entered This %p DeviceObject %p Irp %p UnknownMiniport %p UnknownAdapter %p ResourceList %p\n",
220             this, DeviceObject, Irp, UnknownMiniport, UnknownAdapter, ResourceList);
221 
222     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
223 
224     if (m_bInitialized)
225     {
226         DPRINT("IPortTopology_Init called again\n");
227         return STATUS_SUCCESS;
228     }
229 
230     Status = UnknownMiniport->QueryInterface(IID_IMiniportTopology, (PVOID*)&Miniport);
231     if (!NT_SUCCESS(Status))
232     {
233         DPRINT("IPortTopology_Init called with invalid IMiniport adapter\n");
234         return STATUS_INVALID_PARAMETER;
235     }
236 
237     // Initialize port object
238     m_pMiniport = Miniport;
239     m_pDeviceObject = DeviceObject;
240     m_bInitialized = TRUE;
241 
242     // now initialize the miniport driver
243     Status = Miniport->Init(UnknownAdapter, ResourceList, this);
244     if (!NT_SUCCESS(Status))
245     {
246         DPRINT("IPortTopology_Init failed with %x\n", Status);
247         m_bInitialized = FALSE;
248         Miniport->Release();
249         return Status;
250     }
251 
252     // get the miniport device descriptor
253     Status = Miniport->GetDescription(&m_pDescriptor);
254     if (!NT_SUCCESS(Status))
255     {
256         DPRINT("failed to get description\n");
257         Miniport->Release();
258         m_bInitialized = FALSE;
259         return Status;
260     }
261 
262     // create the subdevice descriptor
263     Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor,
264                                          2,
265                                          InterfaceGuids,
266                                          0,
267                                          NULL,
268                                          2,
269                                          TopologyPropertySet,
270                                          0,
271                                          0,
272                                          0,
273                                          NULL,
274                                          0,
275                                          NULL,
276                                          m_pDescriptor);
277 
278 
279     DPRINT("IPortTopology_fnInit success\n");
280     if (NT_SUCCESS(Status))
281     {
282         // store for node property requests
283         m_SubDeviceDescriptor->UnknownMiniport = UnknownMiniport;
284     }
285 
286     return STATUS_SUCCESS;
287 }
288 
289 
290 NTSTATUS
291 NTAPI
292 CPortTopology::NewRegistryKey(
293     OUT PREGISTRYKEY  *OutRegistryKey,
294     IN PUNKNOWN  OuterUnknown  OPTIONAL,
295     IN ULONG  RegistryKeyType,
296     IN ACCESS_MASK  DesiredAccess,
297     IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
298     IN ULONG  CreateOptions  OPTIONAL,
299     OUT PULONG  Disposition  OPTIONAL)
300 {
301     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
302 
303     if (!m_bInitialized)
304     {
305         DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n");
306         return STATUS_UNSUCCESSFUL;
307     }
308     return PcNewRegistryKey(OutRegistryKey,
309                             OuterUnknown,
310                             RegistryKeyType,
311                             DesiredAccess,
312                             m_pDeviceObject,
313                             (ISubdevice*)this,
314                             ObjectAttributes,
315                             CreateOptions,
316                             Disposition);
317 }
318 
319 //---------------------------------------------------------------
320 // ISubdevice interface
321 //
322 
323 NTSTATUS
324 NTAPI
325 CPortTopology::NewIrpTarget(
326     OUT struct IIrpTarget **OutTarget,
327     IN PCWSTR Name,
328     IN PUNKNOWN Unknown,
329     IN POOL_TYPE PoolType,
330     IN PDEVICE_OBJECT DeviceObject,
331     IN PIRP Irp,
332     IN KSOBJECT_CREATE *CreateObject)
333 {
334     NTSTATUS Status;
335     IPortFilterTopology * Filter;
336 
337     // is there already an instance of the filter
338     if (m_Filter)
339     {
340         // it is, let's return the result
341         *OutTarget = (IIrpTarget*)m_Filter;
342 
343         // increment reference
344         m_Filter->AddRef();
345         return STATUS_SUCCESS;
346     }
347 
348     // create new instance of filter
349     Status = NewPortFilterTopology(&Filter);
350     if (!NT_SUCCESS(Status))
351     {
352         // not enough memory
353         return Status;
354     }
355 
356     // initialize the filter
357     Status = Filter->Init((IPortTopology*)this);
358     if (!NT_SUCCESS(Status))
359     {
360         // destroy filter
361         Filter->Release();
362         // return status
363         return Status;
364     }
365 
366     // store result
367     *OutTarget = (IIrpTarget*)Filter;
368     // store for later re-use
369     m_Filter = Filter;
370     // return status
371     return Status;
372 }
373 
374 NTSTATUS
375 NTAPI
376 CPortTopology::ReleaseChildren()
377 {
378     DPRINT("ISubDevice_fnReleaseChildren\n");
379 
380     // release the filter
381     m_Filter->Release();
382 
383     // release the miniport
384     DPRINT("Refs %u\n", m_pMiniport->Release());
385 
386     return STATUS_SUCCESS;
387 }
388 
389 NTSTATUS
390 NTAPI
391 CPortTopology::GetDescriptor(
392     IN SUBDEVICE_DESCRIPTOR ** Descriptor)
393 {
394     DPRINT("ISubDevice_GetDescriptor this %p Descp %p\n", this, m_SubDeviceDescriptor);
395     *Descriptor = m_SubDeviceDescriptor;
396     return STATUS_SUCCESS;
397 }
398 
399 NTSTATUS
400 NTAPI
401 CPortTopology::DataRangeIntersection(
402     IN  ULONG PinId,
403     IN  PKSDATARANGE DataRange,
404     IN  PKSDATARANGE MatchingDataRange,
405     IN  ULONG OutputBufferLength,
406     OUT PVOID ResultantFormat OPTIONAL,
407     OUT PULONG ResultantFormatLength)
408 {
409     DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
410 
411     if (m_pMiniport)
412     {
413         return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
414     }
415 
416     return STATUS_UNSUCCESSFUL;
417 }
418 
419 NTSTATUS
420 NTAPI
421 CPortTopology::PowerChangeNotify(
422     IN POWER_STATE PowerState)
423 {
424     if (m_pPowerNotify)
425     {
426         m_pPowerNotify->PowerChangeNotify(PowerState);
427     }
428 
429     return STATUS_SUCCESS;
430 }
431 
432 NTSTATUS
433 NTAPI
434 CPortTopology::PinCount(
435     IN ULONG  PinId,
436     IN OUT PULONG  FilterNecessary,
437     IN OUT PULONG  FilterCurrent,
438     IN OUT PULONG  FilterPossible,
439     IN OUT PULONG  GlobalCurrent,
440     IN OUT PULONG  GlobalPossible)
441 {
442     if (m_pPinCount)
443     {
444        m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
445        return STATUS_SUCCESS;
446     }
447 
448     // FIXME
449      // scan filter descriptor
450 
451     return STATUS_UNSUCCESSFUL;
452 }
453 
454 
455 NTSTATUS
456 NTAPI
457 PcCreatePinDispatch(
458     IN  PDEVICE_OBJECT DeviceObject,
459     IN  PIRP Irp)
460 {
461     NTSTATUS Status;
462     IIrpTarget *Filter;
463     IIrpTarget *Pin;
464     PKSOBJECT_CREATE_ITEM CreateItem;
465 
466     // access the create item
467     CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
468     // sanity check
469     PC_ASSERT(CreateItem);
470 
471     DPRINT("PcCreatePinDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
472 
473     Filter = (IIrpTarget*)CreateItem->Context;
474 
475     // sanity checks
476     PC_ASSERT(Filter != NULL);
477     PC_ASSERT_IRQL(PASSIVE_LEVEL);
478 
479 
480 #if KS_IMPLEMENTED
481     Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
482     if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
483     {
484         DPRINT("PcCreatePinDispatch failed to reference device header\n");
485 
486         FreeItem(Entry, TAG_PORTCLASS);
487         goto cleanup;
488     }
489 #endif
490 
491     Status = Filter->NewIrpTarget(&Pin,
492                                   KSSTRING_Pin,
493                                   NULL,
494                                   NonPagedPool,
495                                   DeviceObject,
496                                   Irp,
497                                   NULL);
498 
499     DPRINT("PcCreatePinDispatch Status %x\n", Status);
500 
501     if (NT_SUCCESS(Status))
502     {
503         // create the dispatch object
504         // FIXME need create item for clock
505         Status = NewDispatchObject(Irp, Pin, 0, NULL);
506         DPRINT("Pin %p\n", Pin);
507     }
508 
509     DPRINT("CreatePinWorkerRoutine completing irp %p\n", Irp);
510     // save status in irp
511     Irp->IoStatus.Status = Status;
512     Irp->IoStatus.Information = 0;
513     // complete the request
514     IoCompleteRequest(Irp, IO_NO_INCREMENT);
515     return Status;
516 }
517 
518 NTSTATUS
519 NTAPI
520 PcCreateItemDispatch(
521     IN  PDEVICE_OBJECT DeviceObject,
522     IN  PIRP Irp)
523 {
524     NTSTATUS Status;
525     ISubdevice * SubDevice;
526     IIrpTarget *Filter;
527     PKSOBJECT_CREATE_ITEM CreateItem, PinCreateItem;
528 
529     // access the create item
530     CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
531 
532     DPRINT("PcCreateItemDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
533 
534     // get the subdevice
535     SubDevice = (ISubdevice*)CreateItem->Context;
536 
537     // sanity checks
538     PC_ASSERT(SubDevice != NULL);
539 
540 
541 #if KS_IMPLEMENTED
542     Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
543     if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
544     {
545         DPRINT("PcCreateItemDispatch failed to reference device header\n");
546 
547         FreeItem(Entry, TAG_PORTCLASS);
548         goto cleanup;
549     }
550 #endif
551 
552     // get filter object
553     Status = SubDevice->NewIrpTarget(&Filter,
554                                      NULL,
555                                      NULL,
556                                      NonPagedPool,
557                                      DeviceObject,
558                                      Irp,
559                                      NULL);
560     if (!NT_SUCCESS(Status))
561     {
562         DPRINT("Failed to get filter object\n");
563         Irp->IoStatus.Status = Status;
564         IoCompleteRequest(Irp, IO_NO_INCREMENT);
565         return Status;
566     }
567 
568     // allocate pin create item
569     PinCreateItem = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS);
570     if (!PinCreateItem)
571     {
572         // not enough memory
573         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
574         IoCompleteRequest(Irp, IO_NO_INCREMENT);
575         return STATUS_INSUFFICIENT_RESOURCES;
576     }
577 
578     // initialize pin create item
579     PinCreateItem->Context = (PVOID)Filter;
580     PinCreateItem->Create = PcCreatePinDispatch;
581     RtlInitUnicodeString(&PinCreateItem->ObjectClass, KSSTRING_Pin);
582     // FIXME copy security descriptor
583 
584     // now allocate a dispatch object
585     Status = NewDispatchObject(Irp, Filter, 1, PinCreateItem);
586 
587     // complete request
588     Irp->IoStatus.Status = Status;
589     IoCompleteRequest(Irp, IO_NO_INCREMENT);
590 
591     return STATUS_SUCCESS;
592 }
593 
594 
595 NTSTATUS
596 NewPortTopology(
597     OUT PPORT* OutPort)
598 {
599     CPortTopology * This;
600     NTSTATUS Status;
601 
602     This= new(NonPagedPool, TAG_PORTCLASS) CPortTopology(NULL);
603     if (!This)
604         return STATUS_INSUFFICIENT_RESOURCES;
605 
606     Status = This->QueryInterface(IID_IPort, (PVOID*)OutPort);
607 
608     if (!NT_SUCCESS(Status))
609     {
610         delete This;
611     }
612 
613     DPRINT("NewPortTopology %p Status %x\n", *OutPort, Status);
614     return Status;
615 }
616 
617 
618 PMINIPORTTOPOLOGY
619 GetTopologyMiniport(
620     PPORTTOPOLOGY Port)
621 {
622     CPortTopology * This = (CPortTopology*)Port;
623     return This->m_pMiniport;
624 }
625