- Implement CPortFilterWaveCyclic::FastDeviceIoControl
[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 return STATUS_SUCCESS;
277 }
278
279
280 NTSTATUS
281 NTAPI
282 CPortTopology::NewRegistryKey(
283 OUT PREGISTRYKEY *OutRegistryKey,
284 IN PUNKNOWN OuterUnknown OPTIONAL,
285 IN ULONG RegistryKeyType,
286 IN ACCESS_MASK DesiredAccess,
287 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
288 IN ULONG CreateOptions OPTIONAL,
289 OUT PULONG Disposition OPTIONAL)
290 {
291 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
292
293 if (!m_bInitialized)
294 {
295 DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n");
296 return STATUS_UNSUCCESSFUL;
297 }
298 return PcNewRegistryKey(OutRegistryKey,
299 OuterUnknown,
300 RegistryKeyType,
301 DesiredAccess,
302 m_pDeviceObject,
303 NULL,//FIXME
304 ObjectAttributes,
305 CreateOptions,
306 Disposition);
307 }
308
309 //---------------------------------------------------------------
310 // ISubdevice interface
311 //
312
313 NTSTATUS
314 NTAPI
315 CPortTopology::NewIrpTarget(
316 OUT struct IIrpTarget **OutTarget,
317 IN WCHAR * Name,
318 IN PUNKNOWN Unknown,
319 IN POOL_TYPE PoolType,
320 IN PDEVICE_OBJECT DeviceObject,
321 IN PIRP Irp,
322 IN KSOBJECT_CREATE *CreateObject)
323 {
324 NTSTATUS Status;
325 IPortFilterTopology * Filter;
326
327 // is there already an instance of the filter
328 if (m_Filter)
329 {
330 // it is, let's return the result
331 *OutTarget = (IIrpTarget*)m_Filter;
332
333 // increment reference
334 m_Filter->AddRef();
335 return STATUS_SUCCESS;
336 }
337
338 // create new instance of filter
339 Status = NewPortFilterTopology(&Filter);
340 if (!NT_SUCCESS(Status))
341 {
342 // not enough memory
343 return Status;
344 }
345
346 // initialize the filter
347 Status = Filter->Init((IPortTopology*)this);
348 if (!NT_SUCCESS(Status))
349 {
350 // destroy filter
351 Filter->Release();
352 // return status
353 return Status;
354 }
355
356 // store result
357 *OutTarget = (IIrpTarget*)Filter;
358 // store for later re-use
359 m_Filter = Filter;
360 // return status
361 return Status;
362 }
363
364 NTSTATUS
365 NTAPI
366 CPortTopology::ReleaseChildren()
367 {
368 DPRINT1("ISubDevice_fnReleaseChildren\n");
369
370 // release the filter
371 m_Filter->Release();
372
373 // release the miniport
374 DPRINT("Refs %u\n", m_pMiniport->Release());
375
376 return STATUS_SUCCESS;
377 }
378
379 NTSTATUS
380 NTAPI
381 CPortTopology::GetDescriptor(
382 IN SUBDEVICE_DESCRIPTOR ** Descriptor)
383 {
384 DPRINT("ISubDevice_GetDescriptor this %p Descp %p\n", this, m_SubDeviceDescriptor);
385 *Descriptor = m_SubDeviceDescriptor;
386 return STATUS_SUCCESS;
387 }
388
389 NTSTATUS
390 NTAPI
391 CPortTopology::DataRangeIntersection(
392 IN ULONG PinId,
393 IN PKSDATARANGE DataRange,
394 IN PKSDATARANGE MatchingDataRange,
395 IN ULONG OutputBufferLength,
396 OUT PVOID ResultantFormat OPTIONAL,
397 OUT PULONG ResultantFormatLength)
398 {
399 DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
400
401 if (m_pMiniport)
402 {
403 return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
404 }
405
406 return STATUS_UNSUCCESSFUL;
407 }
408
409 NTSTATUS
410 NTAPI
411 CPortTopology::PowerChangeNotify(
412 IN POWER_STATE PowerState)
413 {
414 if (m_pPowerNotify)
415 {
416 m_pPowerNotify->PowerChangeNotify(PowerState);
417 }
418
419 return STATUS_SUCCESS;
420 }
421
422 NTSTATUS
423 NTAPI
424 CPortTopology::PinCount(
425 IN ULONG PinId,
426 IN OUT PULONG FilterNecessary,
427 IN OUT PULONG FilterCurrent,
428 IN OUT PULONG FilterPossible,
429 IN OUT PULONG GlobalCurrent,
430 IN OUT PULONG GlobalPossible)
431 {
432 if (m_pPinCount)
433 {
434 m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
435 return STATUS_SUCCESS;
436 }
437
438 // FIXME
439 // scan filter descriptor
440
441 return STATUS_UNSUCCESSFUL;
442 }
443
444
445 VOID
446 NTAPI
447 CreatePinWorkerRoutine(
448 IN PDEVICE_OBJECT DeviceObject,
449 IN PVOID Context)
450 {
451 NTSTATUS Status;
452 IIrpTarget *Pin;
453 PPIN_WORKER_CONTEXT WorkerContext = (PPIN_WORKER_CONTEXT)Context;
454
455 DPRINT("CreatePinWorkerRoutine called\n");
456 // create the pin
457 Status = WorkerContext->Filter->NewIrpTarget(&Pin,
458 NULL,
459 NULL,
460 NonPagedPool,
461 DeviceObject,
462 WorkerContext->Irp,
463 NULL);
464
465 DPRINT1("CreatePinWorkerRoutine Status %x\n", Status);
466
467 if (NT_SUCCESS(Status))
468 {
469 // create the dispatch object
470 // FIXME need create item for clock
471 Status = NewDispatchObject(WorkerContext->Irp, Pin, 0, NULL);
472 DPRINT("Pin %p\n", Pin);
473 }
474
475 DPRINT("CreatePinWorkerRoutine completing irp %p\n", WorkerContext->Irp);
476 // save status in irp
477 WorkerContext->Irp->IoStatus.Status = Status;
478 WorkerContext->Irp->IoStatus.Information = 0;
479 // complete the request
480 IoCompleteRequest(WorkerContext->Irp, IO_SOUND_INCREMENT);
481 // free allocated work item
482 IoFreeWorkItem(WorkerContext->WorkItem);
483 // free context
484 FreeItem(WorkerContext, TAG_PORTCLASS);
485 }
486
487 NTSTATUS
488 NTAPI
489 PcCreatePinDispatch(
490 IN PDEVICE_OBJECT DeviceObject,
491 IN PIRP Irp)
492 {
493 IIrpTarget *Filter;
494 PKSOBJECT_CREATE_ITEM CreateItem;
495 PPIN_WORKER_CONTEXT Context;
496
497 // access the create item
498 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
499 // sanity check
500 PC_ASSERT(CreateItem);
501
502 DPRINT1("PcCreatePinDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
503
504 Filter = (IIrpTarget*)CreateItem->Context;
505
506 // sanity checks
507 PC_ASSERT(Filter != NULL);
508
509
510 #if KS_IMPLEMENTED
511 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
512 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
513 {
514 DPRINT1("PcCreatePinDispatch failed to reference device header\n");
515
516 FreeItem(Entry, TAG_PORTCLASS);
517 goto cleanup;
518 }
519 #endif
520
521 // new pins are instantiated at passive level,
522 // so allocate a work item and context for it
523
524
525 Context = (PPIN_WORKER_CONTEXT)AllocateItem(NonPagedPool, sizeof(PIN_WORKER_CONTEXT), TAG_PORTCLASS);
526 if (!Context)
527 {
528 DPRINT("Failed to allocate worker context\n");
529 Irp->IoStatus.Information = 0;
530 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
531 IoCompleteRequest(Irp, IO_NO_INCREMENT);
532 return STATUS_INSUFFICIENT_RESOURCES;
533 }
534
535 // allocate work item
536 Context->WorkItem = IoAllocateWorkItem(DeviceObject);
537 if (!Context->WorkItem)
538 {
539 DPRINT("Failed to allocate workitem\n");
540 FreeItem(Context, TAG_PORTCLASS);
541 Irp->IoStatus.Information = 0;
542 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
543 IoCompleteRequest(Irp, IO_NO_INCREMENT);
544 return STATUS_INSUFFICIENT_RESOURCES;
545 }
546
547 Context->Filter = Filter;
548 Context->Irp = Irp;
549
550 DPRINT("Queueing IRP %p Irql %u\n", Irp, KeGetCurrentIrql());
551 Irp->IoStatus.Information = 0;
552 Irp->IoStatus.Status = STATUS_PENDING;
553 IoMarkIrpPending(Irp);
554 IoQueueWorkItem(Context->WorkItem, CreatePinWorkerRoutine, DelayedWorkQueue, (PVOID)Context);
555 return STATUS_PENDING;
556 }
557
558
559
560 NTSTATUS
561 NTAPI
562 PcCreateItemDispatch(
563 IN PDEVICE_OBJECT DeviceObject,
564 IN PIRP Irp)
565 {
566 NTSTATUS Status;
567 ISubdevice * SubDevice;
568 IIrpTarget *Filter;
569 PKSOBJECT_CREATE_ITEM CreateItem, PinCreateItem;
570
571 // access the create item
572 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
573
574 DPRINT1("PcCreateItemDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer);
575
576 // get the subdevice
577 SubDevice = (ISubdevice*)CreateItem->Context;
578
579 // sanity checks
580 PC_ASSERT(SubDevice != NULL);
581
582 #if KS_IMPLEMENTED
583 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader);
584 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
585 {
586 DPRINT1("PcCreateItemDispatch failed to reference device header\n");
587
588 FreeItem(Entry, TAG_PORTCLASS);
589 goto cleanup;
590 }
591 #endif
592
593 // get filter object
594 Status = SubDevice->NewIrpTarget(&Filter,
595 NULL,
596 NULL,
597 NonPagedPool,
598 DeviceObject,
599 Irp,
600 NULL);
601 if (!NT_SUCCESS(Status))
602 {
603 DPRINT1("Failed to get filter object\n");
604 Irp->IoStatus.Status = Status;
605 IoCompleteRequest(Irp, IO_NO_INCREMENT);
606 return Status;
607 }
608
609 // allocate pin create item
610 PinCreateItem = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS);
611 if (!PinCreateItem)
612 {
613 // not enough memory
614 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
615 IoCompleteRequest(Irp, IO_NO_INCREMENT);
616 return STATUS_INSUFFICIENT_RESOURCES;
617 }
618
619 // initialize pin create item
620 PinCreateItem->Context = (PVOID)Filter;
621 PinCreateItem->Create = PcCreatePinDispatch;
622 RtlInitUnicodeString(&PinCreateItem->ObjectClass, KSSTRING_Pin);
623 // FIXME copy security descriptor
624
625 // now allocate a dispatch object
626 Status = NewDispatchObject(Irp, Filter, 1, PinCreateItem);
627
628 // complete request
629 Irp->IoStatus.Status = Status;
630 IoCompleteRequest(Irp, IO_NO_INCREMENT);
631
632 return STATUS_SUCCESS;
633 }
634
635
636 NTSTATUS
637 NewPortTopology(
638 OUT PPORT* OutPort)
639 {
640 CPortTopology * This;
641 NTSTATUS Status;
642
643 This= new(NonPagedPool, TAG_PORTCLASS) CPortTopology(NULL);
644 if (!This)
645 return STATUS_INSUFFICIENT_RESOURCES;
646
647 Status = This->QueryInterface(IID_IPort, (PVOID*)OutPort);
648
649 if (!NT_SUCCESS(Status))
650 {
651 delete This;
652 }
653
654 DPRINT("NewPortTopology %p Status %x\n", *OutPort, Status);
655 return Status;
656 }
657
658
659 PMINIPORTTOPOLOGY
660 GetTopologyMiniport(
661 PPORTTOPOLOGY Port)
662 {
663 CPortTopology * This = (CPortTopology*)Port;
664 return This->m_pMiniport;
665 }