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