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