winsta: fix spec file
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / pin_wavert.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/pin_wavert.c
5 * PURPOSE: WaveRT IRP Audio Pin
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.h"
10
11 typedef struct
12 {
13 IPortPinWaveRTVtbl *lpVtbl;
14 IServiceSinkVtbl *lpVtblServiceSink;
15 LONG ref;
16
17 IPortWaveRT * Port;
18 IPortFilterWaveRT * Filter;
19 KSPIN_DESCRIPTOR * KsPinDescriptor;
20 PMINIPORTWAVERT Miniport;
21 PMINIPORTWAVERTSTREAM Stream;
22 PPORTWAVERTSTREAM PortStream;
23 PSERVICEGROUP ServiceGroup;
24 KSSTATE State;
25 PKSDATAFORMAT Format;
26 KSPIN_CONNECT * ConnectDetails;
27
28 PVOID CommonBuffer;
29 ULONG CommonBufferSize;
30 ULONG CommonBufferOffset;
31
32 IIrpQueue * IrpQueue;
33
34 BOOL Capture;
35
36 ULONG TotalPackets;
37 ULONG PreCompleted;
38 ULONG PostCompleted;
39
40 ULONGLONG Delay;
41
42 MEMORY_CACHING_TYPE CacheType;
43 PMDL Mdl;
44
45 }IPortPinWaveRTImpl;
46
47
48 typedef struct
49 {
50 IPortPinWaveRTImpl *Pin;
51 PIO_WORKITEM WorkItem;
52 KSSTATE State;
53 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
54
55 static
56 VOID
57 NTAPI
58 SetStreamState(
59 IN IPortPinWaveRTImpl * This,
60 IN KSSTATE State);
61
62 static
63 VOID
64 UpdateCommonBuffer(
65 IPortPinWaveRTImpl * This,
66 ULONG Position)
67 {
68 ULONG BufferLength;
69 ULONG BytesToCopy;
70 ULONG BufferSize;
71 PUCHAR Buffer;
72 NTSTATUS Status;
73
74 BufferLength = Position - This->CommonBufferOffset;
75 while(BufferLength)
76 {
77 Status = This->IrpQueue->lpVtbl->GetMapping(This->IrpQueue, &Buffer, &BufferSize);
78 if (!NT_SUCCESS(Status))
79 return;
80
81 BytesToCopy = min(BufferLength, BufferSize);
82
83 if (This->Capture)
84 {
85 RtlMoveMemory(Buffer, (PUCHAR)This->CommonBuffer + This->CommonBufferOffset, BytesToCopy);
86 }
87 else
88 {
89 RtlMoveMemory((PUCHAR)This->CommonBuffer + This->CommonBufferOffset, Buffer, BytesToCopy);
90 }
91
92 This->IrpQueue->lpVtbl->UpdateMapping(This->IrpQueue, BytesToCopy);
93 This->CommonBufferOffset += BytesToCopy;
94
95 BufferLength = Position - This->CommonBufferOffset;
96 }
97 }
98
99 static
100 VOID
101 UpdateCommonBufferOverlap(
102 IPortPinWaveRTImpl * This,
103 ULONG Position)
104 {
105 ULONG BufferLength;
106 ULONG BytesToCopy;
107 ULONG BufferSize;
108 PUCHAR Buffer;
109 NTSTATUS Status;
110
111
112 BufferLength = This->CommonBufferSize - This->CommonBufferOffset;
113 while(BufferLength)
114 {
115 Status = This->IrpQueue->lpVtbl->GetMapping(This->IrpQueue, &Buffer, &BufferSize);
116 if (!NT_SUCCESS(Status))
117 return;
118
119 BytesToCopy = min(BufferLength, BufferSize);
120
121 if (This->Capture)
122 {
123 RtlMoveMemory(Buffer, (PUCHAR)This->CommonBuffer + This->CommonBufferOffset, BytesToCopy);
124 }
125 else
126 {
127 RtlMoveMemory((PUCHAR)This->CommonBuffer + This->CommonBufferOffset, Buffer, BytesToCopy);
128 }
129
130 This->IrpQueue->lpVtbl->UpdateMapping(This->IrpQueue, BytesToCopy);
131 This->CommonBufferOffset += BytesToCopy;
132
133 BufferLength = This->CommonBufferSize - This->CommonBufferOffset;
134 }
135 This->CommonBufferOffset = 0;
136 UpdateCommonBuffer(This, Position);
137 }
138
139
140
141 //==================================================================================================================================
142 static
143 NTSTATUS
144 NTAPI
145 IServiceSink_fnQueryInterface(
146 IServiceSink* iface,
147 IN REFIID refiid,
148 OUT PVOID* Output)
149 {
150 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink);
151
152 DPRINT("IServiceSink_fnQueryInterface entered\n");
153
154 if (IsEqualGUIDAligned(refiid, &IID_IServiceSink) ||
155 IsEqualGUIDAligned(refiid, &IID_IUnknown))
156 {
157 *Output = &This->lpVtblServiceSink;
158 InterlockedIncrement(&This->ref);
159 return STATUS_SUCCESS;
160 }
161 return STATUS_UNSUCCESSFUL;
162 }
163
164 static
165 ULONG
166 NTAPI
167 IServiceSink_fnAddRef(
168 IServiceSink* iface)
169 {
170 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink);
171 DPRINT("IServiceSink_fnAddRef entered\n");
172
173 return InterlockedIncrement(&This->ref);
174 }
175
176 static
177 ULONG
178 NTAPI
179 IServiceSink_fnRelease(
180 IServiceSink* iface)
181 {
182 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink);
183
184 InterlockedDecrement(&This->ref);
185
186 DPRINT("IServiceSink_fnRelease entered %u\n", This->ref);
187
188 if (This->ref == 0)
189 {
190 FreeItem(This, TAG_PORTCLASS);
191 return 0;
192 }
193 /* Return new reference count */
194 return This->ref;
195 }
196
197 static
198 VOID
199 NTAPI
200 IServiceSink_fnRequestService(
201 IServiceSink* iface)
202 {
203 KSAUDIO_POSITION Position;
204 NTSTATUS Status;
205 PUCHAR Buffer;
206 ULONG BufferSize;
207 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)CONTAINING_RECORD(iface, IPortPinWaveRTImpl, lpVtblServiceSink);
208
209 ASSERT_IRQL(DISPATCH_LEVEL);
210
211 Status = This->IrpQueue->lpVtbl->GetMapping(This->IrpQueue, &Buffer, &BufferSize);
212 if (!NT_SUCCESS(Status))
213 {
214 SetStreamState(This, KSSTATE_STOP);
215 return;
216 }
217
218 Status = This->Stream->lpVtbl->GetPosition(This->Stream, &Position);
219 DPRINT("PlayOffset %lu WriteOffset %lu Buffer %p BufferSize %u CommonBufferSize %u\n", Position.PlayOffset, Position.WriteOffset, Buffer, BufferSize, This->CommonBufferSize);
220
221 if (Position.PlayOffset < This->CommonBufferOffset)
222 {
223 UpdateCommonBufferOverlap(This, Position.PlayOffset);
224 }
225 else if (Position.PlayOffset >= This->CommonBufferOffset)
226 {
227 UpdateCommonBuffer(This, Position.PlayOffset);
228 }
229 }
230
231 static IServiceSinkVtbl vt_IServiceSink =
232 {
233 IServiceSink_fnQueryInterface,
234 IServiceSink_fnAddRef,
235 IServiceSink_fnRelease,
236 IServiceSink_fnRequestService
237 };
238
239
240 static
241 VOID
242 NTAPI
243 SetStreamWorkerRoutine(
244 IN PDEVICE_OBJECT DeviceObject,
245 IN PVOID Context)
246 {
247 IPortPinWaveRTImpl * This;
248 PSETSTREAM_CONTEXT Ctx = (PSETSTREAM_CONTEXT)Context;
249 KSSTATE State;
250
251 This = Ctx->Pin;
252 State = Ctx->State;
253
254 IoFreeWorkItem(Ctx->WorkItem);
255 FreeItem(Ctx, TAG_PORTCLASS);
256
257 /* Has the audio stream resumed? */
258 if (This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue) && State == KSSTATE_STOP)
259 return;
260
261 /* Set the state */
262 if (NT_SUCCESS(This->Stream->lpVtbl->SetState(This->Stream, State)))
263 {
264 /* Set internal state to stop */
265 This->State = State;
266
267 if (This->State == KSSTATE_STOP)
268 {
269 /* reset start stream */
270 This->IrpQueue->lpVtbl->CancelBuffers(This->IrpQueue); //FIX function name
271 This->ServiceGroup->lpVtbl->CancelDelayedService(This->ServiceGroup);
272 DPRINT1("Stopping PreCompleted %u PostCompleted %u\n", This->PreCompleted, This->PostCompleted);
273 }
274
275 if (This->State == KSSTATE_RUN)
276 {
277 /* start the notification timer */
278 This->ServiceGroup->lpVtbl->RequestDelayedService(This->ServiceGroup, This->Delay);
279 }
280 }
281 }
282
283 static
284 VOID
285 NTAPI
286 SetStreamState(
287 IN IPortPinWaveRTImpl * This,
288 IN KSSTATE State)
289 {
290 PDEVICE_OBJECT DeviceObject;
291 PIO_WORKITEM WorkItem;
292 PSETSTREAM_CONTEXT Context;
293
294 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
295
296 /* Has the audio stream resumed? */
297 if (This->IrpQueue->lpVtbl->NumMappings(This->IrpQueue) && State == KSSTATE_STOP)
298 return;
299
300 /* Has the audio state already been set? */
301 if (This->State == State)
302 return;
303
304 /* Get device object */
305 DeviceObject = GetDeviceObjectFromPortWaveRT(This->Port);
306
307 /* allocate set state context */
308 Context = AllocateItem(NonPagedPool, sizeof(SETSTREAM_CONTEXT), TAG_PORTCLASS);
309
310 if (!Context)
311 return;
312
313 /* allocate work item */
314 WorkItem = IoAllocateWorkItem(DeviceObject);
315
316 if (!WorkItem)
317 {
318 ExFreePool(Context);
319 return;
320 }
321
322 Context->Pin = (PVOID)This;
323 Context->WorkItem = WorkItem;
324 Context->State = State;
325
326 /* queue the work item */
327 IoQueueWorkItem(WorkItem, SetStreamWorkerRoutine, DelayedWorkQueue, (PVOID)Context);
328 }
329
330 //==================================================================================================================================
331 /*
332 * @implemented
333 */
334 NTSTATUS
335 NTAPI
336 IPortPinWaveRT_fnQueryInterface(
337 IPortPinWaveRT* iface,
338 IN REFIID refiid,
339 OUT PVOID* Output)
340 {
341 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
342
343 if (IsEqualGUIDAligned(refiid, &IID_IIrpTarget) ||
344 IsEqualGUIDAligned(refiid, &IID_IUnknown))
345 {
346 *Output = &This->lpVtbl;
347 InterlockedIncrement(&This->ref);
348 return STATUS_SUCCESS;
349 }
350
351 return STATUS_UNSUCCESSFUL;
352 }
353
354 /*
355 * @implemented
356 */
357 ULONG
358 NTAPI
359 IPortPinWaveRT_fnAddRef(
360 IPortPinWaveRT* iface)
361 {
362 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
363
364 return InterlockedIncrement(&This->ref);
365 }
366
367 /*
368 * @implemented
369 */
370 ULONG
371 NTAPI
372 IPortPinWaveRT_fnRelease(
373 IPortPinWaveRT* iface)
374 {
375 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
376
377 InterlockedDecrement(&This->ref);
378
379 if (This->ref == 0)
380 {
381 FreeItem(This, TAG_PORTCLASS);
382 return 0;
383 }
384 return This->ref;
385 }
386
387 /*
388 * @unimplemented
389 */
390 NTSTATUS
391 NTAPI
392 IPortPinWaveRT_fnNewIrpTarget(
393 IN IPortPinWaveRT* iface,
394 OUT struct IIrpTarget **OutTarget,
395 IN WCHAR * Name,
396 IN PUNKNOWN Unknown,
397 IN POOL_TYPE PoolType,
398 IN PDEVICE_OBJECT DeviceObject,
399 IN PIRP Irp,
400 IN KSOBJECT_CREATE *CreateObject)
401 {
402 UNIMPLEMENTED
403 return STATUS_UNSUCCESSFUL;
404 }
405
406 NTSTATUS
407 NTAPI
408 IPortPinWaveRT_HandleKsProperty(
409 IN IPortPinWaveRT * iface,
410 IN PIRP Irp)
411 {
412 PKSPROPERTY Property;
413 NTSTATUS Status;
414 UNICODE_STRING GuidString;
415 PIO_STACK_LOCATION IoStack;
416 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
417
418 IoStack = IoGetCurrentIrpStackLocation(Irp);
419
420 DPRINT("IPortPinWave_HandleKsProperty entered\n");
421
422 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
423 {
424 Irp->IoStatus.Information = 0;
425 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
426 IoCompleteRequest(Irp, IO_NO_INCREMENT);
427 return STATUS_INVALID_PARAMETER;
428 }
429
430 Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
431
432 if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Connection))
433 {
434 if (Property->Id == KSPROPERTY_CONNECTION_STATE)
435 {
436 PKSSTATE State = (PKSSTATE)Irp->UserBuffer;
437
438 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSSTATE))
439 {
440 Irp->IoStatus.Information = sizeof(KSSTATE);
441 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
442 IoCompleteRequest(Irp, IO_NO_INCREMENT);
443 return STATUS_BUFFER_TOO_SMALL;
444 }
445
446 if (Property->Flags & KSPROPERTY_TYPE_SET)
447 {
448 Status = STATUS_UNSUCCESSFUL;
449 Irp->IoStatus.Information = 0;
450
451 if (This->Stream)
452 {
453 Status = This->Stream->lpVtbl->SetState(This->Stream, *State);
454
455 DPRINT1("Setting state %u %x\n", *State, Status);
456 if (NT_SUCCESS(Status))
457 {
458 This->State = *State;
459 }
460 }
461 Irp->IoStatus.Status = Status;
462 IoCompleteRequest(Irp, IO_NO_INCREMENT);
463 return Status;
464 }
465 else if (Property->Flags & KSPROPERTY_TYPE_GET)
466 {
467 *State = This->State;
468 Irp->IoStatus.Information = sizeof(KSSTATE);
469 Irp->IoStatus.Status = STATUS_SUCCESS;
470 IoCompleteRequest(Irp, IO_NO_INCREMENT);
471 return STATUS_SUCCESS;
472 }
473 }
474 else if (Property->Id == KSPROPERTY_CONNECTION_DATAFORMAT)
475 {
476 PKSDATAFORMAT DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
477 if (Property->Flags & KSPROPERTY_TYPE_SET)
478 {
479 PKSDATAFORMAT NewDataFormat;
480 if (!RtlCompareMemory(DataFormat, This->Format, DataFormat->FormatSize))
481 {
482 Irp->IoStatus.Information = DataFormat->FormatSize;
483 Irp->IoStatus.Status = STATUS_SUCCESS;
484 IoCompleteRequest(Irp, IO_NO_INCREMENT);
485 return STATUS_SUCCESS;
486 }
487
488 NewDataFormat = AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
489 if (!NewDataFormat)
490 {
491 Irp->IoStatus.Information = 0;
492 Irp->IoStatus.Status = STATUS_NO_MEMORY;
493 IoCompleteRequest(Irp, IO_NO_INCREMENT);
494 return STATUS_NO_MEMORY;
495 }
496 RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
497
498 if (This->Stream)
499 {
500 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
501 ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
502 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO));
503 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM));
504 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
505
506 ASSERT(This->State == KSSTATE_STOP);
507 DPRINT1("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
508 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
509 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
510
511 Status = This->Stream->lpVtbl->SetFormat(This->Stream, NewDataFormat);
512 if (NT_SUCCESS(Status))
513 {
514 if (This->Format)
515 ExFreePoolWithTag(This->Format, TAG_PORTCLASS);
516
517 This->IrpQueue->lpVtbl->UpdateFormat(This->IrpQueue, (PKSDATAFORMAT)NewDataFormat);
518 This->Format = NewDataFormat;
519 Irp->IoStatus.Information = DataFormat->FormatSize;
520 Irp->IoStatus.Status = STATUS_SUCCESS;
521 IoCompleteRequest(Irp, IO_NO_INCREMENT);
522 return STATUS_SUCCESS;
523 }
524 }
525 DPRINT1("Failed to set format\n");
526 Irp->IoStatus.Information = 0;
527 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
528 IoCompleteRequest(Irp, IO_NO_INCREMENT);
529 return STATUS_UNSUCCESSFUL;
530 }
531 else if (Property->Flags & KSPROPERTY_TYPE_GET)
532 {
533 if (!This->Format)
534 {
535 DPRINT1("No format\n");
536 Irp->IoStatus.Information = 0;
537 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
538 IoCompleteRequest(Irp, IO_NO_INCREMENT);
539 return STATUS_UNSUCCESSFUL;
540 }
541 if (This->Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
542 {
543 Irp->IoStatus.Information = This->Format->FormatSize;
544 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
545 IoCompleteRequest(Irp, IO_NO_INCREMENT);
546 return STATUS_BUFFER_TOO_SMALL;
547 }
548
549 RtlMoveMemory(DataFormat, This->Format, This->Format->FormatSize);
550 Irp->IoStatus.Information = DataFormat->FormatSize;
551 Irp->IoStatus.Status = STATUS_SUCCESS;
552 IoCompleteRequest(Irp, IO_NO_INCREMENT);
553 return STATUS_SUCCESS;
554 }
555 }
556
557 }
558 RtlStringFromGUID(&Property->Set, &GuidString);
559 DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
560 DbgBreakPoint();
561 RtlFreeUnicodeString(&GuidString);
562
563 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
564 Irp->IoStatus.Information = 0;
565 IoCompleteRequest(Irp, IO_NO_INCREMENT);
566 return STATUS_NOT_IMPLEMENTED;
567 }
568
569 NTSTATUS
570 NTAPI
571 IPortPinWaveRT_HandleKsStream(
572 IN IPortPinWaveRT * iface,
573 IN PIRP Irp)
574 {
575 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
576
577 DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", This->State, This->Stream);
578
579 return STATUS_PENDING;
580 }
581
582 /*
583 * @unimplemented
584 */
585 NTSTATUS
586 NTAPI
587 IPortPinWaveRT_fnDeviceIoControl(
588 IN IPortPinWaveRT* iface,
589 IN PDEVICE_OBJECT DeviceObject,
590 IN PIRP Irp)
591 {
592 PIO_STACK_LOCATION IoStack;
593
594 IoStack = IoGetCurrentIrpStackLocation(Irp);
595
596
597 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
598 {
599 return IPortPinWaveRT_HandleKsProperty(iface, Irp);
600 }
601 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
602 {
603 /// FIXME
604 /// handle enable event
605 }
606 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT)
607 {
608 /// FIXME
609 /// handle disable event
610 }
611 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
612 {
613 /// FIXME
614 /// handle reset state
615 }
616 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
617 {
618 return IPortPinWaveRT_HandleKsStream(iface, Irp);
619 }
620 else
621 {
622 return KsDefaultDeviceIoCompletion(DeviceObject, Irp);
623 }
624
625 UNIMPLEMENTED
626 DbgBreakPoint();
627
628 Irp->IoStatus.Information = 0;
629 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
630 IoCompleteRequest(Irp, IO_NO_INCREMENT);
631
632 return STATUS_UNSUCCESSFUL;
633 }
634
635 /*
636 * @implemented
637 */
638 NTSTATUS
639 NTAPI
640 IPortPinWaveRT_fnRead(
641 IN IPortPinWaveRT* iface,
642 IN PDEVICE_OBJECT DeviceObject,
643 IN PIRP Irp)
644 {
645 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
646 }
647
648 /*
649 * @implemented
650 */
651 NTSTATUS
652 NTAPI
653 IPortPinWaveRT_fnWrite(
654 IN IPortPinWaveRT* iface,
655 IN PDEVICE_OBJECT DeviceObject,
656 IN PIRP Irp)
657 {
658 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
659 }
660
661 /*
662 * @implemented
663 */
664 NTSTATUS
665 NTAPI
666 IPortPinWaveRT_fnFlush(
667 IN IPortPinWaveRT* iface,
668 IN PDEVICE_OBJECT DeviceObject,
669 IN PIRP Irp)
670 {
671 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
672 }
673
674 static
675 VOID
676 NTAPI
677 CloseStreamRoutine(
678 IN PDEVICE_OBJECT DeviceObject,
679 IN PVOID Context)
680 {
681 PMINIPORTWAVERTSTREAM Stream;
682 NTSTATUS Status;
683 ISubdevice *ISubDevice;
684 PSUBDEVICE_DESCRIPTOR Descriptor;
685 IPortPinWaveRTImpl * This;
686 PCLOSESTREAM_CONTEXT Ctx = (PCLOSESTREAM_CONTEXT)Context;
687
688 This = (IPortPinWaveRTImpl*)Ctx->Pin;
689
690 if (This->Stream)
691 {
692 if (This->State != KSSTATE_STOP)
693 {
694 This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
695 KeStallExecutionProcessor(10);
696 }
697 }
698
699 Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice);
700 if (NT_SUCCESS(Status))
701 {
702 Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor);
703 if (NT_SUCCESS(Status))
704 {
705 Descriptor->Factory.Instances[This->ConnectDetails->PinId].CurrentPinInstanceCount--;
706 }
707 ISubDevice->lpVtbl->Release(ISubDevice);
708 }
709
710 if (This->Format)
711 {
712 ExFreePool(This->Format);
713 This->Format = NULL;
714 }
715
716 if (This->IrpQueue)
717 {
718 This->IrpQueue->lpVtbl->Release(This->IrpQueue);
719 }
720
721 /* complete the irp */
722 Ctx->Irp->IoStatus.Information = 0;
723 Ctx->Irp->IoStatus.Status = STATUS_SUCCESS;
724 IoCompleteRequest(Ctx->Irp, IO_NO_INCREMENT);
725
726 /* free the work item */
727 IoFreeWorkItem(Ctx->WorkItem);
728
729 /* free work item ctx */
730 FreeItem(Ctx, TAG_PORTCLASS);
731
732 if (This->Stream)
733 {
734 Stream = This->Stream;
735 This->Stream = NULL;
736 DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql());
737 Stream->lpVtbl->Release(Stream);
738 }
739 }
740
741 /*
742 * @implemented
743 */
744 NTSTATUS
745 NTAPI
746 IPortPinWaveRT_fnClose(
747 IN IPortPinWaveRT* iface,
748 IN PDEVICE_OBJECT DeviceObject,
749 IN PIRP Irp)
750 {
751 PCLOSESTREAM_CONTEXT Ctx;
752 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
753
754 if (This->Stream)
755 {
756 Ctx = AllocateItem(NonPagedPool, sizeof(CLOSESTREAM_CONTEXT), TAG_PORTCLASS);
757 if (!Ctx)
758 {
759 DPRINT1("Failed to allocate stream context\n");
760 goto cleanup;
761 }
762
763 Ctx->WorkItem = IoAllocateWorkItem(DeviceObject);
764 if (!Ctx->WorkItem)
765 {
766 DPRINT1("Failed to allocate work item\n");
767 goto cleanup;
768 }
769
770 Ctx->Irp = Irp;
771 Ctx->Pin = (PVOID)This;
772
773 IoMarkIrpPending(Irp);
774 Irp->IoStatus.Information = 0;
775 Irp->IoStatus.Status = STATUS_PENDING;
776
777 /* defer work item */
778 IoQueueWorkItem(Ctx->WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)Ctx);
779 /* Return result */
780 return STATUS_PENDING;
781 }
782
783 Irp->IoStatus.Information = 0;
784 Irp->IoStatus.Status = STATUS_SUCCESS;
785 IoCompleteRequest(Irp, IO_NO_INCREMENT);
786
787 return STATUS_SUCCESS;
788
789 cleanup:
790
791 if (Ctx)
792 FreeItem(Ctx, TAG_PORTCLASS);
793
794 Irp->IoStatus.Information = 0;
795 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
796 IoCompleteRequest(Irp, IO_NO_INCREMENT);
797 return STATUS_UNSUCCESSFUL;
798
799 }
800
801 /*
802 * @implemented
803 */
804 NTSTATUS
805 NTAPI
806 IPortPinWaveRT_fnQuerySecurity(
807 IN IPortPinWaveRT* iface,
808 IN PDEVICE_OBJECT DeviceObject,
809 IN PIRP Irp)
810 {
811 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
812 }
813
814 /*
815 * @implemented
816 */
817 NTSTATUS
818 NTAPI
819 IPortPinWaveRT_fnSetSecurity(
820 IN IPortPinWaveRT* iface,
821 IN PDEVICE_OBJECT DeviceObject,
822 IN PIRP Irp)
823 {
824 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
825 }
826
827 /*
828 * @implemented
829 */
830 BOOLEAN
831 NTAPI
832 IPortPinWaveRT_fnFastDeviceIoControl(
833 IN IPortPinWaveRT* iface,
834 IN PFILE_OBJECT FileObject,
835 IN BOOLEAN Wait,
836 IN PVOID InputBuffer,
837 IN ULONG InputBufferLength,
838 OUT PVOID OutputBuffer,
839 IN ULONG OutputBufferLength,
840 IN ULONG IoControlCode,
841 OUT PIO_STATUS_BLOCK StatusBlock,
842 IN PDEVICE_OBJECT DeviceObject)
843 {
844 UNIMPLEMENTED
845 return FALSE;
846 }
847
848 /*
849 * @implemented
850 */
851 BOOLEAN
852 NTAPI
853 IPortPinWaveRT_fnFastRead(
854 IN IPortPinWaveRT* iface,
855 IN PFILE_OBJECT FileObject,
856 IN PLARGE_INTEGER FileOffset,
857 IN ULONG Length,
858 IN BOOLEAN Wait,
859 IN ULONG LockKey,
860 IN PVOID Buffer,
861 OUT PIO_STATUS_BLOCK StatusBlock,
862 IN PDEVICE_OBJECT DeviceObject)
863 {
864 NTSTATUS Status;
865 PCONTEXT_WRITE Packet;
866 PIRP Irp;
867 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
868
869 DPRINT("IPortPinWaveRT_fnFastRead entered\n");
870
871 Packet = (PCONTEXT_WRITE)Buffer;
872
873 Irp = Packet->Irp;
874 StatusBlock->Status = STATUS_PENDING;
875
876 Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp);
877
878 if (!NT_SUCCESS(Status))
879 return FALSE;
880
881 StatusBlock->Status = STATUS_PENDING;
882 return TRUE;
883 }
884
885 /*
886 * @implemented
887 */
888 BOOLEAN
889 NTAPI
890 IPortPinWaveRT_fnFastWrite(
891 IN IPortPinWaveRT* iface,
892 IN PFILE_OBJECT FileObject,
893 IN PLARGE_INTEGER FileOffset,
894 IN ULONG Length,
895 IN BOOLEAN Wait,
896 IN ULONG LockKey,
897 IN PVOID Buffer,
898 OUT PIO_STATUS_BLOCK StatusBlock,
899 IN PDEVICE_OBJECT DeviceObject)
900 {
901 NTSTATUS Status;
902 PCONTEXT_WRITE Packet;
903 PIRP Irp;
904 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
905
906 InterlockedIncrement((PLONG)&This->TotalPackets);
907
908 DPRINT("IPortPinWaveRT_fnFastWrite entered Total %u Pre %u Post %u\n", This->TotalPackets, This->PreCompleted, This->PostCompleted);
909
910 Packet = (PCONTEXT_WRITE)Buffer;
911
912
913 if (This->IrpQueue->lpVtbl->MinimumDataAvailable(This->IrpQueue))
914 {
915 Irp = Packet->Irp;
916 StatusBlock->Status = STATUS_PENDING;
917 InterlockedIncrement((PLONG)&This->PostCompleted);
918 }
919 else
920 {
921 Irp = NULL;
922 Packet->Irp->IoStatus.Status = STATUS_SUCCESS;
923 Packet->Irp->IoStatus.Information = Packet->Header.FrameExtent;
924 IoCompleteRequest(Packet->Irp, IO_SOUND_INCREMENT);
925 StatusBlock->Status = STATUS_SUCCESS;
926 InterlockedIncrement((PLONG)&This->PreCompleted);
927 }
928
929 Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp);
930
931 if (!NT_SUCCESS(Status))
932 return FALSE;
933
934 StatusBlock->Status = STATUS_PENDING;
935 return TRUE;
936 }
937
938 /*
939 * @unimplemented
940 */
941 NTSTATUS
942 NTAPI
943 IPortPinWaveRT_fnInit(
944 IN IPortPinWaveRT* iface,
945 IN PPORTWAVERT Port,
946 IN PPORTFILTERWAVERT Filter,
947 IN KSPIN_CONNECT * ConnectDetails,
948 IN KSPIN_DESCRIPTOR * KsPinDescriptor,
949 IN PDEVICE_OBJECT DeviceObject)
950 {
951 NTSTATUS Status;
952 PKSDATAFORMAT DataFormat;
953 BOOL Capture;
954 KSRTAUDIO_HWLATENCY Latency;
955 IPortPinWaveRTImpl * This = (IPortPinWaveRTImpl*)iface;
956
957 Port->lpVtbl->AddRef(Port);
958 Filter->lpVtbl->AddRef(Filter);
959
960 This->Port = Port;
961 This->Filter = Filter;
962 This->KsPinDescriptor = KsPinDescriptor;
963 This->ConnectDetails = ConnectDetails;
964 This->Miniport = GetWaveRTMiniport(Port);
965
966 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
967
968 DPRINT("IPortPinWaveRT_fnInit entered\n");
969
970 This->Format = AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
971 if (!This->Format)
972 return STATUS_INSUFFICIENT_RESOURCES;
973
974 RtlMoveMemory(This->Format, DataFormat, DataFormat->FormatSize);
975
976 Status = NewIrpQueue(&This->IrpQueue);
977 if (!NT_SUCCESS(Status))
978 {
979 goto cleanup;
980 }
981
982 Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, 0, 0, NULL);
983 if (!NT_SUCCESS(Status))
984 {
985 goto cleanup;
986 }
987
988 Status = NewPortWaveRTStream(&This->PortStream);
989 if (!NT_SUCCESS(Status))
990 {
991 goto cleanup;
992 }
993
994 Status = PcNewServiceGroup(&This->ServiceGroup, NULL);
995 if (!NT_SUCCESS(Status))
996 {
997 goto cleanup;
998 }
999
1000 This->ServiceGroup->lpVtbl->AddMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink);
1001 This->ServiceGroup->lpVtbl->SupportDelayedService(This->ServiceGroup);
1002
1003 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
1004 {
1005 Capture = FALSE;
1006 }
1007 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
1008 {
1009 Capture = TRUE;
1010 }
1011 else
1012 {
1013 DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
1014 KeBugCheck(0);
1015 }
1016
1017 Status = This->Miniport->lpVtbl->NewStream(This->Miniport,
1018 &This->Stream,
1019 This->PortStream,
1020 ConnectDetails->PinId,
1021 Capture,
1022 This->Format);
1023 DPRINT("IPortPinWaveRT_fnInit Status %x\n", Status);
1024
1025 if (!NT_SUCCESS(Status))
1026 goto cleanup;
1027
1028 This->Stream->lpVtbl->GetHWLatency(This->Stream, &Latency);
1029 /* delay of 10 milisec */
1030 This->Delay = Int32x32To64(10, -10000);
1031
1032 Status = This->Stream->lpVtbl->AllocateAudioBuffer(This->Stream, 16384 * 11, &This->Mdl, &This->CommonBufferSize, &This->CommonBufferOffset, &This->CacheType);
1033 if (!NT_SUCCESS(Status))
1034 {
1035 DPRINT1("AllocateAudioBuffer failed with %x\n", Status);
1036 goto cleanup;
1037 }
1038
1039 This->CommonBuffer = MmGetSystemAddressForMdlSafe(This->Mdl, NormalPagePriority);
1040 if (!NT_SUCCESS(Status))
1041 {
1042 DPRINT1("Failed to get system address %x\n", Status);
1043 IoFreeMdl(This->Mdl);
1044 This->Mdl = NULL;
1045 goto cleanup;
1046 }
1047
1048 DPRINT1("Setting state to acquire %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_ACQUIRE));
1049 DPRINT1("Setting state to pause %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_PAUSE));
1050 This->State = KSSTATE_PAUSE;
1051 return STATUS_SUCCESS;
1052
1053 cleanup:
1054 if (This->IrpQueue)
1055 {
1056 This->IrpQueue->lpVtbl->Release(This->IrpQueue);
1057 This->IrpQueue = NULL;
1058 }
1059
1060 if (This->Format)
1061 {
1062 FreeItem(This->Format, TAG_PORTCLASS);
1063 This->Format = NULL;
1064 }
1065
1066 if (This->ServiceGroup)
1067 {
1068 This->ServiceGroup->lpVtbl->Release(This->ServiceGroup);
1069 This->ServiceGroup = NULL;
1070 }
1071
1072 if (This->Stream)
1073 {
1074 This->Stream->lpVtbl->Release(This->Stream);
1075 This->Stream = NULL;
1076 }
1077 else
1078 {
1079 if (This->PortStream)
1080 {
1081 This->PortStream->lpVtbl->Release(This->PortStream);
1082 This->PortStream = NULL;
1083 }
1084
1085 }
1086 return Status;
1087 }
1088
1089 static IPortPinWaveRTVtbl vt_IPortPinWaveRT =
1090 {
1091 IPortPinWaveRT_fnQueryInterface,
1092 IPortPinWaveRT_fnAddRef,
1093 IPortPinWaveRT_fnRelease,
1094 IPortPinWaveRT_fnNewIrpTarget,
1095 IPortPinWaveRT_fnDeviceIoControl,
1096 IPortPinWaveRT_fnRead,
1097 IPortPinWaveRT_fnWrite,
1098 IPortPinWaveRT_fnFlush,
1099 IPortPinWaveRT_fnClose,
1100 IPortPinWaveRT_fnQuerySecurity,
1101 IPortPinWaveRT_fnSetSecurity,
1102 IPortPinWaveRT_fnFastDeviceIoControl,
1103 IPortPinWaveRT_fnFastRead,
1104 IPortPinWaveRT_fnFastWrite,
1105 IPortPinWaveRT_fnInit
1106 };
1107
1108 NTSTATUS NewPortPinWaveRT(
1109 OUT IPortPinWaveRT ** OutPin)
1110 {
1111 IPortPinWaveRTImpl * This;
1112
1113 This = AllocateItem(NonPagedPool, sizeof(IPortPinWaveRTImpl), TAG_PORTCLASS);
1114 if (!This)
1115 return STATUS_INSUFFICIENT_RESOURCES;
1116
1117 /* initialize IPortPinWaveRT */
1118 This->ref = 1;
1119 This->lpVtbl = &vt_IPortPinWaveRT;
1120 This->lpVtblServiceSink = &vt_IServiceSink;
1121
1122 /* store result */
1123 *OutPin = (IPortPinWaveRT*)&This->lpVtbl;
1124
1125 return STATUS_SUCCESS;
1126 }