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