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