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