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