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;
CPortDMus(IUnknown * OuterUnknown)21 CPortDMus(IUnknown *OuterUnknown){}
~CPortDMus()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
QueryInterface(IN REFIID refiid,OUT PVOID * Output)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
GetDeviceProperty(IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty,IN ULONG BufferLength,OUT PVOID PropertyBuffer,OUT PULONG ReturnLength)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
Init(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PUNKNOWN UnknownMiniport,IN PUNKNOWN UnknownAdapter OPTIONAL,IN PRESOURCELIST ResourceList)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
NewRegistryKey(OUT PREGISTRYKEY * OutRegistryKey,IN PUNKNOWN OuterUnknown OPTIONAL,IN ULONG RegistryKeyType,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN ULONG CreateOptions OPTIONAL,OUT PULONG Disposition OPTIONAL)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
Notify(IN PSERVICEGROUP ServiceGroup OPTIONAL)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
RegisterServiceGroup(IN PSERVICEGROUP ServiceGroup)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
NewIrpTarget(OUT struct IIrpTarget ** OutTarget,IN PCWSTR Name,IN PUNKNOWN Unknown,IN POOL_TYPE PoolType,IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN KSOBJECT_CREATE * CreateObject)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
ReleaseChildren()410 CPortDMus::ReleaseChildren()
411 {
412 UNIMPLEMENTED;
413 return STATUS_UNSUCCESSFUL;
414 }
415
416 NTSTATUS
417 NTAPI
GetDescriptor(IN SUBDEVICE_DESCRIPTOR ** Descriptor)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
DataRangeIntersection(IN ULONG PinId,IN PKSDATARANGE DataRange,IN PKSDATARANGE MatchingDataRange,IN ULONG OutputBufferLength,OUT PVOID ResultantFormat OPTIONAL,OUT PULONG ResultantFormatLength)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
PowerChangeNotify(IN POWER_STATE PowerState)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
PinCount(IN ULONG PinId,IN OUT PULONG FilterNecessary,IN OUT PULONG FilterCurrent,IN OUT PULONG FilterPossible,IN OUT PULONG GlobalCurrent,IN OUT PULONG GlobalPossible)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
NewPortDMus(OUT PPORT * OutPort)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
GetDMusMiniport(IN IPortDMus * iface,IN PMINIPORTDMUS * Miniport,IN PMINIPORTMIDI * MidiMiniport)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