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