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