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