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