3e6eb97a464402cc8dda4950ae4e67c6359eb928
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / pin_wavert.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/pin_wavert.cpp
5 * PURPOSE: WaveRT IRP Audio Pin
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.hpp"
10
11 class CPortPinWaveRT : public IPortPinWaveRT,
12 public IServiceSink //hack
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_IPortPinWaveRT;
34 IMP_IServiceSink; //HACK
35 CPortPinWaveRT(IUnknown *OuterUnknown){}
36 virtual ~CPortPinWaveRT(){}
37
38 protected:
39
40 IPortWaveRT * m_Port;
41 IPortFilterWaveRT * m_Filter;
42 KSPIN_DESCRIPTOR * m_KsPinDescriptor;
43 PMINIPORTWAVERT m_Miniport;
44 PMINIPORTWAVERTSTREAM m_Stream;
45 PPORTWAVERTSTREAM m_PortStream;
46 PSERVICEGROUP m_ServiceGroup;
47 KSSTATE m_State;
48 PKSDATAFORMAT m_Format;
49 KSPIN_CONNECT * m_ConnectDetails;
50
51 PVOID m_CommonBuffer;
52 ULONG m_CommonBufferSize;
53 ULONG m_CommonBufferOffset;
54
55 IIrpQueue * m_IrpQueue;
56
57 BOOL m_Capture;
58
59 ULONG m_TotalPackets;
60 ULONG m_PreCompleted;
61 ULONG m_PostCompleted;
62
63 ULONGLONG m_Delay;
64
65 MEMORY_CACHING_TYPE m_CacheType;
66 PMDL m_Mdl;
67
68 LONG m_Ref;
69
70 NTSTATUS NTAPI HandleKsProperty(IN PIRP Irp);
71 NTSTATUS NTAPI HandleKsStream(IN PIRP Irp);
72 VOID NTAPI SetStreamState(IN KSSTATE State);
73 VOID UpdateCommonBuffer(ULONG Position);
74 VOID UpdateCommonBufferOverlap(ULONG Position);
75 friend VOID NTAPI SetStreamWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context);
76 friend VOID NTAPI CloseStreamRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context);
77
78 };
79
80
81 typedef struct
82 {
83 CPortPinWaveRT *Pin;
84 PIO_WORKITEM WorkItem;
85 KSSTATE State;
86 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
87
88
89 VOID
90 CPortPinWaveRT::UpdateCommonBuffer(
91 ULONG Position)
92 {
93 ULONG BufferLength;
94 ULONG BytesToCopy;
95 ULONG BufferSize;
96 PUCHAR Buffer;
97 NTSTATUS Status;
98
99 BufferLength = Position - m_CommonBufferOffset;
100 while(BufferLength)
101 {
102 Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
103 if (!NT_SUCCESS(Status))
104 return;
105
106 BytesToCopy = min(BufferLength, BufferSize);
107
108 if (m_Capture)
109 {
110 RtlMoveMemory(Buffer, (PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BytesToCopy);
111 }
112 else
113 {
114 RtlMoveMemory((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, Buffer, BytesToCopy);
115 }
116
117 m_IrpQueue->UpdateMapping(BytesToCopy);
118 m_CommonBufferOffset += BytesToCopy;
119
120 BufferLength = Position - m_CommonBufferOffset;
121 }
122 }
123
124 VOID
125 CPortPinWaveRT::UpdateCommonBufferOverlap(
126 ULONG Position)
127 {
128 ULONG BufferLength;
129 ULONG BytesToCopy;
130 ULONG BufferSize;
131 PUCHAR Buffer;
132 NTSTATUS Status;
133
134
135 BufferLength = m_CommonBufferSize - m_CommonBufferOffset;
136 while(BufferLength)
137 {
138 Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
139 if (!NT_SUCCESS(Status))
140 return;
141
142 BytesToCopy = min(BufferLength, BufferSize);
143
144 if (m_Capture)
145 {
146 RtlMoveMemory(Buffer, (PUCHAR)m_CommonBuffer + m_CommonBufferOffset, BytesToCopy);
147 }
148 else
149 {
150 RtlMoveMemory((PUCHAR)m_CommonBuffer + m_CommonBufferOffset, Buffer, BytesToCopy);
151 }
152
153 m_IrpQueue->UpdateMapping(BytesToCopy);
154 m_CommonBufferOffset += BytesToCopy;
155
156 BufferLength = m_CommonBufferSize - m_CommonBufferOffset;
157 }
158 m_CommonBufferOffset = 0;
159 UpdateCommonBuffer(Position);
160 }
161
162
163
164 //==================================================================================================================================
165 NTSTATUS
166 NTAPI
167 CPortPinWaveRT::QueryInterface(
168 IN REFIID refiid,
169 OUT PVOID* Output)
170 {
171 DPRINT("IServiceSink_fnQueryInterface entered\n");
172
173 if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
174 {
175 *Output = PVOID(PSERVICEGROUP(this));
176 PUNKNOWN(*Output)->AddRef();
177 return STATUS_SUCCESS;
178 }
179
180 if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) ||
181 IsEqualGUIDAligned(refiid, IID_IUnknown))
182 {
183 *Output = PVOID(PUNKNOWN((IIrpTarget*)this));
184 PUNKNOWN(*Output)->AddRef();
185 return STATUS_SUCCESS;
186 }
187 return STATUS_UNSUCCESSFUL;
188 }
189
190 VOID
191 NTAPI
192 CPortPinWaveRT::RequestService()
193 {
194 KSAUDIO_POSITION Position;
195 NTSTATUS Status;
196 PUCHAR Buffer;
197 ULONG BufferSize;
198
199 PC_ASSERT_IRQL(DISPATCH_LEVEL);
200
201 Status = m_IrpQueue->GetMapping(&Buffer, &BufferSize);
202 if (!NT_SUCCESS(Status))
203 {
204 SetStreamState(KSSTATE_STOP);
205 return;
206 }
207
208 Status = m_Stream->GetPosition(&Position);
209 DPRINT("PlayOffset %lu WriteOffset %lu Buffer %p BufferSize %u CommonBufferSize %u\n", Position.PlayOffset, Position.WriteOffset, Buffer, BufferSize, m_CommonBufferSize);
210
211 if (Position.PlayOffset < m_CommonBufferOffset)
212 {
213 UpdateCommonBufferOverlap(Position.PlayOffset);
214 }
215 else if (Position.PlayOffset >= m_CommonBufferOffset)
216 {
217 UpdateCommonBuffer(Position.PlayOffset);
218 }
219 }
220
221 VOID
222 NTAPI
223 SetStreamWorkerRoutine(
224 IN PDEVICE_OBJECT DeviceObject,
225 IN PVOID Context)
226 {
227 CPortPinWaveRT * This;
228 PSETSTREAM_CONTEXT Ctx = (PSETSTREAM_CONTEXT)Context;
229 KSSTATE State;
230
231 This = Ctx->Pin;
232 State = Ctx->State;
233
234 IoFreeWorkItem(Ctx->WorkItem);
235 FreeItem(Ctx, TAG_PORTCLASS);
236
237 // Has the audio stream resumed?
238 if (This->m_IrpQueue->NumMappings() && State == KSSTATE_STOP)
239 return;
240
241 // Set the state
242 if (NT_SUCCESS(This->m_Stream->SetState(State)))
243 {
244 // Set internal state to stop
245 This->m_State = State;
246
247 if (This->m_State == KSSTATE_STOP)
248 {
249 // reset start stream
250 This->m_IrpQueue->CancelBuffers(); //FIX function name
251 This->m_ServiceGroup->CancelDelayedService();
252 DPRINT1("Stopping PreCompleted %u PostCompleted %u\n", This->m_PreCompleted, This->m_PostCompleted);
253 }
254
255 if (This->m_State == KSSTATE_RUN)
256 {
257 // start the notification timer
258 This->m_ServiceGroup->RequestDelayedService(This->m_Delay);
259 }
260 }
261 }
262
263 VOID
264 NTAPI
265 CPortPinWaveRT::SetStreamState(
266 IN KSSTATE State)
267 {
268 PDEVICE_OBJECT DeviceObject;
269 PIO_WORKITEM WorkItem;
270 PSETSTREAM_CONTEXT Context;
271
272 PC_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
273
274 // Has the audio stream resumed?
275 if (m_IrpQueue->NumMappings() && State == KSSTATE_STOP)
276 return;
277
278 // Has the audio state already been set?
279 if (m_State == State)
280 return;
281
282 // Get device object
283 DeviceObject = GetDeviceObjectFromPortWaveRT(m_Port);
284
285 // allocate set state context
286 Context = (PSETSTREAM_CONTEXT)AllocateItem(NonPagedPool, sizeof(SETSTREAM_CONTEXT), TAG_PORTCLASS);
287
288 if (!Context)
289 return;
290
291 // allocate work item
292 WorkItem = IoAllocateWorkItem(DeviceObject);
293
294 if (!WorkItem)
295 {
296 ExFreePool(Context);
297 return;
298 }
299
300 Context->Pin = this;
301 Context->WorkItem = WorkItem;
302 Context->State = State;
303
304 // queue the work item
305 IoQueueWorkItem(WorkItem, SetStreamWorkerRoutine, DelayedWorkQueue, (PVOID)Context);
306 }
307
308 //==================================================================================================================================
309
310 NTSTATUS
311 NTAPI
312 CPortPinWaveRT::NewIrpTarget(
313 OUT struct IIrpTarget **OutTarget,
314 IN PCWSTR Name,
315 IN PUNKNOWN Unknown,
316 IN POOL_TYPE PoolType,
317 IN PDEVICE_OBJECT DeviceObject,
318 IN PIRP Irp,
319 IN KSOBJECT_CREATE *CreateObject)
320 {
321 UNIMPLEMENTED
322 return STATUS_UNSUCCESSFUL;
323 }
324
325 NTSTATUS
326 NTAPI
327 CPortPinWaveRT::HandleKsProperty(
328 IN PIRP Irp)
329 {
330 PKSPROPERTY Property;
331 NTSTATUS Status;
332 UNICODE_STRING GuidString;
333 PIO_STACK_LOCATION IoStack;
334
335 IoStack = IoGetCurrentIrpStackLocation(Irp);
336
337 DPRINT("IPortPinWave_HandleKsProperty entered\n");
338
339 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
340 {
341 Irp->IoStatus.Information = 0;
342 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
343 IoCompleteRequest(Irp, IO_NO_INCREMENT);
344 return STATUS_INVALID_PARAMETER;
345 }
346
347 Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
348
349 if (IsEqualGUIDAligned(Property->Set, KSPROPSETID_Connection))
350 {
351 if (Property->Id == KSPROPERTY_CONNECTION_STATE)
352 {
353 PKSSTATE State = (PKSSTATE)Irp->UserBuffer;
354
355 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSSTATE))
356 {
357 Irp->IoStatus.Information = sizeof(KSSTATE);
358 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
359 IoCompleteRequest(Irp, IO_NO_INCREMENT);
360 return STATUS_BUFFER_TOO_SMALL;
361 }
362
363 if (Property->Flags & KSPROPERTY_TYPE_SET)
364 {
365 Status = STATUS_UNSUCCESSFUL;
366 Irp->IoStatus.Information = 0;
367
368 if (m_Stream)
369 {
370 Status = m_Stream->SetState(*State);
371
372 DPRINT1("Setting state %u %x\n", *State, Status);
373 if (NT_SUCCESS(Status))
374 {
375 m_State = *State;
376 }
377 }
378 Irp->IoStatus.Status = Status;
379 IoCompleteRequest(Irp, IO_NO_INCREMENT);
380 return Status;
381 }
382 else if (Property->Flags & KSPROPERTY_TYPE_GET)
383 {
384 *State = m_State;
385 Irp->IoStatus.Information = sizeof(KSSTATE);
386 Irp->IoStatus.Status = STATUS_SUCCESS;
387 IoCompleteRequest(Irp, IO_NO_INCREMENT);
388 return STATUS_SUCCESS;
389 }
390 }
391 else if (Property->Id == KSPROPERTY_CONNECTION_DATAFORMAT)
392 {
393 PKSDATAFORMAT DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
394 if (Property->Flags & KSPROPERTY_TYPE_SET)
395 {
396 PKSDATAFORMAT NewDataFormat;
397 if (!RtlCompareMemory(DataFormat, m_Format, DataFormat->FormatSize))
398 {
399 Irp->IoStatus.Information = DataFormat->FormatSize;
400 Irp->IoStatus.Status = STATUS_SUCCESS;
401 IoCompleteRequest(Irp, IO_NO_INCREMENT);
402 return STATUS_SUCCESS;
403 }
404
405 NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
406 if (!NewDataFormat)
407 {
408 Irp->IoStatus.Information = 0;
409 Irp->IoStatus.Status = STATUS_NO_MEMORY;
410 IoCompleteRequest(Irp, IO_NO_INCREMENT);
411 return STATUS_NO_MEMORY;
412 }
413 RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
414
415 if (m_Stream)
416 {
417 #if 0
418 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
419 ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
420 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO));
421 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM));
422 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
423
424 ASSERT(m_State == KSSTATE_STOP);
425 #endif
426 DPRINT1("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
427 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
428 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
429
430 Status = m_Stream->SetFormat(NewDataFormat);
431 if (NT_SUCCESS(Status))
432 {
433 if (m_Format)
434 ExFreePoolWithTag(m_Format, TAG_PORTCLASS);
435
436 m_IrpQueue->UpdateFormat((PKSDATAFORMAT)NewDataFormat);
437 m_Format = NewDataFormat;
438 Irp->IoStatus.Information = DataFormat->FormatSize;
439 Irp->IoStatus.Status = STATUS_SUCCESS;
440 IoCompleteRequest(Irp, IO_NO_INCREMENT);
441 return STATUS_SUCCESS;
442 }
443 }
444 DPRINT1("Failed to set format\n");
445 Irp->IoStatus.Information = 0;
446 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
447 IoCompleteRequest(Irp, IO_NO_INCREMENT);
448 return STATUS_UNSUCCESSFUL;
449 }
450 else if (Property->Flags & KSPROPERTY_TYPE_GET)
451 {
452 if (!m_Format)
453 {
454 DPRINT1("No format\n");
455 Irp->IoStatus.Information = 0;
456 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
457 IoCompleteRequest(Irp, IO_NO_INCREMENT);
458 return STATUS_UNSUCCESSFUL;
459 }
460 if (m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
461 {
462 Irp->IoStatus.Information = m_Format->FormatSize;
463 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
464 IoCompleteRequest(Irp, IO_NO_INCREMENT);
465 return STATUS_BUFFER_TOO_SMALL;
466 }
467
468 RtlMoveMemory(DataFormat, m_Format, m_Format->FormatSize);
469 Irp->IoStatus.Information = DataFormat->FormatSize;
470 Irp->IoStatus.Status = STATUS_SUCCESS;
471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
472 return STATUS_SUCCESS;
473 }
474 }
475
476 }
477 RtlStringFromGUID(Property->Set, &GuidString);
478 DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
479 RtlFreeUnicodeString(&GuidString);
480
481 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
482 Irp->IoStatus.Information = 0;
483 IoCompleteRequest(Irp, IO_NO_INCREMENT);
484 return STATUS_NOT_IMPLEMENTED;
485 }
486
487 NTSTATUS
488 NTAPI
489 CPortPinWaveRT::HandleKsStream(
490 IN PIRP Irp)
491 {
492 DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", m_State, m_Stream);
493
494 return STATUS_PENDING;
495 }
496
497 NTSTATUS
498 NTAPI
499 CPortPinWaveRT::DeviceIoControl(
500 IN PDEVICE_OBJECT DeviceObject,
501 IN PIRP Irp)
502 {
503 PIO_STACK_LOCATION IoStack;
504
505 IoStack = IoGetCurrentIrpStackLocation(Irp);
506
507
508 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
509 {
510 return HandleKsProperty(Irp);
511 }
512 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
513 {
514 /// FIXME
515 /// handle enable event
516 }
517 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT)
518 {
519 /// FIXME
520 /// handle disable event
521 }
522 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
523 {
524 /// FIXME
525 /// handle reset state
526 }
527 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
528 {
529 return HandleKsStream(Irp);
530 }
531 else
532 {
533 return KsDefaultDeviceIoCompletion(DeviceObject, Irp);
534 }
535
536 UNIMPLEMENTED
537 DbgBreakPoint();
538
539 Irp->IoStatus.Information = 0;
540 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
541 IoCompleteRequest(Irp, IO_NO_INCREMENT);
542
543 return STATUS_UNSUCCESSFUL;
544 }
545
546 NTSTATUS
547 NTAPI
548 CPortPinWaveRT::Read(
549 IN PDEVICE_OBJECT DeviceObject,
550 IN PIRP Irp)
551 {
552 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
553 }
554
555 NTSTATUS
556 NTAPI
557 CPortPinWaveRT::Write(
558 IN PDEVICE_OBJECT DeviceObject,
559 IN PIRP Irp)
560 {
561 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
562 }
563
564 NTSTATUS
565 NTAPI
566 CPortPinWaveRT::Flush(
567 IN PDEVICE_OBJECT DeviceObject,
568 IN PIRP Irp)
569 {
570 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
571 }
572
573 VOID
574 NTAPI
575 CloseStreamRoutine(
576 IN PDEVICE_OBJECT DeviceObject,
577 IN PVOID Context)
578 {
579 PMINIPORTWAVERTSTREAM Stream;
580 NTSTATUS Status;
581 ISubdevice *ISubDevice;
582 PSUBDEVICE_DESCRIPTOR Descriptor;
583 CPortPinWaveRT * This;
584 PCLOSESTREAM_CONTEXT Ctx = (PCLOSESTREAM_CONTEXT)Context;
585
586 This = (CPortPinWaveRT*)Ctx->Pin;
587
588 if (This->m_Stream)
589 {
590 if (This->m_State != KSSTATE_STOP)
591 {
592 This->m_Stream->SetState(KSSTATE_STOP);
593 KeStallExecutionProcessor(10);
594 }
595 }
596
597 Status = This->m_Port->QueryInterface(IID_ISubdevice, (PVOID*)&ISubDevice);
598 if (NT_SUCCESS(Status))
599 {
600 Status = ISubDevice->GetDescriptor(&Descriptor);
601 if (NT_SUCCESS(Status))
602 {
603 Descriptor->Factory.Instances[This->m_ConnectDetails->PinId].CurrentPinInstanceCount--;
604 }
605 ISubDevice->Release();
606 }
607
608 if (This->m_Format)
609 {
610 ExFreePool(This->m_Format);
611 This->m_Format = NULL;
612 }
613
614 if (This->m_IrpQueue)
615 {
616 This->m_IrpQueue->Release();
617 }
618
619 // complete the irp
620 Ctx->Irp->IoStatus.Information = 0;
621 Ctx->Irp->IoStatus.Status = STATUS_SUCCESS;
622 IoCompleteRequest(Ctx->Irp, IO_NO_INCREMENT);
623
624 // free the work item
625 IoFreeWorkItem(Ctx->WorkItem);
626
627 // free work item ctx
628 FreeItem(Ctx, TAG_PORTCLASS);
629
630 if (This->m_Stream)
631 {
632 Stream = This->m_Stream;
633 This->m_Stream = NULL;
634 DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql());
635 Stream->Release();
636 }
637 }
638
639 NTSTATUS
640 NTAPI
641 CPortPinWaveRT::Close(
642 IN PDEVICE_OBJECT DeviceObject,
643 IN PIRP Irp)
644 {
645 PCLOSESTREAM_CONTEXT Ctx;
646
647 if (m_Stream)
648 {
649 Ctx = (PCLOSESTREAM_CONTEXT)AllocateItem(NonPagedPool, sizeof(CLOSESTREAM_CONTEXT), TAG_PORTCLASS);
650 if (!Ctx)
651 {
652 DPRINT1("Failed to allocate stream context\n");
653 goto cleanup;
654 }
655
656 Ctx->WorkItem = IoAllocateWorkItem(DeviceObject);
657 if (!Ctx->WorkItem)
658 {
659 DPRINT1("Failed to allocate work item\n");
660 goto cleanup;
661 }
662
663 Ctx->Irp = Irp;
664 Ctx->Pin = this;
665
666 IoMarkIrpPending(Irp);
667 Irp->IoStatus.Information = 0;
668 Irp->IoStatus.Status = STATUS_PENDING;
669
670 // defer work item
671 IoQueueWorkItem(Ctx->WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)Ctx);
672 // Return result
673 return STATUS_PENDING;
674 }
675
676 Irp->IoStatus.Information = 0;
677 Irp->IoStatus.Status = STATUS_SUCCESS;
678 IoCompleteRequest(Irp, IO_NO_INCREMENT);
679
680 return STATUS_SUCCESS;
681
682 cleanup:
683
684 if (Ctx)
685 FreeItem(Ctx, TAG_PORTCLASS);
686
687 Irp->IoStatus.Information = 0;
688 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
689 IoCompleteRequest(Irp, IO_NO_INCREMENT);
690 return STATUS_UNSUCCESSFUL;
691
692 }
693
694 NTSTATUS
695 NTAPI
696 CPortPinWaveRT::QuerySecurity(
697 IN PDEVICE_OBJECT DeviceObject,
698 IN PIRP Irp)
699 {
700 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
701 }
702
703 NTSTATUS
704 NTAPI
705 CPortPinWaveRT::SetSecurity(
706 IN PDEVICE_OBJECT DeviceObject,
707 IN PIRP Irp)
708 {
709 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
710 }
711
712 BOOLEAN
713 NTAPI
714 CPortPinWaveRT::FastDeviceIoControl(
715 IN PFILE_OBJECT FileObject,
716 IN BOOLEAN Wait,
717 IN PVOID InputBuffer,
718 IN ULONG InputBufferLength,
719 OUT PVOID OutputBuffer,
720 IN ULONG OutputBufferLength,
721 IN ULONG IoControlCode,
722 OUT PIO_STATUS_BLOCK StatusBlock,
723 IN PDEVICE_OBJECT DeviceObject)
724 {
725 return FALSE;
726 }
727
728 BOOLEAN
729 NTAPI
730 CPortPinWaveRT::FastRead(
731 IN PFILE_OBJECT FileObject,
732 IN PLARGE_INTEGER FileOffset,
733 IN ULONG Length,
734 IN BOOLEAN Wait,
735 IN ULONG LockKey,
736 IN PVOID Buffer,
737 OUT PIO_STATUS_BLOCK StatusBlock,
738 IN PDEVICE_OBJECT DeviceObject)
739 {
740 return FALSE;
741 }
742
743 BOOLEAN
744 NTAPI
745 CPortPinWaveRT::FastWrite(
746 IN PFILE_OBJECT FileObject,
747 IN PLARGE_INTEGER FileOffset,
748 IN ULONG Length,
749 IN BOOLEAN Wait,
750 IN ULONG LockKey,
751 IN PVOID Buffer,
752 OUT PIO_STATUS_BLOCK StatusBlock,
753 IN PDEVICE_OBJECT DeviceObject)
754 {
755 return FALSE;
756 }
757
758 NTSTATUS
759 NTAPI
760 CPortPinWaveRT::Init(
761 IN PPORTWAVERT Port,
762 IN PPORTFILTERWAVERT Filter,
763 IN KSPIN_CONNECT * ConnectDetails,
764 IN KSPIN_DESCRIPTOR * KsPinDescriptor,
765 IN PDEVICE_OBJECT DeviceObject)
766 {
767 NTSTATUS Status;
768 PKSDATAFORMAT DataFormat;
769 BOOL Capture;
770 KSRTAUDIO_HWLATENCY Latency;
771
772 Port->AddRef();
773 Filter->AddRef();
774
775 m_Port = Port;
776 m_Filter = Filter;
777 m_KsPinDescriptor = KsPinDescriptor;
778 m_ConnectDetails = ConnectDetails;
779 m_Miniport = GetWaveRTMiniport(Port);
780
781 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
782
783 DPRINT("CPortPinWaveRT::Init entered\n");
784
785 m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
786 if (!m_Format)
787 return STATUS_INSUFFICIENT_RESOURCES;
788
789 RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
790
791 Status = NewIrpQueue(&m_IrpQueue);
792 if (!NT_SUCCESS(Status))
793 {
794 goto cleanup;
795 }
796
797 Status = m_IrpQueue->Init(ConnectDetails, DataFormat, DeviceObject, 0, 0, NULL);
798 if (!NT_SUCCESS(Status))
799 {
800 goto cleanup;
801 }
802
803 Status = NewPortWaveRTStream(&m_PortStream);
804 if (!NT_SUCCESS(Status))
805 {
806 goto cleanup;
807 }
808
809 Status = PcNewServiceGroup(&m_ServiceGroup, NULL);
810 if (!NT_SUCCESS(Status))
811 {
812 goto cleanup;
813 }
814
815 m_ServiceGroup->AddMember(PSERVICESINK(this));
816 m_ServiceGroup->SupportDelayedService();
817
818 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
819 {
820 Capture = FALSE;
821 }
822 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
823 {
824 Capture = TRUE;
825 }
826 else
827 {
828 DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
829 KeBugCheck(0);
830 }
831
832 Status = m_Miniport->NewStream(&m_Stream, m_PortStream, ConnectDetails->PinId, Capture, m_Format);
833 DPRINT("CPortPinWaveRT::Init Status %x\n", Status);
834
835 if (!NT_SUCCESS(Status))
836 goto cleanup;
837
838 m_Stream->GetHWLatency(&Latency);
839 // delay of 10 milisec
840 m_Delay = Int32x32To64(10, -10000);
841
842 Status = m_Stream->AllocateAudioBuffer(16384 * 11, &m_Mdl, &m_CommonBufferSize, &m_CommonBufferOffset, &m_CacheType);
843 if (!NT_SUCCESS(Status))
844 {
845 DPRINT1("AllocateAudioBuffer failed with %x\n", Status);
846 goto cleanup;
847 }
848
849 m_CommonBuffer = MmGetSystemAddressForMdlSafe(m_Mdl, NormalPagePriority);
850 if (!NT_SUCCESS(Status))
851 {
852 DPRINT1("Failed to get system address %x\n", Status);
853 IoFreeMdl(m_Mdl);
854 m_Mdl = NULL;
855 goto cleanup;
856 }
857
858 DPRINT1("Setting state to acquire %x\n", m_Stream->SetState(KSSTATE_ACQUIRE));
859 DPRINT1("Setting state to pause %x\n", m_Stream->SetState(KSSTATE_PAUSE));
860 m_State = KSSTATE_PAUSE;
861 return STATUS_SUCCESS;
862
863 cleanup:
864 if (m_IrpQueue)
865 {
866 m_IrpQueue->Release();
867 m_IrpQueue = NULL;
868 }
869
870 if (m_Format)
871 {
872 FreeItem(m_Format, TAG_PORTCLASS);
873 m_Format = NULL;
874 }
875
876 if (m_Stream)
877 {
878 m_Stream->Release();
879 m_Stream = NULL;
880 }
881 else
882 {
883 if (m_PortStream)
884 {
885 m_PortStream->Release();
886 m_PortStream = NULL;
887 }
888
889 }
890 return Status;
891 }
892
893
894 NTSTATUS
895 NewPortPinWaveRT(
896 OUT IPortPinWaveRT ** OutPin)
897 {
898 CPortPinWaveRT * This;
899
900 This = new(NonPagedPool, TAG_PORTCLASS) CPortPinWaveRT(NULL);
901 if (!This)
902 return STATUS_INSUFFICIENT_RESOURCES;
903
904 This->AddRef();
905
906 // store result
907 *OutPin = (PPORTPINWAVERT)This;
908
909 return STATUS_SUCCESS;
910 }