Sync with trunk head (r49139)
[reactos.git] / drivers / wdm / audio / backpln / portcls / port_topology.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/port_topology.cpp
5 * PURPOSE: Topology Port driver
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.hpp"
10
11 class CPortTopology : public IPortTopology,
12 public ISubdevice,
13 public IPortEvents
14 {
15 public:
16 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
17
18 STDMETHODIMP_(ULONG) AddRef()
19 {
20 InterlockedIncrement(&m_Ref);
21 return m_Ref;
22 }
23 STDMETHODIMP_(ULONG) Release()
24 {
25 InterlockedDecrement(&m_Ref);
26
27 if (!m_Ref)
28 {
29 delete this;
30 return 0;
31 }
32 return m_Ref;
33 }
34 IMP_IPortTopology;
35 IMP_ISubdevice;
36 IMP_IPortEvents;
37 CPortTopology(IUnknown *OuterUnknown){}
38 virtual ~CPortTopology(){}
39
40 protected:
41 BOOL m_bInitialized;
42
43 PMINIPORTTOPOLOGY m_pMiniport;
44 PDEVICE_OBJECT m_pDeviceObject;
45 PPINCOUNT m_pPinCount;
46 PPOWERNOTIFY m_pPowerNotify;
47
48 PPCFILTER_DESCRIPTOR m_pDescriptor;
49 PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor;
50 IPortFilterTopology * m_Filter;
51
52 LONG m_Ref;
53
54 friend PMINIPORTTOPOLOGY GetTopologyMiniport(PPORTTOPOLOGY Port);
55
56 };
57
58 static GUID InterfaceGuids[2] =
59 {
60 {
61 /// KS_CATEGORY_AUDIO
62 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
63 },
64 {
65 /// KS_CATEGORY_TOPOLOGY
66 0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00}
67 }
68 };
69
70 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterTopologyTopologySet, TopologyPropertyHandler);
71 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterTopologyPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
72
73 KSPROPERTY_SET TopologyPropertySet[] =
74 {
75 {
76 &KSPROPSETID_Topology,
77 sizeof(PortFilterTopologyTopologySet) / sizeof(KSPROPERTY_ITEM),
78 (const KSPROPERTY_ITEM*)&PortFilterTopologyTopologySet,
79 0,
80 NULL
81 },
82 {
83 &KSPROPSETID_Pin,
84 sizeof(PortFilterTopologyPinSet) / sizeof(KSPROPERTY_ITEM),
85 (const KSPROPERTY_ITEM*)&PortFilterTopologyPinSet,
86 0,
87 NULL
88 }
89 };
90
91 //---------------------------------------------------------------
92 // IPortEvents
93 //
94
95
96 void
97 NTAPI
98 CPortTopology::AddEventToEventList(
99 IN PKSEVENT_ENTRY EventEntry)
100 {
101 UNIMPLEMENTED
102 }
103
104 void
105 NTAPI
106 CPortTopology::GenerateEventList(
107 IN GUID* Set OPTIONAL,
108 IN ULONG EventId,
109 IN BOOL PinEvent,
110 IN ULONG PinId,
111 IN BOOL NodeEvent,
112 IN ULONG NodeId)
113 {
114 UNIMPLEMENTED
115 }
116
117
118 //---------------------------------------------------------------
119 // IUnknown interface functions
120 //
121
122 NTSTATUS
123 NTAPI
124 CPortTopology::QueryInterface(
125 IN REFIID refiid,
126 OUT PVOID* Output)
127 {
128 UNICODE_STRING GuidString;
129
130 DPRINT("IPortTopology_fnQueryInterface\n");
131
132 if (IsEqualGUIDAligned(refiid, IID_IPortTopology) ||
133 IsEqualGUIDAligned(refiid, IID_IPort) ||
134 IsEqualGUIDAligned(refiid, IID_IUnknown))
135 {
136 *Output = PVOID(PUNKNOWN((IPortTopology*)this));
137 PUNKNOWN(*Output)->AddRef();
138 return STATUS_SUCCESS;
139 }
140 else if (IsEqualGUIDAligned(refiid, IID_ISubdevice))
141 {
142 *Output = PVOID(PSUBDEVICE(this));
143 PUNKNOWN(*Output)->AddRef();
144 return STATUS_SUCCESS;
145 }
146 else if (IsEqualGUIDAligned(refiid, IID_IPortEvents))
147 {
148 *Output = PVOID(PPORTEVENTS(this));
149 PUNKNOWN(*Output)->AddRef();
150 return STATUS_SUCCESS;
151 }
152 else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion))
153 {
154 return NewPortClsVersion((PPORTCLSVERSION*)Output);
155 }
156 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice))
157 {
158 return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
159 }
160 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection))
161 {
162 return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
163 }
164
165 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
166 {
167 DPRINT("IPortTopology_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
168 RtlFreeUnicodeString(&GuidString);
169 }
170 return STATUS_UNSUCCESSFUL;
171 }
172
173 //---------------------------------------------------------------
174 // IPort interface functions
175 //
176
177 NTSTATUS
178 NTAPI
179 CPortTopology::GetDeviceProperty(
180 IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty,
181 IN ULONG BufferLength,
182 OUT PVOID PropertyBuffer,
183 OUT PULONG ReturnLength)
184 {
185 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
186
187 if (!m_bInitialized)
188 {
189 DPRINT("IPortTopology_fnNewRegistryKey called w/o initiazed\n");
190 return STATUS_UNSUCCESSFUL;
191 }
192
193 return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
194 }
195
196 NTSTATUS
197 NTAPI
198 CPortTopology::Init(
199 IN PDEVICE_OBJECT DeviceObject,
200 IN PIRP Irp,
201 IN PUNKNOWN UnknownMiniport,
202 IN PUNKNOWN UnknownAdapter OPTIONAL,
203 IN PRESOURCELIST ResourceList)
204 {
205 IMiniportTopology * Miniport;
206 NTSTATUS Status;
207
208 DPRINT("IPortTopology_fnInit entered This %p DeviceObject %p Irp %p UnknownMiniport %p UnknownAdapter %p ResourceList %p\n",
209 this, DeviceObject, Irp, UnknownMiniport, UnknownAdapter, ResourceList);
210
211 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
212
213 if (m_bInitialized)
214 {
215 DPRINT("IPortTopology_Init called again\n");
216 return STATUS_SUCCESS;
217 }
218
219 Status = UnknownMiniport->QueryInterface(IID_IMiniportTopology, (PVOID*)&Miniport);
220 if (!NT_SUCCESS(Status))
221 {
222 DPRINT("IPortTopology_Init called with invalid IMiniport adapter\n");
223 return STATUS_INVALID_PARAMETER;
224 }
225
226 // Initialize port object
227 m_pMiniport = Miniport;
228 m_pDeviceObject = DeviceObject;
229 m_bInitialized = TRUE;
230
231 // now initialize the miniport driver
232 Status = Miniport->Init(UnknownAdapter, ResourceList, this);
233 if (!NT_SUCCESS(Status))
234 {
235 DPRINT("IPortTopology_Init failed with %x\n", Status);
236 m_bInitialized = FALSE;
237 Miniport->Release();
238 return Status;
239 }
240
241 // get the miniport device descriptor
242 Status = Miniport->GetDescription(&m_pDescriptor);
243 if (!NT_SUCCESS(Status))
244 {
245 DPRINT("failed to get description\n");
246 Miniport->Release();
247 m_bInitialized = FALSE;
248 return Status;
249 }
250
251 // create the subdevice descriptor
252 Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor,
253 2,
254 InterfaceGuids,
255 0,
256 NULL,
257 2,
258 TopologyPropertySet,
259 0,
260 0,
261 0,
262 NULL,
263 0,
264 NULL,
265 m_pDescriptor);
266
267
268 DPRINT("IPortTopology_fnInit success\n");
269 if (NT_SUCCESS(Status))
270 {
271 // store for node property requests
272 m_SubDeviceDescriptor->UnknownMiniport = UnknownMiniport;
273 }
274
275 return STATUS_SUCCESS;
276 }
277
278
279 NTSTATUS
280 NTAPI
281 CPortTopology::NewRegistryKey(
282 OUT PREGISTRYKEY *OutRegistryKey,
283 IN PUNKNOWN OuterUnknown OPTIONAL,
284 IN ULONG RegistryKeyType,
285 IN ACCESS_MASK DesiredAccess,
286 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
287 IN ULONG CreateOptions OPTIONAL,
288 OUT PULONG Disposition OPTIONAL)
289 {
290 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
291
292 if (!m_bInitialized)
293 {
294 DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n");
295 return STATUS_UNSUCCESSFUL;
296 }
297 return PcNewRegistryKey(OutRegistryKey,
298 OuterUnknown,
299 RegistryKeyType,
300 DesiredAccess,
301 m_pDeviceObject,
302 (ISubdevice*)this,
303 ObjectAttributes,
304 CreateOptions,
305 Disposition);
306 }
307
308 //---------------------------------------------------------------
309 // ISubdevice interface
310 //
311
312 NTSTATUS
313 NTAPI
314 CPortTopology::NewIrpTarget(
315 OUT struct IIrpTarget **OutTarget,
316 IN PCWSTR Name,
317 IN PUNKNOWN Unknown,
318 IN POOL_TYPE PoolType,
319 IN PDEVICE_OBJECT DeviceObject,
320 IN PIRP Irp,
321 IN KSOBJECT_CREATE *CreateObject)
322 {
323 NTSTATUS Status;
324 IPortFilterTopology * Filter;
325
326 // is there already an instance of the filter
327 if (m_Filter)
328 {
329 // it is, let's return the result
330 *OutTarget = (IIrpTarget*)m_Filter;
331
332 // increment reference
333 m_Filter->AddRef();
334 return STATUS_SUCCESS;
335 }
336
337 // create new instance of filter
338 Status = NewPortFilterTopology(&Filter);
339 if (!NT_SUCCESS(Status))
340 {
341 // not enough memory
342 return Status;
343 }
344
345 // initialize the filter
346 Status = Filter->Init((IPortTopology*)this);
347 if (!NT_SUCCESS(Status))
348 {
349 // destroy filter
350 Filter->Release();
351 // return status
352 return Status;
353 }
354
355 // store result
356 *OutTarget = (IIrpTarget*)Filter;
357 // store for later re-use
358 m_Filter = Filter;
359 // return status
360 return Status;
361 }
362
363 NTSTATUS
364 NTAPI
365 CPortTopology::ReleaseChildren()
366 {
367 DPRINT("ISubDevice_fnReleaseChildren\n");
368
369 // release the filter
370 m_Filter->Release();
371
372 // release the miniport
373 DPRINT("Refs %u\n", m_pMiniport->Release());
374
375 return STATUS_SUCCESS;
376 }
377
378 NTSTATUS
379 NTAPI
380 CPortTopology::GetDescriptor(
381 IN SUBDEVICE_DESCRIPTOR ** Descriptor)
382 {
383 DPRINT("ISubDevice_GetDescriptor this %p Descp %p\n", this, m_SubDeviceDescriptor);
384 *Descriptor = m_SubDeviceDescriptor;
385 return STATUS_SUCCESS;
386 }
387
388 NTSTATUS
389 NTAPI
390 CPortTopology::DataRangeIntersection(
391 IN ULONG PinId,
392 IN PKSDATARANGE DataRange,
393 IN PKSDATARANGE MatchingDataRange,
394 IN ULONG OutputBufferLength,
395 OUT PVOID ResultantFormat OPTIONAL,
396 OUT PULONG ResultantFormatLength)
397 {
398 DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
399
400 if (m_pMiniport)
401 {
402 return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
403 }
404
405 return STATUS_UNSUCCESSFUL;
406 }
407
408 NTSTATUS
409 NTAPI
410 CPortTopology::PowerChangeNotify(
411 IN POWER_STATE PowerState)
412 {
413 if (m_pPowerNotify)
414 {
415 m_pPowerNotify->PowerChangeNotify(PowerState);
416 }
417
418 return STATUS_SUCCESS;
419 }
420
421 NTSTATUS
422 NTAPI
423 CPortTopology::PinCount(
424 IN ULONG PinId,
425 IN OUT PULONG FilterNecessary,
426 IN OUT PULONG FilterCurrent,
427 IN OUT PULONG FilterPossible,
428 IN OUT PULONG GlobalCurrent,
429 IN OUT PULONG GlobalPossible)
430 {
431 if (m_pPinCount)
432 {
433 m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
434 return STATUS_SUCCESS;
435 }
436
437 // FIXME
438 // scan filter descriptor
439
440 return STATUS_UNSUCCESSFUL;
441 }
442
443
444 NTSTATUS
445 NTAPI
446 PcCreatePinDispatch(
447 IN PDEVICE_OBJECT DeviceObject,
448 IN PIRP Irp)
449 {
450 NTSTATUS Status;
451 IIrpTarget *Filter;
452 IIrpTarget *Pin;
453 PKSOBJECT_CREATE_ITEM CreateItem;
454
455 // access the create item
456 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
457 // sanity check
458 PC_ASSERT(CreateItem);
459
460 DPRINT("PcCreatePinDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
461
462 Filter = (IIrpTarget*)CreateItem->Context;
463
464 // sanity checks
465 PC_ASSERT(Filter != NULL);
466 PC_ASSERT_IRQL(PASSIVE_LEVEL);
467
468
469 #if KS_IMPLEMENTED
470 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
471 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
472 {
473 DPRINT("PcCreatePinDispatch failed to reference device header\n");
474
475 FreeItem(Entry, TAG_PORTCLASS);
476 goto cleanup;
477 }
478 #endif
479
480 Status = Filter->NewIrpTarget(&Pin,
481 KSSTRING_Pin,
482 NULL,
483 NonPagedPool,
484 DeviceObject,
485 Irp,
486 NULL);
487
488 DPRINT("PcCreatePinDispatch Status %x\n", Status);
489
490 if (NT_SUCCESS(Status))
491 {
492 // create the dispatch object
493 // FIXME need create item for clock
494 Status = NewDispatchObject(Irp, Pin, 0, NULL);
495 DPRINT("Pin %p\n", Pin);
496 }
497
498 DPRINT("CreatePinWorkerRoutine completing irp %p\n", Irp);
499 // save status in irp
500 Irp->IoStatus.Status = Status;
501 Irp->IoStatus.Information = 0;
502 // complete the request
503 IoCompleteRequest(Irp, IO_NO_INCREMENT);
504 return Status;
505 }
506
507 NTSTATUS
508 NTAPI
509 PcCreateItemDispatch(
510 IN PDEVICE_OBJECT DeviceObject,
511 IN PIRP Irp)
512 {
513 NTSTATUS Status;
514 ISubdevice * SubDevice;
515 IIrpTarget *Filter;
516 PKSOBJECT_CREATE_ITEM CreateItem, PinCreateItem;
517
518 // access the create item
519 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
520
521 DPRINT("PcCreateItemDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
522
523 // get the subdevice
524 SubDevice = (ISubdevice*)CreateItem->Context;
525
526 // sanity checks
527 PC_ASSERT(SubDevice != NULL);
528
529
530 #if KS_IMPLEMENTED
531 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
532 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
533 {
534 DPRINT("PcCreateItemDispatch failed to reference device header\n");
535
536 FreeItem(Entry, TAG_PORTCLASS);
537 goto cleanup;
538 }
539 #endif
540
541 // get filter object
542 Status = SubDevice->NewIrpTarget(&Filter,
543 NULL,
544 NULL,
545 NonPagedPool,
546 DeviceObject,
547 Irp,
548 NULL);
549 if (!NT_SUCCESS(Status))
550 {
551 DPRINT("Failed to get filter object\n");
552 Irp->IoStatus.Status = Status;
553 IoCompleteRequest(Irp, IO_NO_INCREMENT);
554 return Status;
555 }
556
557 // allocate pin create item
558 PinCreateItem = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS);
559 if (!PinCreateItem)
560 {
561 // not enough memory
562 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
563 IoCompleteRequest(Irp, IO_NO_INCREMENT);
564 return STATUS_INSUFFICIENT_RESOURCES;
565 }
566
567 // initialize pin create item
568 PinCreateItem->Context = (PVOID)Filter;
569 PinCreateItem->Create = PcCreatePinDispatch;
570 RtlInitUnicodeString(&PinCreateItem->ObjectClass, KSSTRING_Pin);
571 // FIXME copy security descriptor
572
573 // now allocate a dispatch object
574 Status = NewDispatchObject(Irp, Filter, 1, PinCreateItem);
575
576 // complete request
577 Irp->IoStatus.Status = Status;
578 IoCompleteRequest(Irp, IO_NO_INCREMENT);
579
580 return STATUS_SUCCESS;
581 }
582
583
584 NTSTATUS
585 NewPortTopology(
586 OUT PPORT* OutPort)
587 {
588 CPortTopology * This;
589 NTSTATUS Status;
590
591 This= new(NonPagedPool, TAG_PORTCLASS) CPortTopology(NULL);
592 if (!This)
593 return STATUS_INSUFFICIENT_RESOURCES;
594
595 Status = This->QueryInterface(IID_IPort, (PVOID*)OutPort);
596
597 if (!NT_SUCCESS(Status))
598 {
599 delete This;
600 }
601
602 DPRINT("NewPortTopology %p Status %x\n", *OutPort, Status);
603 return Status;
604 }
605
606
607 PMINIPORTTOPOLOGY
608 GetTopologyMiniport(
609 PPORTTOPOLOGY Port)
610 {
611 CPortTopology * This = (CPortTopology*)Port;
612 return This->m_pMiniport;
613 }