a71d26a942507ebb58cadc3624ad1411e6668512
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / port_dmus.cpp
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 }