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