1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/port_dmus.cpp
5  * PURPOSE:         DirectMusic 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 CPortDMus : public CUnknownImpl<IPortDMus, ISubdevice>
18 {
19 public:
20     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
21 
22     IMP_IPortDMus;
23     IMP_ISubdevice;
24     CPortDMus(IUnknown *OuterUnknown){}
25     virtual ~CPortDMus(){}
26 
27 protected:
28 
29     BOOL m_bInitialized;
30     IMiniportDMus * m_pMiniport;
31     IMiniportMidi * m_pMiniportMidi;
32     DEVICE_OBJECT * m_pDeviceObject;
33     PSERVICEGROUP m_ServiceGroup;
34     PPINCOUNT m_pPinCount;
35     PPOWERNOTIFY m_pPowerNotify;
36     PPORTFILTERDMUS m_Filter;
37 
38     PPCFILTER_DESCRIPTOR m_pDescriptor;
39     PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor;
40 
41     friend VOID GetDMusMiniport(IN IPortDMus * iface, IN PMINIPORTDMUS * Miniport, IN PMINIPORTMIDI * MidiMiniport);
42 
43 };
44 
45 static GUID InterfaceGuids[3] =
46 {
47     {
48         /// KS_CATEGORY_AUDIO
49         0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
50     },
51     {
52         /// KS_CATEGORY_RENDER
53         0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
54     },
55     {
56         /// KS_CATEGORY_CAPTURE
57         0x65E8773D, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
58     }
59 };
60 
61 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterDMusTopologySet, TopologyPropertyHandler);
62 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterDMusPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
63 
64 KSPROPERTY_SET PortDMusPropertySet[] =
65 {
66     {
67         &KSPROPSETID_Topology,
68         sizeof(PortFilterDMusTopologySet) / sizeof(KSPROPERTY_ITEM),
69         (const KSPROPERTY_ITEM*)&PortFilterDMusTopologySet,
70         0,
71         NULL
72     },
73     {
74         &KSPROPSETID_Pin,
75         sizeof(PortFilterDMusPinSet) / sizeof(KSPROPERTY_ITEM),
76         (const KSPROPERTY_ITEM*)&PortFilterDMusPinSet,
77         0,
78         NULL
79     }
80 };
81 
82 
83 //---------------------------------------------------------------
84 // IUnknown interface functions
85 //
86 
87 NTSTATUS
88 NTAPI
89 CPortDMus::QueryInterface(
90     IN  REFIID refiid,
91     OUT PVOID* Output)
92 {
93     UNICODE_STRING GuidString;
94 
95     if (IsEqualGUIDAligned(refiid, IID_IPortDMus) ||
96         IsEqualGUIDAligned(refiid, IID_IPortMidi) ||
97         IsEqualGUIDAligned(refiid, IID_IPort) ||
98         IsEqualGUIDAligned(refiid, IID_IUnknown))
99     {
100         *Output = PVOID(PUNKNOWN((IPortDMus*)this));
101         PUNKNOWN(*Output)->AddRef();
102         return STATUS_SUCCESS;
103     }
104     else if (IsEqualGUIDAligned(refiid, IID_ISubdevice))
105     {
106         *Output = PVOID(PSUBDEVICE(this));
107         PUNKNOWN(*Output)->AddRef();
108         return STATUS_SUCCESS;
109     }
110     else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) ||
111              IsEqualGUIDAligned(refiid, IID_IDrmPort2))
112     {
113         return NewIDrmPort((PDRMPORT2*)Output);
114     }
115     else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion))
116     {
117         return NewPortClsVersion((PPORTCLSVERSION*)Output);
118     }
119     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice))
120     {
121         return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
122     }
123     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection))
124     {
125         return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
126     }
127 
128     if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
129     {
130         DPRINT("IPortMidi_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
131         RtlFreeUnicodeString(&GuidString);
132     }
133     return STATUS_UNSUCCESSFUL;
134 }
135 
136 //---------------------------------------------------------------
137 // IPort interface functions
138 //
139 
140 NTSTATUS
141 NTAPI
142 CPortDMus::GetDeviceProperty(
143     IN DEVICE_REGISTRY_PROPERTY  DeviceRegistryProperty,
144     IN ULONG  BufferLength,
145     OUT PVOID  PropertyBuffer,
146     OUT PULONG  ReturnLength)
147 {
148     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
149 
150     if (!m_bInitialized)
151     {
152         DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n");
153         return STATUS_UNSUCCESSFUL;
154     }
155 
156     return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
157 }
158 
159 NTSTATUS
160 NTAPI
161 CPortDMus::Init(
162     IN PDEVICE_OBJECT  DeviceObject,
163     IN PIRP  Irp,
164     IN PUNKNOWN  UnknownMiniport,
165     IN PUNKNOWN  UnknownAdapter  OPTIONAL,
166     IN PRESOURCELIST  ResourceList)
167 {
168     IMiniportDMus * Miniport = NULL;
169     IMiniportMidi * MidiMiniport = NULL;
170     NTSTATUS Status;
171     PSERVICEGROUP ServiceGroup = NULL;
172     PPINCOUNT PinCount;
173     PPOWERNOTIFY PowerNotify;
174 
175     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
176 
177     if (m_bInitialized)
178     {
179         DPRINT("IPortDMus_Init called again\n");
180         return STATUS_SUCCESS;
181     }
182 
183     Status = UnknownMiniport->QueryInterface(IID_IMiniportDMus, (PVOID*)&Miniport);
184     if (!NT_SUCCESS(Status))
185     {
186         // check for legacy interface
187         Status = UnknownMiniport->QueryInterface(IID_IMiniportMidi, (PVOID*)&MidiMiniport);
188         if (!NT_SUCCESS(Status))
189         {
190             DPRINT("IPortDMus_Init called with invalid IMiniport adapter\n");
191             return STATUS_INVALID_PARAMETER;
192         }
193     }
194 
195     // Initialize port object
196     m_pMiniport = Miniport;
197     m_pMiniportMidi = MidiMiniport;
198     m_pDeviceObject = DeviceObject;
199     m_bInitialized = TRUE;
200 
201     if (Miniport)
202     {
203         // initialize IMiniportDMus
204         Status = Miniport->Init(UnknownAdapter, ResourceList, this, &ServiceGroup);
205         if (!NT_SUCCESS(Status))
206         {
207             DPRINT("IMiniportDMus_Init failed with %x\n", Status);
208             m_bInitialized = FALSE;
209             return Status;
210         }
211 
212         // get the miniport device descriptor
213         Status = Miniport->GetDescription(&m_pDescriptor);
214         if (!NT_SUCCESS(Status))
215         {
216             DPRINT("failed to get description\n");
217             Miniport->Release();
218             m_bInitialized = FALSE;
219             return Status;
220         }
221 
222         // increment reference on miniport adapter
223         Miniport->AddRef();
224 
225     }
226     else
227     {
228         // initialize IMiniportMidi
229         Status = MidiMiniport->Init(UnknownAdapter, ResourceList, (IPortMidi*)this, &ServiceGroup);
230         if (!NT_SUCCESS(Status))
231         {
232             DPRINT("IMiniportMidi_Init failed with %x\n", Status);
233             m_bInitialized = FALSE;
234             return Status;
235         }
236 
237         // get the miniport device descriptor
238         Status = MidiMiniport->GetDescription(&m_pDescriptor);
239         if (!NT_SUCCESS(Status))
240         {
241             DPRINT("failed to get description\n");
242             MidiMiniport->Release();
243             m_bInitialized = FALSE;
244             return Status;
245         }
246 
247         // increment reference on miniport adapter
248         MidiMiniport->AddRef();
249     }
250 
251     // create the subdevice descriptor
252     Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor,
253                                          3,
254                                          InterfaceGuids,
255                                          0,
256                                          NULL,
257                                          2,
258                                          PortDMusPropertySet,
259                                          0,
260                                          0,
261                                          0,
262                                          NULL,
263                                          0,
264                                          NULL,
265                                          m_pDescriptor);
266 
267     if (!NT_SUCCESS(Status))
268     {
269         DPRINT("Failed to create descriptor\n");
270 
271         if (Miniport)
272             Miniport->Release();
273         else
274             MidiMiniport->Release();
275 
276         m_bInitialized = FALSE;
277         return Status;
278     }
279 
280     if (m_ServiceGroup == NULL && ServiceGroup)
281     {
282         // register service group
283         m_ServiceGroup = ServiceGroup;
284     }
285 
286     // check if it supports IPinCount interface
287     Status = UnknownMiniport->QueryInterface(IID_IPinCount, (PVOID*)&PinCount);
288     if (NT_SUCCESS(Status))
289     {
290         // store IPinCount interface
291         m_pPinCount = PinCount;
292     }
293 
294     // does the Miniport adapter support IPowerNotify interface*/
295     Status = UnknownMiniport->QueryInterface(IID_IPowerNotify, (PVOID*)&PowerNotify);
296     if (NT_SUCCESS(Status))
297     {
298         // store reference
299         m_pPowerNotify = PowerNotify;
300     }
301 
302     return STATUS_SUCCESS;
303 }
304 
305 
306 NTSTATUS
307 NTAPI
308 CPortDMus::NewRegistryKey(
309     OUT PREGISTRYKEY  *OutRegistryKey,
310     IN PUNKNOWN  OuterUnknown  OPTIONAL,
311     IN ULONG  RegistryKeyType,
312     IN ACCESS_MASK  DesiredAccess,
313     IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
314     IN ULONG  CreateOptions  OPTIONAL,
315     OUT PULONG  Disposition  OPTIONAL)
316 {
317     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
318 
319     if (!m_bInitialized)
320     {
321         DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n");
322         return STATUS_UNSUCCESSFUL;
323     }
324 
325     return PcNewRegistryKey(OutRegistryKey,
326                             OuterUnknown,
327                             RegistryKeyType,
328                             DesiredAccess,
329                             m_pDeviceObject,
330                             (ISubdevice*)this,
331                             ObjectAttributes,
332                             CreateOptions,
333                             Disposition);
334 }
335 
336 VOID
337 NTAPI
338 CPortDMus::Notify(
339     IN PSERVICEGROUP  ServiceGroup  OPTIONAL)
340 {
341     if (ServiceGroup)
342     {
343         ServiceGroup->RequestService ();
344         return;
345     }
346 
347     PC_ASSERT(m_ServiceGroup);
348 
349     // notify miniport service group
350     m_ServiceGroup->RequestService();
351 
352     // notify stream miniport service group
353     if (m_Filter)
354     {
355         m_Filter->NotifyPins();
356     }
357 }
358 
359 VOID
360 NTAPI
361 CPortDMus::RegisterServiceGroup(
362     IN PSERVICEGROUP  ServiceGroup)
363 {
364     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
365 
366     m_ServiceGroup = ServiceGroup;
367 
368     ServiceGroup->AddMember(PSERVICESINK(this));
369 }
370 //---------------------------------------------------------------
371 // ISubdevice interface
372 //
373 
374 NTSTATUS
375 NTAPI
376 CPortDMus::NewIrpTarget(
377     OUT struct IIrpTarget **OutTarget,
378     IN PCWSTR Name,
379     IN PUNKNOWN Unknown,
380     IN POOL_TYPE PoolType,
381     IN PDEVICE_OBJECT DeviceObject,
382     IN PIRP Irp,
383     IN KSOBJECT_CREATE *CreateObject)
384 {
385     NTSTATUS Status;
386     PPORTFILTERDMUS Filter;
387 
388     DPRINT("ISubDevice_NewIrpTarget this %p\n", this);
389 
390     if (m_Filter)
391     {
392         *OutTarget = (IIrpTarget*)m_Filter;
393         return STATUS_SUCCESS;
394     }
395 
396 
397     Status = NewPortFilterDMus(&Filter);
398     if (!NT_SUCCESS(Status))
399     {
400         return Status;
401     }
402 
403     Status = Filter->Init(PPORTDMUS(this));
404     if (!NT_SUCCESS(Status))
405     {
406         Filter->Release();
407         return Status;
408     }
409 
410     *OutTarget = (IIrpTarget*)Filter;
411     return Status;
412 }
413 
414 NTSTATUS
415 NTAPI
416 CPortDMus::ReleaseChildren()
417 {
418     UNIMPLEMENTED;
419     return STATUS_UNSUCCESSFUL;
420 }
421 
422 NTSTATUS
423 NTAPI
424 CPortDMus::GetDescriptor(
425     IN SUBDEVICE_DESCRIPTOR ** Descriptor)
426 {
427     DPRINT("ISubDevice_GetDescriptor this %p\n", this);
428     *Descriptor = m_SubDeviceDescriptor;
429     return STATUS_SUCCESS;
430 }
431 
432 NTSTATUS
433 NTAPI
434 CPortDMus::DataRangeIntersection(
435     IN  ULONG PinId,
436     IN  PKSDATARANGE DataRange,
437     IN  PKSDATARANGE MatchingDataRange,
438     IN  ULONG OutputBufferLength,
439     OUT PVOID ResultantFormat OPTIONAL,
440     OUT PULONG ResultantFormatLength)
441 {
442     DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
443 
444     if (m_pMiniport)
445     {
446         return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
447     }
448 
449     return STATUS_UNSUCCESSFUL;
450 }
451 
452 NTSTATUS
453 NTAPI
454 CPortDMus::PowerChangeNotify(
455     IN POWER_STATE PowerState)
456 {
457     if (m_pPowerNotify)
458     {
459         m_pPowerNotify->PowerChangeNotify(PowerState);
460     }
461 
462     return STATUS_SUCCESS;
463 }
464 
465 
466 NTSTATUS
467 NTAPI
468 CPortDMus::PinCount(
469     IN ULONG  PinId,
470     IN OUT PULONG  FilterNecessary,
471     IN OUT PULONG  FilterCurrent,
472     IN OUT PULONG  FilterPossible,
473     IN OUT PULONG  GlobalCurrent,
474     IN OUT PULONG  GlobalPossible)
475 {
476     if (m_pPinCount)
477     {
478        m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
479        return STATUS_SUCCESS;
480     }
481 
482     // FIXME
483     // scan filter descriptor
484 
485     return STATUS_UNSUCCESSFUL;
486 }
487 
488 
489 
490 NTSTATUS
491 NewPortDMus(
492     OUT PPORT* OutPort)
493 {
494     NTSTATUS Status;
495     CPortDMus * Port = new(NonPagedPool, TAG_PORTCLASS) CPortDMus(NULL);
496     if (!Port)
497         return STATUS_INSUFFICIENT_RESOURCES;
498 
499     Status = Port->QueryInterface(IID_IPort, (PVOID*)OutPort);
500 
501     if (!NT_SUCCESS(Status))
502     {
503         delete Port;
504     }
505 
506     DPRINT("NewPortDMus %p Status %u\n", Port, Status);
507     return Status;
508 
509 }
510 
511 
512 
513 VOID
514 GetDMusMiniport(
515     IN IPortDMus * iface,
516     IN PMINIPORTDMUS * Miniport,
517     IN PMINIPORTMIDI * MidiMiniport)
518 {
519     CPortDMus * This = (CPortDMus*)iface;
520 
521     *Miniport = This->m_pMiniport;
522     *MidiMiniport = This->m_pMiniportMidi;
523 }
524