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