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