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