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