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