1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/port_wavepci.cpp
5  * PURPOSE:         Wave PCI 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 CPortWavePci : public CUnknownImpl<IPortWavePci, IPortEvents, ISubdevice, IServiceSink>
18 {
19 public:
20     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
21 
22     IMP_IPortWavePci;
23     IMP_ISubdevice;
24     IMP_IPortEvents;
25     IMP_IServiceSink;
26     CPortWavePci(IUnknown *OuterUnknown){}
27     virtual ~CPortWavePci() {}
28 
29 protected:
30 
31     PMINIPORTWAVEPCI m_Miniport;
32     PDEVICE_OBJECT m_pDeviceObject;
33     PSERVICEGROUP m_ServiceGroup;
34     PPINCOUNT m_pPinCount;
35     PPOWERNOTIFY m_pPowerNotify;
36     PPCFILTER_DESCRIPTOR m_pDescriptor;
37     PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor;
38     IPortFilterWavePci * m_Filter;
39 
40     LIST_ENTRY m_EventList;
41     KSPIN_LOCK m_EventListLock;
42 
43     friend PDEVICE_OBJECT GetDeviceObjectFromPortWavePci(IPortWavePci* iface);
44     friend PMINIPORTWAVEPCI GetWavePciMiniport(PPORTWAVEPCI iface);
45 
46 };
47 
48 static GUID InterfaceGuids[3] =
49 {
50     {
51         /// KS_CATEGORY_AUDIO
52         0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
53     },
54     {
55         /// KSCATEGORY_RENDER
56         0x65E8773EL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
57     },
58     {
59         /// KSCATEGORY_CAPTURE
60         0x65E8773DL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
61     }
62 };
63 
64 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterWavePciTopologySet, TopologyPropertyHandler);
65 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterWavePciPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
66 
67 KSPROPERTY_SET WavePciPropertySet[] =
68 {
69     {
70         &KSPROPSETID_Topology,
71         sizeof(PortFilterWavePciTopologySet) / sizeof(KSPROPERTY_ITEM),
72         (const KSPROPERTY_ITEM*)&PortFilterWavePciTopologySet,
73         0,
74         NULL
75     },
76     {
77         &KSPROPSETID_Pin,
78         sizeof(PortFilterWavePciPinSet) / sizeof(KSPROPERTY_ITEM),
79         (const KSPROPERTY_ITEM*)&PortFilterWavePciPinSet,
80         0,
81         NULL
82     }
83 };
84 
85 
86 //---------------------------------------------------------------
87 // IPortEvents
88 //
89 
90 void
91 NTAPI
92 CPortWavePci::AddEventToEventList(
93     IN PKSEVENT_ENTRY EventEntry)
94 {
95     KIRQL OldIrql;
96 
97     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
98 
99     KeAcquireSpinLock(&m_EventListLock, &OldIrql);
100     InsertTailList(&m_EventList, &EventEntry->ListEntry);
101     KeReleaseSpinLock(&m_EventListLock, OldIrql);
102 }
103 
104 
105 
106 void
107 NTAPI
108 CPortWavePci::GenerateEventList(
109     IN  GUID* Set OPTIONAL,
110     IN  ULONG EventId,
111     IN  BOOL PinEvent,
112     IN  ULONG PinId,
113     IN  BOOL NodeEvent,
114     IN  ULONG NodeId)
115 {
116     UNIMPLEMENTED;
117 }
118 //---------------------------------------------------------------
119 // IServiceSink
120 //
121 
122 VOID
123 NTAPI
124 CPortWavePci::RequestService()
125 {
126     //DPRINT("IServiceSink_fnRequestService entered\n");
127     if (m_Miniport)
128     {
129         m_Miniport->Service();
130     }
131 }
132 
133 //---------------------------------------------------------------
134 // IPortWavePci
135 //
136 
137 NTSTATUS
138 NTAPI
139 CPortWavePci::QueryInterface(
140     IN  REFIID refiid,
141     OUT PVOID* Output)
142 {
143     UNICODE_STRING GuidString;
144 
145     DPRINT("IPortWavePci_fnQueryInterface entered\n");
146 
147     if (IsEqualGUIDAligned(refiid, IID_IPortWavePci) ||
148         IsEqualGUIDAligned(refiid, IID_IUnknown) ||
149         IsEqualGUIDAligned(refiid, IID_IPort))
150     {
151         *Output = PVOID(PPORTWAVEPCI(this));
152         PUNKNOWN(*Output)->AddRef();
153         return STATUS_SUCCESS;
154     }
155     else if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
156     {
157         *Output = PVOID(PSERVICESINK(this));
158         PUNKNOWN(*Output)->AddRef();
159         return STATUS_SUCCESS;
160     }
161     else if (IsEqualGUIDAligned(refiid, IID_IPortEvents))
162     {
163         *Output = PVOID(PPORTEVENTS(this));
164         PUNKNOWN(*Output)->AddRef();
165         return STATUS_SUCCESS;
166     }
167     else if (IsEqualGUIDAligned(refiid, IID_ISubdevice))
168     {
169         *Output = PVOID(PSUBDEVICE(this));
170         PUNKNOWN(*Output)->AddRef();
171         return STATUS_SUCCESS;
172     }
173     else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) ||
174              IsEqualGUIDAligned(refiid, IID_IDrmPort2))
175     {
176         return NewIDrmPort((PDRMPORT2*)Output);
177     }
178     else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion))
179     {
180         return NewPortClsVersion((PPORTCLSVERSION*)Output);
181     }
182     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice))
183     {
184         return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
185     }
186     else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection))
187     {
188         return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
189     }
190 
191     if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
192     {
193         DPRINT("IPortWavePci_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
194         RtlFreeUnicodeString(&GuidString);
195     }
196 
197     return STATUS_UNSUCCESSFUL;
198 }
199 
200 NTSTATUS
201 NTAPI
202 CPortWavePci::Init(
203     IN PDEVICE_OBJECT  DeviceObject,
204     IN PIRP  Irp,
205     IN PUNKNOWN  UnknownMiniport,
206     IN PUNKNOWN  UnknownAdapter  OPTIONAL,
207     IN PRESOURCELIST  ResourceList)
208 {
209     IMiniportWavePci * Miniport;
210     PSERVICEGROUP ServiceGroup = 0;
211     NTSTATUS Status;
212     PPINCOUNT PinCount;
213     PPOWERNOTIFY PowerNotify;
214 
215     DPRINT("IPortWavePci_fnInit entered with This %p, DeviceObject %p Irp %p UnknownMiniport %p, UnknownAdapter %p ResourceList %p\n",
216             this, DeviceObject, Irp, UnknownMiniport, UnknownAdapter, ResourceList);
217     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
218 
219     Status = UnknownMiniport->QueryInterface(IID_IMiniportWavePci, (PVOID*)&Miniport);
220     if (!NT_SUCCESS(Status))
221     {
222         DPRINT("IPortWavePci_fnInit called with invalid IMiniport adapter\n");
223         return STATUS_INVALID_PARAMETER;
224     }
225 
226     // Initialize port object
227     m_Miniport = Miniport;
228     m_pDeviceObject = DeviceObject;
229 
230     InitializeListHead(&m_EventList);
231     KeInitializeSpinLock(&m_EventListLock);
232 
233     // increment reference on miniport adapter
234     Miniport->AddRef();
235 
236     Status = Miniport->Init(UnknownAdapter, ResourceList, this, &ServiceGroup);
237     if (!NT_SUCCESS(Status))
238     {
239         DPRINT("IPortWavePci_fnInit failed with %x\n", Status);
240 
241         // release reference on miniport adapter
242         Miniport->Release();
243         return Status;
244     }
245 
246     // check if the miniport adapter provides a valid device descriptor
247     Status = Miniport->GetDescription(&m_pDescriptor);
248     if (!NT_SUCCESS(Status))
249     {
250         DPRINT("failed to get description\n");
251         Miniport->Release();
252         return Status;
253     }
254 
255    // create the subdevice descriptor
256     Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor,
257                                          3,
258                                          InterfaceGuids,
259                                          0,
260                                          NULL,
261                                          2,
262                                          WavePciPropertySet,
263                                          0,
264                                          0,
265                                          0,
266                                          NULL,
267                                          0,
268                                          NULL,
269                                          m_pDescriptor);
270 
271 
272     if (!NT_SUCCESS(Status))
273     {
274         DPRINT("PcCreateSubdeviceDescriptor failed with %x\n", Status);
275         Miniport->Release();
276         return Status;
277     }
278 
279     // did we get a service group
280    if (ServiceGroup)
281     {
282         // store service group in context
283         m_ServiceGroup = ServiceGroup;
284 
285         // add ourselves to service group which is called when miniport receives an isr
286         m_ServiceGroup->AddMember(PSERVICESINK(this));
287 
288         // increment reference on service group
289         m_ServiceGroup->AddRef();
290     }
291 
292     // store for node property requests
293     m_SubDeviceDescriptor->UnknownMiniport = UnknownMiniport;
294 
295     // check if it supports IPinCount interface
296     Status = UnknownMiniport->QueryInterface(IID_IPinCount, (PVOID*)&PinCount);
297     if (NT_SUCCESS(Status))
298     {
299         // store IPinCount interface
300         m_pPinCount = PinCount;
301     }
302 
303     // does the Miniport adapter support IPowerNotify interface*/
304     Status = UnknownMiniport->QueryInterface(IID_IPowerNotify, (PVOID*)&PowerNotify);
305     if (NT_SUCCESS(Status))
306     {
307         // store reference
308         m_pPowerNotify = PowerNotify;
309     }
310 
311     DPRINT("IPortWavePci_Init successfully initialized\n");
312     return STATUS_SUCCESS;
313 }
314 
315 NTSTATUS
316 NTAPI
317 CPortWavePci::NewRegistryKey(
318     OUT PREGISTRYKEY  *OutRegistryKey,
319     IN PUNKNOWN  OuterUnknown  OPTIONAL,
320     IN ULONG  RegistryKeyType,
321     IN ACCESS_MASK  DesiredAccess,
322     IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
323     IN ULONG  CreateOptions  OPTIONAL,
324     OUT PULONG  Disposition  OPTIONAL)
325 {
326     DPRINT("IPortWavePci_fnNewRegistryKey entered\n");
327     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
328 
329     return PcNewRegistryKey(OutRegistryKey,
330                             OuterUnknown,
331                             RegistryKeyType,
332                             DesiredAccess,
333                             m_pDeviceObject,
334                             (ISubdevice*)this,
335                             ObjectAttributes,
336                             CreateOptions,
337                             Disposition);
338 }
339 
340 NTSTATUS
341 NTAPI
342 CPortWavePci::GetDeviceProperty(
343     IN DEVICE_REGISTRY_PROPERTY  DeviceRegistryProperty,
344     IN ULONG  BufferLength,
345     OUT PVOID  PropertyBuffer,
346     OUT PULONG  ReturnLength)
347 {
348     DPRINT("IPortWavePci_fnGetDeviceProperty entered\n");
349     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
350 
351     return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
352 }
353 
354 NTSTATUS
355 NTAPI
356 CPortWavePci::NewMasterDmaChannel(
357     OUT PDMACHANNEL *DmaChannel,
358     IN PUNKNOWN OuterUnknown OPTIONAL,
359     IN POOL_TYPE PoolType,
360     IN PRESOURCELIST ResourceList OPTIONAL,
361     IN BOOLEAN ScatterGather,
362     IN BOOLEAN Dma32BitAddresses,
363     IN BOOLEAN Dma64BitAddresses,
364     IN BOOLEAN IgnoreCount,
365     IN DMA_WIDTH DmaWidth,
366     IN DMA_SPEED DmaSpeed,
367     IN ULONG  MaximumLength,
368     IN ULONG  DmaPort)
369 {
370     NTSTATUS Status;
371     DEVICE_DESCRIPTION DeviceDescription;
372 
373     DPRINT("IPortWavePci_fnNewMasterDmaChannel This %p entered\n", this);
374     PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
375 
376     Status = PcDmaMasterDescription(ResourceList, ScatterGather, Dma32BitAddresses, IgnoreCount, Dma64BitAddresses, DmaWidth, DmaSpeed, MaximumLength, DmaPort, &DeviceDescription);
377     if (NT_SUCCESS(Status))
378     {
379         return PcNewDmaChannel(DmaChannel, OuterUnknown, PoolType, &DeviceDescription, m_pDeviceObject);
380     }
381 
382     return Status;
383 }
384 
385 VOID
386 NTAPI
387 CPortWavePci::Notify(
388     IN  PSERVICEGROUP ServiceGroup)
389 {
390     //DPRINT("IPortWavePci_fnNotify entered %p, ServiceGroup %p\n", This, ServiceGroup);
391 
392     if (ServiceGroup)
393     {
394         ServiceGroup->RequestService ();
395     }
396 }
397 
398 //---------------------------------------------------------------
399 // ISubdevice interface
400 //
401 
402 NTSTATUS
403 NTAPI
404 CPortWavePci::NewIrpTarget(
405     OUT struct IIrpTarget **OutTarget,
406     IN PCWSTR Name,
407     IN PUNKNOWN Unknown,
408     IN POOL_TYPE PoolType,
409     IN PDEVICE_OBJECT DeviceObject,
410     IN PIRP Irp,
411     IN KSOBJECT_CREATE *CreateObject)
412 {
413     NTSTATUS Status;
414     IPortFilterWavePci * Filter;
415 
416     DPRINT("ISubDevice_NewIrpTarget this %p\n", this);
417 
418     if (m_Filter)
419     {
420         *OutTarget = (IIrpTarget*)m_Filter;
421         return STATUS_SUCCESS;
422     }
423 
424     Status = NewPortFilterWavePci(&Filter);
425     if (!NT_SUCCESS(Status))
426     {
427         return Status;
428     }
429 
430     Status = Filter->Init((IPortWavePci*)this);
431     if (!NT_SUCCESS(Status))
432     {
433         Filter->Release();
434         return Status;
435     }
436 
437     *OutTarget = (IIrpTarget*)Filter;
438     m_Filter = Filter;
439     return Status;
440 }
441 
442 NTSTATUS
443 NTAPI
444 CPortWavePci::ReleaseChildren()
445 {
446     UNIMPLEMENTED;
447     return STATUS_UNSUCCESSFUL;
448 }
449 
450 NTSTATUS
451 NTAPI
452 CPortWavePci::GetDescriptor(
453     IN SUBDEVICE_DESCRIPTOR ** Descriptor)
454 {
455     DPRINT("ISubDevice_GetDescriptor this %p\n", this);
456     *Descriptor = m_SubDeviceDescriptor;
457     return STATUS_SUCCESS;
458 }
459 
460 NTSTATUS
461 NTAPI
462 CPortWavePci::DataRangeIntersection(
463     IN  ULONG PinId,
464     IN  PKSDATARANGE DataRange,
465     IN  PKSDATARANGE MatchingDataRange,
466     IN  ULONG OutputBufferLength,
467     OUT PVOID ResultantFormat OPTIONAL,
468     OUT PULONG ResultantFormatLength)
469 {
470     DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
471 
472     if (m_Miniport)
473     {
474         return m_Miniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
475     }
476 
477     return STATUS_UNSUCCESSFUL;
478 }
479 
480 NTSTATUS
481 NTAPI
482 CPortWavePci::PowerChangeNotify(
483     IN POWER_STATE PowerState)
484 {
485     if (m_pPowerNotify)
486     {
487         m_pPowerNotify->PowerChangeNotify(PowerState);
488     }
489 
490     return STATUS_SUCCESS;
491 }
492 
493 NTSTATUS
494 NTAPI
495 CPortWavePci::PinCount(
496     IN ULONG  PinId,
497     IN OUT PULONG  FilterNecessary,
498     IN OUT PULONG  FilterCurrent,
499     IN OUT PULONG  FilterPossible,
500     IN OUT PULONG  GlobalCurrent,
501     IN OUT PULONG  GlobalPossible)
502 {
503     if (m_pPinCount)
504     {
505        m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
506        return STATUS_SUCCESS;
507     }
508 
509     // FIXME
510     // scan filter descriptor
511 
512     return STATUS_UNSUCCESSFUL;
513 }
514 
515 
516 NTSTATUS
517 NewPortWavePci(
518     OUT PPORT* OutPort)
519 {
520     CPortWavePci * Port;
521     NTSTATUS Status;
522 
523     Port = new(NonPagedPool, TAG_PORTCLASS) CPortWavePci(NULL);
524     if (!Port)
525         return STATUS_INSUFFICIENT_RESOURCES;
526 
527     Status = Port->QueryInterface(IID_IPort, (PVOID*)OutPort);
528 
529     if (!NT_SUCCESS(Status))
530     {
531         delete Port;
532     }
533 
534     DPRINT("NewPortWavePci %p Status %u\n", Port, Status);
535     return Status;
536 
537 }
538 
539 
540 PDEVICE_OBJECT
541 GetDeviceObjectFromPortWavePci(
542     IPortWavePci* iface)
543 {
544     CPortWavePci * This = (CPortWavePci*)iface;
545     return This->m_pDeviceObject;
546 }
547 
548 PMINIPORTWAVEPCI
549 GetWavePciMiniport(
550     PPORTWAVEPCI iface)
551 {
552     CPortWavePci * This = (CPortWavePci*)iface;
553     return This->m_Miniport;
554 }
555