1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp
5  * PURPOSE:         WaveCyclic IRP Audio Pin
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 CPortPinWaveCyclic : public CUnknownImpl<IPortPinWaveCyclic, IServiceSink>
18 {
19 public:
20     inline
21     PVOID
22     operator new(
23         size_t Size,
24         POOL_TYPE PoolType,
25         ULONG Tag)
26     {
27         return ExAllocatePoolWithTag(PoolType, Size, Tag);
28     }
29 
30     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
31 
32     IMP_IPortPinWaveCyclic;
33     IMP_IServiceSink;
34     CPortPinWaveCyclic(IUnknown *OuterUnknown) :
35         m_Port(nullptr),
36         m_Filter(nullptr),
37         m_KsPinDescriptor(nullptr),
38         m_Miniport(nullptr),
39         m_ServiceGroup(nullptr),
40         m_DmaChannel(nullptr),
41         m_Stream(nullptr),
42         m_State(KSSTATE_STOP),
43         m_Format(nullptr),
44         m_ConnectDetails(nullptr),
45         m_CommonBuffer(nullptr),
46         m_CommonBufferSize(0),
47         m_CommonBufferOffset(0),
48         m_IrpQueue(nullptr),
49         m_FrameSize(0),
50         m_Capture(FALSE),
51         m_TotalPackets(0),
52         m_StopCount(0),
53         m_Position({0}),
54         m_AllocatorFraming({{0}}),
55         m_Descriptor(nullptr),
56         m_EventListLock(0),
57         m_EventList({nullptr}),
58         m_ResetState(KSRESET_BEGIN),
59         m_Delay(0)
60     {
61     }
62     virtual ~CPortPinWaveCyclic(){}
63 
64 protected:
65 
66     VOID UpdateCommonBuffer(ULONG Position, ULONG MaxTransferCount);
67     VOID UpdateCommonBufferOverlap(ULONG Position, ULONG MaxTransferCount);
68     VOID GeneratePositionEvents(IN ULONGLONG OldOffset, IN ULONGLONG NewOffset);
69 
70     friend NTSTATUS NTAPI PinWaveCyclicState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
71     friend NTSTATUS NTAPI PinWaveCyclicDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
72     friend NTSTATUS NTAPI PinWaveCyclicAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
73     friend NTSTATUS NTAPI PinWaveCyclicAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
74     friend NTSTATUS NTAPI PinWaveCyclicAddEndOfStreamEvent(IN PIRP Irp, IN PKSEVENTDATA EventData, IN PKSEVENT_ENTRY EventEntry);
75     friend NTSTATUS NTAPI PinWaveCyclicAddLoopedStreamEvent(IN PIRP Irp, IN PKSEVENTDATA  EventData, IN PKSEVENT_ENTRY EventEntry);
76     friend VOID CALLBACK PinSetStateWorkerRoutine(IN PDEVICE_OBJECT  DeviceObject, IN PVOID  Context);
77 
78     IPortWaveCyclic * m_Port;
79     IPortFilterWaveCyclic * m_Filter;
80     KSPIN_DESCRIPTOR * m_KsPinDescriptor;
81     PMINIPORTWAVECYCLIC m_Miniport;
82     PSERVICEGROUP m_ServiceGroup;
83     PDMACHANNEL m_DmaChannel;
84     PMINIPORTWAVECYCLICSTREAM m_Stream;
85     KSSTATE m_State;
86     PKSDATAFORMAT m_Format;
87     PKSPIN_CONNECT m_ConnectDetails;
88 
89     PVOID m_CommonBuffer;
90     ULONG m_CommonBufferSize;
91     ULONG m_CommonBufferOffset;
92 
93     IIrpQueue * m_IrpQueue;
94 
95     ULONG m_FrameSize;
96     BOOL m_Capture;
97 
98     ULONG m_TotalPackets;
99     ULONG m_StopCount;
100     KSAUDIO_POSITION m_Position;
101     KSALLOCATOR_FRAMING m_AllocatorFraming;
102     PSUBDEVICE_DESCRIPTOR m_Descriptor;
103 
104     KSPIN_LOCK m_EventListLock;
105     LIST_ENTRY m_EventList;
106 
107     KSRESET m_ResetState;
108 
109     ULONG m_Delay;
110 };
111 
112 
113 typedef struct
114 {
115     ULONG bLoopedStreaming;
116     ULONGLONG Position;
117 }LOOPEDSTREAMING_EVENT_CONTEXT, *PLOOPEDSTREAMING_EVENT_CONTEXT;
118 
119 typedef struct
120 {
121     ULONG bLoopedStreaming;
122 }ENDOFSTREAM_EVENT_CONTEXT, *PENDOFSTREAM_EVENT_CONTEXT;
123 
124 
125 
126 NTSTATUS NTAPI PinWaveCyclicState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
127 NTSTATUS NTAPI PinWaveCyclicDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
128 NTSTATUS NTAPI PinWaveCyclicAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
129 NTSTATUS NTAPI PinWaveCyclicAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
130 NTSTATUS NTAPI PinWaveCyclicAddEndOfStreamEvent(IN PIRP Irp, IN PKSEVENTDATA  EventData, IN PKSEVENT_ENTRY  EventEntry);
131 NTSTATUS NTAPI PinWaveCyclicAddLoopedStreamEvent(IN PIRP Irp, IN PKSEVENTDATA  EventData, IN PKSEVENT_ENTRY EventEntry);
132 NTSTATUS NTAPI PinWaveCyclicDRMHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
133 
134 
135 DEFINE_KSPROPERTY_CONNECTIONSET(PinWaveCyclicConnectionSet, PinWaveCyclicState, PinWaveCyclicDataFormat, PinWaveCyclicAllocatorFraming);
136 DEFINE_KSPROPERTY_AUDIOSET(PinWaveCyclicAudioSet, PinWaveCyclicAudioPosition);
137 DEFINE_KSPROPERTY_DRMSET(PinWaveCyclicDRMSet, PinWaveCyclicDRMHandler);
138 
139 KSEVENT_ITEM PinWaveCyclicConnectionEventSet =
140 {
141     KSEVENT_CONNECTION_ENDOFSTREAM,
142     sizeof(KSEVENTDATA),
143     sizeof(ENDOFSTREAM_EVENT_CONTEXT),
144     PinWaveCyclicAddEndOfStreamEvent,
145     0,
146     0
147 };
148 
149 KSEVENT_ITEM PinWaveCyclicStreamingEventSet =
150 {
151     KSEVENT_LOOPEDSTREAMING_POSITION,
152     sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA),
153     sizeof(LOOPEDSTREAMING_EVENT_CONTEXT),
154     PinWaveCyclicAddLoopedStreamEvent,
155     0,
156     0
157 };
158 
159 
160 KSPROPERTY_SET PinWaveCyclicPropertySet[] =
161 {
162     {
163         &KSPROPSETID_Connection,
164         sizeof(PinWaveCyclicConnectionSet) / sizeof(KSPROPERTY_ITEM),
165         (const KSPROPERTY_ITEM*)&PinWaveCyclicConnectionSet,
166         0,
167         NULL
168     },
169     {
170         &KSPROPSETID_Audio,
171         sizeof(PinWaveCyclicAudioSet) / sizeof(KSPROPERTY_ITEM),
172         (const KSPROPERTY_ITEM*)&PinWaveCyclicAudioSet,
173         0,
174         NULL
175     },
176     {
177         &KSPROPSETID_DrmAudioStream,
178         sizeof(PinWaveCyclicDRMSet) / sizeof(KSPROPERTY_ITEM),
179         (const KSPROPERTY_ITEM*)&PinWaveCyclicDRMSet,
180         0,
181         NULL
182     }
183 };
184 
185 KSEVENT_SET PinWaveCyclicEventSet[] =
186 {
187     {
188         &KSEVENTSETID_LoopedStreaming,
189         sizeof(PinWaveCyclicStreamingEventSet) / sizeof(KSEVENT_ITEM),
190         (const KSEVENT_ITEM*)&PinWaveCyclicStreamingEventSet
191     },
192     {
193         &KSEVENTSETID_Connection,
194         sizeof(PinWaveCyclicConnectionEventSet) / sizeof(KSEVENT_ITEM),
195         (const KSEVENT_ITEM*)&PinWaveCyclicConnectionEventSet
196     }
197 };
198 
199 
200 //==================================================================================================================================
201 
202 NTSTATUS
203 NTAPI
204 CPortPinWaveCyclic::QueryInterface(
205     IN  REFIID refiid,
206     OUT PVOID* Output)
207 {
208     DPRINT("IServiceSink_fnQueryInterface entered\n");
209 
210     if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) ||
211         IsEqualGUIDAligned(refiid, IID_IUnknown))
212     {
213         *Output = PVOID(PUNKNOWN((IIrpTarget*)this));
214         PUNKNOWN(*Output)->AddRef();
215         return STATUS_SUCCESS;
216     }
217 
218     if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
219     {
220         *Output = PVOID(PUNKNOWN(PSERVICESINK(this)));
221         PUNKNOWN(*Output)->AddRef();
222         return STATUS_SUCCESS;
223     }
224 
225     return STATUS_UNSUCCESSFUL;
226 }
227 
228 NTSTATUS
229 NTAPI
230 PinWaveCyclicDRMHandler(
231     IN PIRP Irp,
232     IN PKSIDENTIFIER Request,
233     IN OUT PVOID Data)
234 {
235     DPRINT1("PinWaveCyclicDRMHandler\n");
236     ASSERT(0);
237     return STATUS_INVALID_PARAMETER;
238 }
239 
240 
241 NTSTATUS
242 NTAPI
243 PinWaveCyclicAddEndOfStreamEvent(
244     IN PIRP Irp,
245     IN PKSEVENTDATA  EventData,
246     IN PKSEVENT_ENTRY EventEntry)
247 {
248     PENDOFSTREAM_EVENT_CONTEXT Entry;
249     PSUBDEVICE_DESCRIPTOR Descriptor;
250     CPortPinWaveCyclic *Pin;
251 
252     // get sub device descriptor
253     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
254 
255     // sanity check
256     PC_ASSERT(Descriptor);
257     PC_ASSERT(Descriptor->PortPin);
258     PC_ASSERT_IRQL(DISPATCH_LEVEL);
259 
260     // cast to pin impl
261     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
262 
263      // get extra size
264     Entry = (PENDOFSTREAM_EVENT_CONTEXT)(EventEntry + 1);
265 
266     // not a looped event
267     Entry->bLoopedStreaming = FALSE;
268 
269     // insert item
270     (void)ExInterlockedInsertTailList(&Pin->m_EventList, &EventEntry->ListEntry, &Pin->m_EventListLock);
271 
272     // done
273     return STATUS_SUCCESS;
274 }
275 
276 NTSTATUS
277 NTAPI
278 PinWaveCyclicAddLoopedStreamEvent(
279     IN PIRP Irp,
280     IN PKSEVENTDATA  EventData,
281     IN PKSEVENT_ENTRY EventEntry)
282 {
283     PLOOPEDSTREAMING_POSITION_EVENT_DATA Data;
284     PLOOPEDSTREAMING_EVENT_CONTEXT Entry;
285     PSUBDEVICE_DESCRIPTOR Descriptor;
286     CPortPinWaveCyclic *Pin;
287 
288     // get sub device descriptor
289     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSEVENT_ITEM_IRP_STORAGE(Irp);
290 
291     // sanity check
292     PC_ASSERT(Descriptor);
293     PC_ASSERT(Descriptor->PortPin);
294     PC_ASSERT_IRQL(DISPATCH_LEVEL);
295 
296     // cast to pin impl
297     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
298 
299     // cast to looped event
300     Data = (PLOOPEDSTREAMING_POSITION_EVENT_DATA)EventData;
301 
302     // get extra size
303     Entry = (PLOOPEDSTREAMING_EVENT_CONTEXT)(EventEntry + 1);
304 
305     Entry->bLoopedStreaming = TRUE;
306     Entry->Position = Data->Position;
307 
308     DPRINT1("Added event\n");
309 
310     // insert item
311     (void)ExInterlockedInsertTailList(&Pin->m_EventList, &EventEntry->ListEntry, &Pin->m_EventListLock);
312 
313     // done
314     return STATUS_SUCCESS;
315 }
316 
317 NTSTATUS
318 NTAPI
319 PinWaveCyclicAllocatorFraming(
320     IN PIRP Irp,
321     IN PKSIDENTIFIER Request,
322     IN OUT PVOID Data)
323 {
324     CPortPinWaveCyclic *Pin;
325     PSUBDEVICE_DESCRIPTOR Descriptor;
326 
327     // get sub device descriptor
328     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSEVENT_ITEM_IRP_STORAGE(Irp);
329 
330     // sanity check
331     PC_ASSERT(Descriptor);
332     PC_ASSERT(Descriptor->PortPin);
333     PC_ASSERT_IRQL(DISPATCH_LEVEL);
334 
335     // cast to pin impl
336     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
337 
338 
339     if (Request->Flags & KSPROPERTY_TYPE_GET)
340     {
341         // copy pin framing
342         RtlMoveMemory(Data, &Pin->m_AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
343 
344         Irp->IoStatus.Information = sizeof(KSALLOCATOR_FRAMING);
345         return STATUS_SUCCESS;
346     }
347 
348     // not supported
349     return STATUS_NOT_SUPPORTED;
350 }
351 
352 NTSTATUS
353 NTAPI
354 PinWaveCyclicAudioPosition(
355     IN PIRP Irp,
356     IN PKSIDENTIFIER Request,
357     IN OUT PVOID Data)
358 {
359     CPortPinWaveCyclic *Pin;
360     PSUBDEVICE_DESCRIPTOR Descriptor;
361     PKSAUDIO_POSITION Position;
362 
363     // get sub device descriptor
364     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
365 
366     // sanity check
367     PC_ASSERT(Descriptor);
368     PC_ASSERT(Descriptor->PortPin);
369     PC_ASSERT_IRQL(DISPATCH_LEVEL);
370 
371     // cast to pin impl
372     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
373 
374     //sanity check
375     PC_ASSERT(Pin->m_Stream);
376 
377     if (Request->Flags & KSPROPERTY_TYPE_GET)
378     {
379         // FIXME non multithreading-safe
380         // copy audio position
381 
382         Position = (PKSAUDIO_POSITION)Data;
383 
384         if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_STREAMING)
385         {
386             RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION));
387             DPRINT("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset);
388         }
389         else if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
390         {
391             Position->PlayOffset = Pin->m_Position.PlayOffset;
392             Position->WriteOffset = (ULONGLONG)Pin->m_IrpQueue->GetCurrentIrpOffset();
393             DPRINT("Play %lu Write %lu\n", Position->PlayOffset, Position->WriteOffset);
394         }
395 
396         Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION);
397         return STATUS_SUCCESS;
398     }
399 
400     // not supported
401     return STATUS_NOT_SUPPORTED;
402 }
403 
404 typedef struct
405 {
406     CPortPinWaveCyclic *Pin;
407     KSSTATE NewState;
408     PIO_WORKITEM WorkItem;
409     PIRP Irp;
410 
411 }SETPIN_CONTEXT, *PSETPIN_CONTEXT;
412 
413 VOID
414 CALLBACK
415 PinSetStateWorkerRoutine(
416     IN PDEVICE_OBJECT  DeviceObject,
417     IN PVOID  Context)
418 {
419     PSETPIN_CONTEXT PinWorkContext = (PSETPIN_CONTEXT)Context;
420     NTSTATUS Status;
421 
422     // try set stream
423     Status = PinWorkContext->Pin->m_Stream->SetState(PinWorkContext->NewState);
424 
425     DPRINT1("Setting state %u %x\n", PinWorkContext->NewState, Status);
426     if (NT_SUCCESS(Status))
427     {
428         // store new state
429         PinWorkContext->Pin->m_State = PinWorkContext->NewState;
430 
431         if (PinWorkContext->Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && PinWorkContext->Pin->m_State == KSSTATE_STOP)
432         {
433             /* FIXME complete pending irps with successful state */
434             PinWorkContext->Pin->m_IrpQueue->CancelBuffers();
435         }
436         //HACK
437         //PinWorkContext->Pin->m_IrpQueue->CancelBuffers();
438     }
439 
440     // store result
441     PinWorkContext->Irp->IoStatus.Information = sizeof(KSSTATE);
442     PinWorkContext->Irp->IoStatus.Status = Status;
443 
444     // complete irp
445     IoCompleteRequest(PinWorkContext->Irp, IO_NO_INCREMENT);
446 
447     // free work item
448     IoFreeWorkItem(PinWorkContext->WorkItem);
449 
450     // free work context
451     FreeItem(PinWorkContext, TAG_PORTCLASS);
452 
453 }
454 
455 
456 NTSTATUS
457 NTAPI
458 PinWaveCyclicState(
459     IN PIRP Irp,
460     IN PKSIDENTIFIER Request,
461     IN OUT PVOID Data)
462 {
463     NTSTATUS Status = STATUS_UNSUCCESSFUL;
464     CPortPinWaveCyclic *Pin;
465     PSUBDEVICE_DESCRIPTOR Descriptor;
466     PKSSTATE State = (PKSSTATE)Data;
467 
468     // get sub device descriptor
469     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
470 
471     // sanity check
472     PC_ASSERT(Descriptor);
473     PC_ASSERT(Descriptor->PortPin);
474     PC_ASSERT_IRQL(DISPATCH_LEVEL);
475 
476     // cast to pin impl
477     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
478 
479     //sanity check
480     PC_ASSERT(Pin->m_Stream);
481 
482     if (Request->Flags & KSPROPERTY_TYPE_SET)
483     {
484         // try set stream
485         Status = Pin->m_Stream->SetState(*State);
486 
487         DPRINT("Setting state %u %x\n", *State, Status);
488         if (NT_SUCCESS(Status))
489         {
490             // store new state
491             Pin->m_State = *State;
492 
493             if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && Pin->m_State == KSSTATE_STOP)
494             {
495                 // FIXME
496                 // complete with successful state
497                 Pin->m_Stream->Silence(Pin->m_CommonBuffer, Pin->m_CommonBufferSize);
498                 Pin->m_IrpQueue->CancelBuffers();
499                 Pin->m_Position.PlayOffset = 0;
500                 Pin->m_Position.WriteOffset = 0;
501             }
502             else if (Pin->m_State == KSSTATE_STOP)
503             {
504                 Pin->m_Stream->Silence(Pin->m_CommonBuffer, Pin->m_CommonBufferSize);
505                 Pin->m_IrpQueue->CancelBuffers();
506                 Pin->m_Position.PlayOffset = 0;
507                 Pin->m_Position.WriteOffset = 0;
508             }
509             // store result
510             Irp->IoStatus.Information = sizeof(KSSTATE);
511         }
512         return Status;
513     }
514     else if (Request->Flags & KSPROPERTY_TYPE_GET)
515     {
516         // get current stream state
517         *State = Pin->m_State;
518         // store result
519         Irp->IoStatus.Information = sizeof(KSSTATE);
520 
521         return STATUS_SUCCESS;
522     }
523 
524     // unsupported request
525     return STATUS_NOT_SUPPORTED;
526 }
527 
528 NTSTATUS
529 NTAPI
530 PinWaveCyclicDataFormat(
531     IN PIRP Irp,
532     IN PKSIDENTIFIER Request,
533     IN OUT PVOID Data)
534 {
535     NTSTATUS Status = STATUS_UNSUCCESSFUL;
536     CPortPinWaveCyclic *Pin;
537     PSUBDEVICE_DESCRIPTOR Descriptor;
538     PIO_STACK_LOCATION IoStack;
539 
540     // get current irp stack location
541     IoStack = IoGetCurrentIrpStackLocation(Irp);
542 
543     // get sub device descriptor
544     Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
545 
546     // sanity check
547     PC_ASSERT(Descriptor);
548     PC_ASSERT(Descriptor->PortPin);
549 
550     // cast to pin impl
551     Pin = (CPortPinWaveCyclic*)Descriptor->PortPin;
552 
553     //sanity check
554     PC_ASSERT(Pin->m_Stream);
555     PC_ASSERT(Pin->m_Format);
556 
557     if (Request->Flags & KSPROPERTY_TYPE_SET)
558     {
559         // try to change data format
560         PKSDATAFORMAT NewDataFormat, DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
561         ULONG Size = min(Pin->m_Format->FormatSize, DataFormat->FormatSize);
562 
563         if (RtlCompareMemory(DataFormat, Pin->m_Format, Size) == Size)
564         {
565             // format is identical
566             Irp->IoStatus.Information = DataFormat->FormatSize;
567             return STATUS_SUCCESS;
568         }
569 
570         // new change request
571         PC_ASSERT(Pin->m_State != KSSTATE_RUN);
572         // FIXME queue a work item when Irql != PASSIVE_LEVEL
573         PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
574 
575         // allocate new data format
576         NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
577         if (!NewDataFormat)
578         {
579             // not enough memory
580             return STATUS_NO_MEMORY;
581         }
582 
583         // copy new data format
584         RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
585 
586         // set new format
587         Status = Pin->m_Stream->SetFormat(NewDataFormat);
588         if (NT_SUCCESS(Status))
589         {
590             // free old format
591             FreeItem(Pin->m_Format, TAG_PORTCLASS);
592 
593             // store new format
594             Pin->m_Format = NewDataFormat;
595             Irp->IoStatus.Information = NewDataFormat->FormatSize;
596 
597 #if 0
598             PC_ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
599             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, KSDATAFORMAT_TYPE_AUDIO));
600             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, KSDATAFORMAT_SUBTYPE_PCM));
601             PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
602 
603 
604             DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
605                                                                        ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
606                                                                        ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
607 #endif
608 
609         }
610         else
611         {
612             // failed to set format
613             FreeItem(NewDataFormat, TAG_PORTCLASS);
614         }
615 
616 
617         // done
618         return Status;
619     }
620     else if (Request->Flags & KSPROPERTY_TYPE_GET)
621     {
622         // get current data format
623         PC_ASSERT(Pin->m_Format);
624 
625         if (Pin->m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
626         {
627             // buffer too small
628             Irp->IoStatus.Information = Pin->m_Format->FormatSize;
629             return STATUS_MORE_ENTRIES;
630         }
631         // copy data format
632         RtlMoveMemory(Data, Pin->m_Format, Pin->m_Format->FormatSize);
633         // store result size
634         Irp->IoStatus.Information = Pin->m_Format->FormatSize;
635 
636         // done
637         return STATUS_SUCCESS;
638     }
639 
640     // unsupported request
641     return STATUS_NOT_SUPPORTED;
642 }
643 
644 VOID
645 CPortPinWaveCyclic::GeneratePositionEvents(
646     IN ULONGLONG OldOffset,
647     IN ULONGLONG NewOffset)
648 {
649     PLIST_ENTRY Entry;
650     PKSEVENT_ENTRY EventEntry;
651     PLOOPEDSTREAMING_EVENT_CONTEXT Context;
652 
653     // acquire event lock
654     KeAcquireSpinLockAtDpcLevel(&m_EventListLock);
655 
656     // point to first entry
657     Entry = m_EventList.Flink;
658 
659     while(Entry != &m_EventList)
660     {
661         // get event entry
662         EventEntry = (PKSEVENT_ENTRY)CONTAINING_RECORD(Entry, KSEVENT_ENTRY, ListEntry);
663 
664         // get event entry context
665         Context = (PLOOPEDSTREAMING_EVENT_CONTEXT)(EventEntry + 1);
666 
667         if (Context->bLoopedStreaming != FALSE)
668         {
669             if (NewOffset > OldOffset)
670             {
671                 /* buffer progress no overlap */
672                 if (OldOffset < Context->Position && Context->Position <= NewOffset)
673                 {
674                     /* when someone eventually fixes sprintf... */
675                     DPRINT("Generating event at OldOffset %I64u\n", OldOffset);
676                     DPRINT("Context->Position %I64u\n", Context->Position);
677                     DPRINT("NewOffset %I64u\n", NewOffset);
678                     /* generate event */
679                     KsGenerateEvent(EventEntry);
680                 }
681             }
682             else
683             {
684                 /* buffer wrap-arround */
685                 if (OldOffset < Context->Position || NewOffset > Context->Position)
686                 {
687                     /* when someone eventually fixes sprintf... */
688                     DPRINT("Generating event at OldOffset %I64u\n", OldOffset);
689                     DPRINT("Context->Position %I64u\n", Context->Position);
690                     DPRINT("NewOffset %I64u\n", NewOffset);
691                     /* generate event */
692                     KsGenerateEvent(EventEntry);
693                 }
694             }
695         }
696 
697         // move to next entry
698         Entry = Entry->Flink;
699     }
700 
701     // release lock
702     KeReleaseSpinLockFromDpcLevel(&m_EventListLock);
703 }
704 
705 VOID
706 CPortPinWaveCyclic::UpdateCommonBuffer(
707     ULONG Position,
708     ULONG MaxTransferCount)
709 {
710     ULONG BufferLength;
711     ULONG BytesToCopy;
712     ULONG BufferSize;
713     ULONG Gap;
714     PUCHAR Buffer;
715     NTSTATUS Status;
716 
717     BufferLength = Position - m_CommonBufferOffset;
718     BufferLength = min(BufferLength, MaxTransferCount);
719 
720     while(BufferLength)
721     {
722         Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
723         if (!NT_SUCCESS(Status))
724         {
725             Gap = Position - m_CommonBufferOffset;
726             if (Gap > BufferLength)
727             {
728                 // insert silence samples
729                 DPRINT("Inserting Silence Buffer Offset %lu GapLength %lu\n", m_CommonBufferOffset, BufferLength);
730                 m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength);
731 
732                 m_CommonBufferOffset += BufferLength;
733             }
734             break;
735         }
736 
737         BytesToCopy = min(BufferLength, BufferSize);
738 
739         if (m_Capture)
740         {
741             m_DmaChannel->CopyFrom(Buffer, (PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BytesToCopy);
742         }
743         else
744         {
745             m_DmaChannel->CopyTo((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, Buffer, BytesToCopy);
746         }
747 
748         m_IrpQueue->UpdateMapping(BytesToCopy);
749         m_CommonBufferOffset += BytesToCopy;
750 
751         BufferLength -= BytesToCopy;
752         m_Position.PlayOffset += BytesToCopy;
753 
754         if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
755         {
756             if (m_Position.WriteOffset)
757             {
758                 // normalize position
759                 m_Position.PlayOffset = m_Position.PlayOffset % m_Position.WriteOffset;
760             }
761         }
762     }
763 }
764 
765 VOID
766 CPortPinWaveCyclic::UpdateCommonBufferOverlap(
767     ULONG Position,
768     ULONG MaxTransferCount)
769 {
770     ULONG BufferLength, Length, Gap;
771     ULONG BytesToCopy;
772     ULONG BufferSize;
773     PUCHAR Buffer;
774     NTSTATUS Status;
775 
776 
777     BufferLength = Gap = m_CommonBufferSize - m_CommonBufferOffset;
778     BufferLength = Length = min(BufferLength, MaxTransferCount);
779     while(BufferLength)
780     {
781         Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
782         if (!NT_SUCCESS(Status))
783         {
784             Gap = m_CommonBufferSize - m_CommonBufferOffset + Position;
785             if (Gap > BufferLength)
786             {
787                 // insert silence samples
788                 DPRINT("Overlap Inserting Silence Buffer Size %lu Offset %lu Gap %lu Position %lu\n", m_CommonBufferSize, m_CommonBufferOffset, Gap, Position);
789                 m_Stream->Silence((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BufferLength);
790 
791                 m_CommonBufferOffset += BufferLength;
792             }
793             break;
794         }
795 
796         BytesToCopy = min(BufferLength, BufferSize);
797 
798         if (m_Capture)
799         {
800             m_DmaChannel->CopyFrom(Buffer,
801                                              (PUCHAR)m_CommonBuffer + m_CommonBufferOffset,
802                                              BytesToCopy);
803         }
804         else
805         {
806             m_DmaChannel->CopyTo((PUCHAR)m_CommonBuffer + m_CommonBufferOffset,
807                                              Buffer,
808                                              BytesToCopy);
809         }
810 
811         m_IrpQueue->UpdateMapping(BytesToCopy);
812         m_CommonBufferOffset += BytesToCopy;
813         m_Position.PlayOffset += BytesToCopy;
814 
815         BufferLength -=BytesToCopy;
816 
817         if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
818         {
819             if (m_Position.WriteOffset)
820             {
821                 // normalize position
822                 m_Position.PlayOffset = m_Position.PlayOffset % m_Position.WriteOffset;
823             }
824         }
825     }
826 
827     if (Gap == Length)
828     {
829         m_CommonBufferOffset = 0;
830 
831         MaxTransferCount -= Length;
832 
833         if (MaxTransferCount)
834         {
835             UpdateCommonBuffer(Position, MaxTransferCount);
836         }
837     }
838 }
839 
840 VOID
841 NTAPI
842 CPortPinWaveCyclic::RequestService()
843 {
844     ULONG Position;
845     ULONGLONG OldOffset, NewOffset;
846 
847     PC_ASSERT_IRQL(DISPATCH_LEVEL);
848 
849     if (m_State == KSSTATE_RUN && m_ResetState == KSRESET_END)
850     {
851         m_Stream->GetPosition(&Position);
852 
853         OldOffset = m_Position.PlayOffset;
854 
855         if (Position < m_CommonBufferOffset)
856         {
857             UpdateCommonBufferOverlap(Position, m_FrameSize);
858         }
859         else if (Position >= m_CommonBufferOffset)
860         {
861             UpdateCommonBuffer(Position, m_FrameSize);
862         }
863 
864         NewOffset = m_Position.PlayOffset;
865 
866         GeneratePositionEvents(OldOffset, NewOffset);
867     }
868 }
869 
870 NTSTATUS
871 NTAPI
872 CPortPinWaveCyclic::NewIrpTarget(
873     OUT struct IIrpTarget **OutTarget,
874     IN PCWSTR Name,
875     IN PUNKNOWN Unknown,
876     IN POOL_TYPE PoolType,
877     IN PDEVICE_OBJECT DeviceObject,
878     IN PIRP Irp,
879     IN KSOBJECT_CREATE *CreateObject)
880 {
881     UNIMPLEMENTED;
882     return STATUS_UNSUCCESSFUL;
883 }
884 
885 NTSTATUS
886 NTAPI
887 CPortPinWaveCyclic::DeviceIoControl(
888     IN PDEVICE_OBJECT DeviceObject,
889     IN PIRP Irp)
890 {
891     PIO_STACK_LOCATION IoStack;
892     PKSPROPERTY Property;
893     UNICODE_STRING GuidString;
894     NTSTATUS Status = STATUS_NOT_SUPPORTED;
895     ULONG Data = 0;
896     KSRESET ResetValue;
897 
898     /* get current irp stack location */
899     IoStack = IoGetCurrentIrpStackLocation(Irp);
900 
901     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
902     {
903         /* handle property with subdevice descriptor */
904         Status = PcHandlePropertyWithTable(Irp,  m_Descriptor->FilterPropertySetCount, m_Descriptor->FilterPropertySet, m_Descriptor);
905 
906         if (Status == STATUS_NOT_FOUND)
907         {
908             Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
909 
910             RtlStringFromGUID(Property->Set, &GuidString);
911             DPRINT("Unhandled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
912             RtlFreeUnicodeString(&GuidString);
913         }
914     }
915     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
916     {
917         Status = PcHandleEnableEventWithTable(Irp, m_Descriptor);
918     }
919     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT)
920     {
921         Status = PcHandleDisableEventWithTable(Irp, m_Descriptor);
922     }
923     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
924     {
925         Status = KsAcquireResetValue(Irp, &ResetValue);
926         DPRINT("Status %x Value %u\n", Status, ResetValue);
927         /* check for success */
928         if (NT_SUCCESS(Status))
929         {
930             //determine state of reset request
931             if (ResetValue == KSRESET_BEGIN)
932             {
933                 // start reset process
934                 // incoming read/write requests will be rejected
935                 m_ResetState = KSRESET_BEGIN;
936 
937                 // cancel existing buffers
938                 m_IrpQueue->CancelBuffers();
939             }
940             else if (ResetValue == KSRESET_END)
941             {
942                 // end of reset process
943                 m_ResetState = KSRESET_END;
944             }
945         }
946     }
947     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
948     {
949         /* increment total number of packets */
950         InterlockedIncrement((PLONG)&m_TotalPackets);
951 
952          DPRINT("New Packet Total %u State %x MinData %u\n", m_TotalPackets, m_State, m_IrpQueue->NumData());
953 
954          /* is the device not currently reset */
955          if (m_ResetState == KSRESET_END)
956          {
957              /* add the mapping */
958              Status = m_IrpQueue->AddMapping(Irp, &Data);
959 
960              /* check for success */
961              if (NT_SUCCESS(Status))
962              {
963                 m_Position.WriteOffset += Data;
964                 Status = STATUS_PENDING;
965              }
966          }
967          else
968          {
969              /* reset request is currently in progress */
970              Status = STATUS_DEVICE_NOT_READY;
971              DPRINT1("NotReady\n");
972          }
973     }
974     else
975     {
976         return KsDefaultDeviceIoCompletion(DeviceObject, Irp);
977     }
978 
979     if (Status != STATUS_PENDING)
980     {
981         Irp->IoStatus.Status = Status;
982         IoCompleteRequest(Irp, IO_NO_INCREMENT);
983     }
984 
985     return Status;
986 }
987 
988 NTSTATUS
989 NTAPI
990 CPortPinWaveCyclic::Read(
991     IN PDEVICE_OBJECT DeviceObject,
992     IN PIRP Irp)
993 {
994     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
995 }
996 
997 NTSTATUS
998 NTAPI
999 CPortPinWaveCyclic::Write(
1000     IN PDEVICE_OBJECT DeviceObject,
1001     IN PIRP Irp)
1002 {
1003     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
1004 }
1005 
1006 NTSTATUS
1007 NTAPI
1008 CPortPinWaveCyclic::Flush(
1009     IN PDEVICE_OBJECT DeviceObject,
1010     IN PIRP Irp)
1011 {
1012     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
1013 }
1014 
1015 NTSTATUS
1016 NTAPI
1017 CPortPinWaveCyclic::Close(
1018     IN PDEVICE_OBJECT DeviceObject,
1019     IN PIRP Irp)
1020 {
1021     DPRINT("CPortPinWaveCyclic::Close entered\n");
1022 
1023     PC_ASSERT_IRQL(PASSIVE_LEVEL);
1024 
1025     if (m_Format)
1026     {
1027         // free format
1028         FreeItem(m_Format, TAG_PORTCLASS);
1029 
1030         // format is freed
1031         m_Format = NULL;
1032     }
1033 
1034     if (m_IrpQueue)
1035     {
1036         // cancel remaining irps
1037         m_IrpQueue->CancelBuffers();
1038 
1039         // release irp queue
1040         m_IrpQueue->Release();
1041 
1042         // queue is freed
1043         m_IrpQueue = NULL;
1044     }
1045 
1046     if (m_ServiceGroup)
1047     {
1048         // remove member from service group
1049         m_ServiceGroup->RemoveMember(PSERVICESINK(this));
1050 
1051         // do not release service group, it is released by the miniport object
1052         m_ServiceGroup = NULL;
1053     }
1054 
1055     if (m_Stream)
1056     {
1057         if (m_State != KSSTATE_STOP)
1058         {
1059             // stop stream
1060             NTSTATUS Status = m_Stream->SetState(KSSTATE_STOP);
1061             if (!NT_SUCCESS(Status))
1062             {
1063                 DPRINT("Warning: failed to stop stream with %x\n", Status);
1064                 PC_ASSERT(0);
1065             }
1066         }
1067         // set state to stop
1068         m_State = KSSTATE_STOP;
1069 
1070         DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
1071 
1072         // release stream
1073         m_Stream->Release();
1074 
1075         // stream is now freed
1076         m_Stream = NULL;
1077     }
1078 
1079 
1080     if (m_Filter)
1081     {
1082         // disconnect pin from filter
1083         m_Filter->FreePin((PPORTPINWAVECYCLIC)this);
1084 
1085         // release filter reference
1086         m_Filter->Release();
1087 
1088         // pin is done with filter
1089         m_Filter = NULL;
1090     }
1091 
1092     if (m_Port)
1093     {
1094         // release reference to port driver
1095         m_Port->Release();
1096 
1097         // work is done for port
1098         m_Port = NULL;
1099     }
1100 
1101     Irp->IoStatus.Information = 0;
1102     Irp->IoStatus.Status = STATUS_SUCCESS;
1103     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1104 
1105     delete this;
1106 
1107     return STATUS_SUCCESS;
1108 }
1109 
1110 NTSTATUS
1111 NTAPI
1112 CPortPinWaveCyclic::QuerySecurity(
1113     IN PDEVICE_OBJECT DeviceObject,
1114     IN PIRP Irp)
1115 {
1116     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
1117 }
1118 
1119 NTSTATUS
1120 NTAPI
1121 CPortPinWaveCyclic::SetSecurity(
1122     IN PDEVICE_OBJECT DeviceObject,
1123     IN PIRP Irp)
1124 {
1125     return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
1126 }
1127 
1128 BOOLEAN
1129 NTAPI
1130 CPortPinWaveCyclic::FastDeviceIoControl(
1131     IN PFILE_OBJECT FileObject,
1132     IN BOOLEAN Wait,
1133     IN PVOID InputBuffer,
1134     IN ULONG InputBufferLength,
1135     OUT PVOID OutputBuffer,
1136     IN ULONG OutputBufferLength,
1137     IN ULONG IoControlCode,
1138     OUT PIO_STATUS_BLOCK StatusBlock,
1139     IN PDEVICE_OBJECT DeviceObject)
1140 {
1141     return KsDispatchFastIoDeviceControlFailure(FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, StatusBlock, DeviceObject);
1142 }
1143 
1144 
1145 BOOLEAN
1146 NTAPI
1147 CPortPinWaveCyclic::FastRead(
1148     IN PFILE_OBJECT FileObject,
1149     IN PLARGE_INTEGER FileOffset,
1150     IN ULONG Length,
1151     IN BOOLEAN Wait,
1152     IN ULONG LockKey,
1153     IN PVOID Buffer,
1154     OUT PIO_STATUS_BLOCK StatusBlock,
1155     IN PDEVICE_OBJECT DeviceObject)
1156 {
1157     return KsDispatchFastReadFailure(FileObject, FileOffset, Length, Wait, LockKey, Buffer, StatusBlock, DeviceObject);
1158 }
1159 
1160 
1161 BOOLEAN
1162 NTAPI
1163 CPortPinWaveCyclic::FastWrite(
1164     IN PFILE_OBJECT FileObject,
1165     IN PLARGE_INTEGER FileOffset,
1166     IN ULONG Length,
1167     IN BOOLEAN Wait,
1168     IN ULONG LockKey,
1169     IN PVOID Buffer,
1170     OUT PIO_STATUS_BLOCK StatusBlock,
1171     IN PDEVICE_OBJECT DeviceObject)
1172 {
1173     return KsDispatchFastReadFailure(FileObject, FileOffset, Length, Wait, LockKey, Buffer, StatusBlock, DeviceObject);
1174 }
1175 
1176 
1177 NTSTATUS
1178 NTAPI
1179 CPortPinWaveCyclic::Init(
1180     IN PPORTWAVECYCLIC Port,
1181     IN PPORTFILTERWAVECYCLIC Filter,
1182     IN KSPIN_CONNECT * ConnectDetails,
1183     IN KSPIN_DESCRIPTOR * KsPinDescriptor)
1184 {
1185     NTSTATUS Status;
1186     PKSDATAFORMAT DataFormat;
1187     //PDEVICE_OBJECT DeviceObject;
1188     BOOLEAN Capture;
1189     PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor = NULL;
1190     //IDrmAudioStream * DrmAudio = NULL;
1191 
1192     m_KsPinDescriptor = KsPinDescriptor;
1193     m_ConnectDetails = ConnectDetails;
1194     m_Miniport = GetWaveCyclicMiniport(Port);
1195 
1196     //DeviceObject = GetDeviceObject(Port);
1197 
1198     DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
1199 
1200     DPRINT("CPortPinWaveCyclic::Init entered Size %u\n", DataFormat->FormatSize);
1201 
1202     Status = NewIrpQueue(&m_IrpQueue);
1203     if (!NT_SUCCESS(Status))
1204         return Status;
1205 
1206     if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
1207     {
1208         Capture = FALSE;
1209     }
1210     else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
1211     {
1212         Capture = TRUE;
1213     }
1214     else
1215     {
1216         DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
1217         DbgBreakPoint();
1218         while(TRUE);
1219     }
1220 
1221 
1222     Status = m_Miniport->NewStream(&m_Stream,
1223                                    NULL,
1224                                    NonPagedPool,
1225                                    ConnectDetails->PinId,
1226                                    Capture,
1227                                    DataFormat,
1228                                    &m_DmaChannel,
1229                                    &m_ServiceGroup);
1230 #if 0
1231     Status = m_Stream->QueryInterface(IID_IDrmAudioStream, (PVOID*)&DrmAudio);
1232     if (NT_SUCCESS(Status))
1233     {
1234         DRMRIGHTS DrmRights;
1235         DPRINT("Got IID_IDrmAudioStream interface %p\n", DrmAudio);
1236 
1237         DrmRights.CopyProtect = FALSE;
1238         DrmRights.Reserved = 0;
1239         DrmRights.DigitalOutputDisable = FALSE;
1240 
1241         Status = DrmAudio->SetContentId(1, &DrmRights);
1242         DPRINT("Status %x\n", Status);
1243     }
1244 #endif
1245 
1246     DPRINT1("CPortPinWaveCyclic::Init Status %x PinId %u Capture %u\n", Status, ConnectDetails->PinId, Capture);
1247 
1248     if (!NT_SUCCESS(Status))
1249         return Status;
1250 
1251     ISubdevice * Subdevice = NULL;
1252     // get subdevice interface
1253     Status = Port->QueryInterface(IID_ISubdevice, (PVOID*)&Subdevice);
1254 
1255     if (!NT_SUCCESS(Status))
1256         return Status;
1257 
1258     Status = Subdevice->GetDescriptor(&SubDeviceDescriptor);
1259     if (!NT_SUCCESS(Status))
1260     {
1261         // failed to get descriptor
1262         Subdevice->Release();
1263         return Status;
1264     }
1265 
1266     /* initialize event management */
1267     InitializeListHead(&m_EventList);
1268     KeInitializeSpinLock(&m_EventListLock);
1269 
1270     Status = PcCreateSubdeviceDescriptor(&m_Descriptor,
1271                                          SubDeviceDescriptor->InterfaceCount,
1272                                          SubDeviceDescriptor->Interfaces,
1273                                          0, /* FIXME KSINTERFACE_STANDARD with KSINTERFACE_STANDARD_STREAMING / KSINTERFACE_STANDARD_LOOPED_STREAMING */
1274                                          NULL,
1275                                          sizeof(PinWaveCyclicPropertySet) / sizeof(KSPROPERTY_SET),
1276                                          PinWaveCyclicPropertySet,
1277                                          0,
1278                                          0,
1279                                          0,
1280                                          NULL,
1281                                          sizeof(PinWaveCyclicEventSet) / sizeof(KSEVENT_SET),
1282                                          PinWaveCyclicEventSet,
1283                                          SubDeviceDescriptor->DeviceDescriptor);
1284 
1285     m_Descriptor->UnknownStream = (PUNKNOWN)m_Stream;
1286     m_Descriptor->UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
1287     m_Descriptor->PortPin = (PVOID)this;
1288     m_Descriptor->EventList = &m_EventList;
1289     m_Descriptor->EventListLock = &m_EventListLock;
1290 
1291     // initialize reset state
1292     m_ResetState = KSRESET_END;
1293 
1294     // release subdevice descriptor
1295     Subdevice->Release();
1296 
1297     // add ourselves to service group
1298     Status = m_ServiceGroup->AddMember(PSERVICESINK(this));
1299     if (!NT_SUCCESS(Status))
1300     {
1301         DPRINT("Failed to add pin to service group\n");
1302         return Status;
1303     }
1304 
1305     m_Stream->SetState(KSSTATE_STOP);
1306     m_State = KSSTATE_STOP;
1307     m_CommonBufferOffset = 0;
1308     m_CommonBufferSize = m_DmaChannel->BufferSize();
1309     m_CommonBuffer = m_DmaChannel->SystemAddress();
1310     m_Capture = Capture;
1311     // delay of 10 millisec
1312     m_Delay = Int32x32To64(10, -10000);
1313 
1314     // sanity checks
1315     PC_ASSERT(m_CommonBufferSize);
1316     PC_ASSERT(m_CommonBuffer);
1317 
1318     Status = m_Stream->SetNotificationFreq(10, &m_FrameSize);
1319     PC_ASSERT(NT_SUCCESS(Status));
1320     PC_ASSERT(m_FrameSize);
1321 
1322     DPRINT1("Bits %u Samples %u Channels %u Tag %u FrameSize %u CommonBufferSize %lu, CommonBuffer %p\n", ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wBitsPerSample, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nSamplesPerSec, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.nChannels, ((PKSDATAFORMAT_WAVEFORMATEX)(DataFormat))->WaveFormatEx.wFormatTag, m_FrameSize, m_CommonBufferSize, m_DmaChannel->SystemAddress());
1323 
1324 
1325     /* set up allocator framing */
1326     m_AllocatorFraming.RequirementsFlags = KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
1327     m_AllocatorFraming.PoolType = NonPagedPool;
1328     m_AllocatorFraming.Frames = 8;
1329     m_AllocatorFraming.FileAlignment = FILE_64_BYTE_ALIGNMENT;
1330     m_AllocatorFraming.Reserved = 0;
1331     m_AllocatorFraming.FrameSize = m_FrameSize;
1332 
1333     m_Stream->Silence(m_CommonBuffer, m_CommonBufferSize);
1334 
1335     Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_FrameSize, 0, FALSE);
1336     if (!NT_SUCCESS(Status))
1337     {
1338        m_IrpQueue->Release();
1339        return Status;
1340     }
1341 
1342     m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
1343     if (!m_Format)
1344         return STATUS_INSUFFICIENT_RESOURCES;
1345 
1346     RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
1347 
1348     Port->AddRef();
1349     Filter->AddRef();
1350 
1351     m_Port = Port;
1352     m_Filter = Filter;
1353 
1354     return STATUS_SUCCESS;
1355 }
1356 
1357 
1358 ULONG
1359 NTAPI
1360 CPortPinWaveCyclic::GetCompletedPosition()
1361 {
1362     UNIMPLEMENTED;
1363     return 0;
1364 }
1365 
1366 
1367 ULONG
1368 NTAPI
1369 CPortPinWaveCyclic::GetCycleCount()
1370 {
1371     UNIMPLEMENTED;
1372     return 0;
1373 }
1374 
1375 
1376 ULONG
1377 NTAPI
1378 CPortPinWaveCyclic::GetDeviceBufferSize()
1379 {
1380     return m_CommonBufferSize;
1381 }
1382 
1383 
1384 PVOID
1385 NTAPI
1386 CPortPinWaveCyclic::GetIrpStream()
1387 {
1388     return (PVOID)m_IrpQueue;
1389 }
1390 
1391 
1392 PMINIPORT
1393 NTAPI
1394 CPortPinWaveCyclic::GetMiniport()
1395 {
1396     return (PMINIPORT)m_Miniport;
1397 }
1398 
1399 
1400 NTSTATUS
1401 NewPortPinWaveCyclic(
1402     OUT IPortPinWaveCyclic ** OutPin)
1403 {
1404     CPortPinWaveCyclic * This;
1405 
1406     This = new(NonPagedPool, TAG_PORTCLASS)CPortPinWaveCyclic(NULL);
1407     if (!This)
1408         return STATUS_INSUFFICIENT_RESOURCES;
1409 
1410     This->AddRef();
1411 
1412     // store result
1413     *OutPin = (IPortPinWaveCyclic*)This;
1414 
1415     return STATUS_SUCCESS;
1416 }
1417 
1418