[KS]
[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 return STATUS_PENDING;
644 }
645
646 /*
647 * @unimplemented
648 */
649 NTSTATUS
650 NTAPI
651 IPortPinWaveCyclic_fnDeviceIoControl(
652 IN IPortPinWaveCyclic* iface,
653 IN PDEVICE_OBJECT DeviceObject,
654 IN PIRP Irp)
655 {
656 PIO_STACK_LOCATION IoStack;
657
658 IoStack = IoGetCurrentIrpStackLocation(Irp);
659
660
661 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
662 {
663 return IPortPinWaveCyclic_HandleKsProperty(iface, Irp);
664 }
665 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
666 {
667 /// FIXME
668 /// handle enable event
669 }
670 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT)
671 {
672 /// FIXME
673 /// handle disable event
674 }
675 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
676 {
677 /// FIXME
678 /// handle reset state
679 }
680 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
681 {
682 return IPortPinWaveCyclic_HandleKsStream(iface, Irp);
683 }
684 else
685 {
686 return KsDefaultDeviceIoCompletion(DeviceObject, Irp);
687 }
688
689 UNIMPLEMENTED
690
691 Irp->IoStatus.Information = 0;
692 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
693 IoCompleteRequest(Irp, IO_NO_INCREMENT);
694
695 return STATUS_UNSUCCESSFUL;
696 }
697
698 /*
699 * @implemented
700 */
701 NTSTATUS
702 NTAPI
703 IPortPinWaveCyclic_fnRead(
704 IN IPortPinWaveCyclic* iface,
705 IN PDEVICE_OBJECT DeviceObject,
706 IN PIRP Irp)
707 {
708 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
709 }
710
711 /*
712 * @implemented
713 */
714 NTSTATUS
715 NTAPI
716 IPortPinWaveCyclic_fnWrite(
717 IN IPortPinWaveCyclic* iface,
718 IN PDEVICE_OBJECT DeviceObject,
719 IN PIRP Irp)
720 {
721 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
722 }
723
724 /*
725 * @implemented
726 */
727 NTSTATUS
728 NTAPI
729 IPortPinWaveCyclic_fnFlush(
730 IN IPortPinWaveCyclic* iface,
731 IN PDEVICE_OBJECT DeviceObject,
732 IN PIRP Irp)
733 {
734 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
735 }
736
737 VOID
738 NTAPI
739 CloseStreamRoutine(
740 IN PDEVICE_OBJECT DeviceObject,
741 IN PVOID Context)
742 {
743 PMINIPORTWAVECYCLICSTREAM Stream;
744 IPortPinWaveCyclicImpl * This;
745 NTSTATUS Status;
746 PCLOSESTREAM_CONTEXT Ctx = (PCLOSESTREAM_CONTEXT)Context;
747
748 This = (IPortPinWaveCyclicImpl*)Ctx->Pin;
749
750 if (This->State != KSSTATE_STOP)
751 {
752 /* stop stream in case it hasn't been */
753 Status = This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
754 if (!NT_SUCCESS(Status))
755 DPRINT1("Warning: failed to stop stream with %x\n", Status);
756
757 This->State = KSSTATE_STOP;
758 }
759
760 if (This->Format)
761 {
762 /* free format */
763 ExFreePool(This->Format);
764 This->Format = NULL;
765 }
766
767 if (This->IrpQueue)
768 {
769 This->IrpQueue->lpVtbl->Release(This->IrpQueue);
770 }
771
772 /* complete the irp */
773 Ctx->Irp->IoStatus.Information = 0;
774 Ctx->Irp->IoStatus.Status = STATUS_SUCCESS;
775 IoCompleteRequest(Ctx->Irp, IO_NO_INCREMENT);
776
777 /* free the work item */
778 IoFreeWorkItem(Ctx->WorkItem);
779
780 /* free work item ctx */
781 FreeItem(Ctx, TAG_PORTCLASS);
782
783 /* release reference to port driver */
784 This->Port->lpVtbl->Release(This->Port);
785
786 /* release reference to filter instance */
787 This->Filter->lpVtbl->Release(This->Filter);
788
789 if (This->Stream)
790 {
791 Stream = This->Stream;
792 This->Stream = NULL;
793 This->Filter->lpVtbl->FreePin(This->Filter, (IPortPinWaveCyclic*)This);
794 DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql());
795 Stream->lpVtbl->Release(Stream);
796 }
797 }
798
799 /*
800 * @implemented
801 */
802 NTSTATUS
803 NTAPI
804 IPortPinWaveCyclic_fnClose(
805 IN IPortPinWaveCyclic* iface,
806 IN PDEVICE_OBJECT DeviceObject,
807 IN PIRP Irp)
808 {
809 PCLOSESTREAM_CONTEXT Ctx;
810 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
811
812 if (This->Stream)
813 {
814 /* allocate a close context */
815 Ctx = AllocateItem(NonPagedPool, sizeof(CLOSESTREAM_CONTEXT), TAG_PORTCLASS);
816 if (!Ctx)
817 {
818 DPRINT1("Failed to allocate stream context\n");
819 goto cleanup;
820 }
821 /* allocate work context */
822 Ctx->WorkItem = IoAllocateWorkItem(DeviceObject);
823 if (!Ctx->WorkItem)
824 {
825 DPRINT1("Failed to allocate work item\n");
826 goto cleanup;
827 }
828 /* setup the close context */
829 Ctx->Irp = Irp;
830 Ctx->Pin = (PVOID)This;
831
832 IoMarkIrpPending(Irp);
833 Irp->IoStatus.Information = 0;
834 Irp->IoStatus.Status = STATUS_PENDING;
835
836 /* remove member from service group */
837 This->ServiceGroup->lpVtbl->RemoveMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink);
838
839 /* defer work item */
840 IoQueueWorkItem(Ctx->WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)Ctx);
841 /* Return result */
842 return STATUS_PENDING;
843 }
844
845 Irp->IoStatus.Information = 0;
846 Irp->IoStatus.Status = STATUS_SUCCESS;
847 IoCompleteRequest(Irp, IO_NO_INCREMENT);
848
849 return STATUS_SUCCESS;
850
851 cleanup:
852
853 if (Ctx)
854 FreeItem(Ctx, TAG_PORTCLASS);
855
856 Irp->IoStatus.Information = 0;
857 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
858 IoCompleteRequest(Irp, IO_NO_INCREMENT);
859 return STATUS_UNSUCCESSFUL;
860
861 }
862
863 /*
864 * @implemented
865 */
866 NTSTATUS
867 NTAPI
868 IPortPinWaveCyclic_fnQuerySecurity(
869 IN IPortPinWaveCyclic* iface,
870 IN PDEVICE_OBJECT DeviceObject,
871 IN PIRP Irp)
872 {
873 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
874 }
875
876 /*
877 * @implemented
878 */
879 NTSTATUS
880 NTAPI
881 IPortPinWaveCyclic_fnSetSecurity(
882 IN IPortPinWaveCyclic* iface,
883 IN PDEVICE_OBJECT DeviceObject,
884 IN PIRP Irp)
885 {
886 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
887 }
888
889 /*
890 * @implemented
891 */
892 BOOLEAN
893 NTAPI
894 IPortPinWaveCyclic_fnFastDeviceIoControl(
895 IN IPortPinWaveCyclic* iface,
896 IN PFILE_OBJECT FileObject,
897 IN BOOLEAN Wait,
898 IN PVOID InputBuffer,
899 IN ULONG InputBufferLength,
900 OUT PVOID OutputBuffer,
901 IN ULONG OutputBufferLength,
902 IN ULONG IoControlCode,
903 OUT PIO_STATUS_BLOCK StatusBlock,
904 IN PDEVICE_OBJECT DeviceObject)
905 {
906 return KsDispatchFastIoDeviceControlFailure(FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, StatusBlock, DeviceObject);
907 }
908
909 /*
910 * @implemented
911 */
912 BOOLEAN
913 NTAPI
914 IPortPinWaveCyclic_fnFastRead(
915 IN IPortPinWaveCyclic* iface,
916 IN PFILE_OBJECT FileObject,
917 IN PLARGE_INTEGER FileOffset,
918 IN ULONG Length,
919 IN BOOLEAN Wait,
920 IN ULONG LockKey,
921 IN PVOID Buffer,
922 OUT PIO_STATUS_BLOCK StatusBlock,
923 IN PDEVICE_OBJECT DeviceObject)
924 {
925 NTSTATUS Status;
926 PCONTEXT_WRITE Packet;
927 PIRP Irp;
928 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
929
930 /* HACK to be removed */
931
932 DPRINT("IPortPinWaveCyclic_fnFastRead entered\n");
933
934 Packet = (PCONTEXT_WRITE)Buffer;
935
936 Irp = Packet->Irp;
937 StatusBlock->Status = STATUS_PENDING;
938
939 Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp);
940
941 if (!NT_SUCCESS(Status))
942 return FALSE;
943
944 StatusBlock->Status = STATUS_PENDING;
945
946 return TRUE;
947 }
948
949 /*
950 * @implemented
951 */
952 BOOLEAN
953 NTAPI
954 IPortPinWaveCyclic_fnFastWrite(
955 IN IPortPinWaveCyclic* iface,
956 IN PFILE_OBJECT FileObject,
957 IN PLARGE_INTEGER FileOffset,
958 IN ULONG Length,
959 IN BOOLEAN Wait,
960 IN ULONG LockKey,
961 IN PVOID Buffer,
962 OUT PIO_STATUS_BLOCK StatusBlock,
963 IN PDEVICE_OBJECT DeviceObject)
964 {
965 NTSTATUS Status;
966 PCONTEXT_WRITE Packet;
967 PIRP Irp;
968 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
969
970 /* HACK to be removed */
971
972 InterlockedIncrement((PLONG)&This->TotalPackets);
973
974 DPRINT("IPortPinWaveCyclic_fnFastWrite entered Total %u State %x MinData %u\n", This->TotalPackets, This->State, This->IrpQueue->lpVtbl->NumData(This->IrpQueue));
975
976 Packet = (PCONTEXT_WRITE)Buffer;
977 Irp = Packet->Irp;
978
979 Status = This->IrpQueue->lpVtbl->AddMapping(This->IrpQueue, Buffer, Length, Irp);
980
981 if (!NT_SUCCESS(Status))
982 return FALSE;
983
984 StatusBlock->Status = STATUS_PENDING;
985
986 return TRUE;
987 }
988
989 /*
990 * @implemented
991 */
992 NTSTATUS
993 NTAPI
994 IPortPinWaveCyclic_fnInit(
995 IN IPortPinWaveCyclic* iface,
996 IN PPORTWAVECYCLIC Port,
997 IN PPORTFILTERWAVECYCLIC Filter,
998 IN KSPIN_CONNECT * ConnectDetails,
999 IN KSPIN_DESCRIPTOR * KsPinDescriptor)
1000 {
1001 NTSTATUS Status;
1002 PKSDATAFORMAT DataFormat;
1003 PDEVICE_OBJECT DeviceObject;
1004 BOOL Capture;
1005 PVOID SilenceBuffer;
1006 //IDrmAudioStream * DrmAudio = NULL;
1007
1008 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
1009
1010 This->KsPinDescriptor = KsPinDescriptor;
1011 This->ConnectDetails = ConnectDetails;
1012 This->Miniport = GetWaveCyclicMiniport(Port);
1013
1014 DeviceObject = GetDeviceObject(Port);
1015
1016 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
1017
1018 DPRINT("IPortPinWaveCyclic_fnInit entered\n");
1019
1020 This->Format = ExAllocatePoolWithTag(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
1021 if (!This->Format)
1022 return STATUS_INSUFFICIENT_RESOURCES;
1023
1024 RtlMoveMemory(This->Format, DataFormat, DataFormat->FormatSize);
1025
1026 Status = NewIrpQueue(&This->IrpQueue);
1027 if (!NT_SUCCESS(Status))
1028 return Status;
1029
1030 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
1031 {
1032 Capture = FALSE;
1033 }
1034 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
1035 {
1036 Capture = TRUE;
1037 }
1038 else
1039 {
1040 DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
1041 KeBugCheck(0);
1042 }
1043
1044 Status = This->Miniport->lpVtbl->NewStream(This->Miniport,
1045 &This->Stream,
1046 NULL,
1047 NonPagedPool,
1048 ConnectDetails->PinId,
1049 Capture,
1050 This->Format,
1051 &This->DmaChannel,
1052 &This->ServiceGroup);
1053 #if 0
1054 Status = This->Stream->lpVtbl->QueryInterface(This->Stream, &IID_IDrmAudioStream, (PVOID*)&DrmAudio);
1055 if (NT_SUCCESS(Status))
1056 {
1057 DRMRIGHTS DrmRights;
1058 DPRINT1("Got IID_IDrmAudioStream interface %p\n", DrmAudio);
1059
1060 DrmRights.CopyProtect = FALSE;
1061 DrmRights.Reserved = 0;
1062 DrmRights.DigitalOutputDisable = FALSE;
1063
1064 Status = DrmAudio->lpVtbl->SetContentId(DrmAudio, 1, &DrmRights);
1065 DPRINT("Status %x\n", Status);
1066 }
1067 #endif
1068
1069 DPRINT("IPortPinWaveCyclic_fnInit Status %x\n", Status);
1070
1071 if (!NT_SUCCESS(Status))
1072 return Status;
1073
1074 Status = This->ServiceGroup->lpVtbl->AddMember(This->ServiceGroup,
1075 (PSERVICESINK)&This->lpVtblServiceSink);
1076 if (!NT_SUCCESS(Status))
1077 {
1078 DPRINT1("Failed to add pin to service group\n");
1079 return Status;
1080 }
1081
1082 This->ServiceGroup->lpVtbl->SupportDelayedService(This->ServiceGroup);
1083 This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
1084 This->State = KSSTATE_STOP;
1085 This->CommonBufferOffset = 0;
1086 This->CommonBufferSize = This->DmaChannel->lpVtbl->AllocatedBufferSize(This->DmaChannel);
1087 This->CommonBuffer = This->DmaChannel->lpVtbl->SystemAddress(This->DmaChannel);
1088 This->Capture = Capture;
1089 /* delay of 10 milisec */
1090 This->Delay = Int32x32To64(10, -10000);
1091
1092 Status = This->Stream->lpVtbl->SetNotificationFreq(This->Stream, 10, &This->FrameSize);
1093
1094 SilenceBuffer = AllocateItem(NonPagedPool, This->FrameSize, TAG_PORTCLASS);
1095 if (!SilenceBuffer)
1096 return STATUS_INSUFFICIENT_RESOURCES;
1097
1098 This->Stream->lpVtbl->Silence(This->Stream, SilenceBuffer, This->FrameSize);
1099
1100 Status = This->IrpQueue->lpVtbl->Init(This->IrpQueue, ConnectDetails, DataFormat, DeviceObject, This->FrameSize, 0, SilenceBuffer);
1101 if (!NT_SUCCESS(Status))
1102 {
1103 This->IrpQueue->lpVtbl->Release(This->IrpQueue);
1104 return Status;
1105 }
1106
1107 Port->lpVtbl->AddRef(Port);
1108 Filter->lpVtbl->AddRef(Filter);
1109
1110 This->Port = Port;
1111 This->Filter = Filter;
1112
1113 //This->Stream->lpVtbl->SetFormat(This->Stream, (PKSDATAFORMAT)This->Format);
1114 DPRINT1("Setting state to acquire %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_ACQUIRE));
1115 DPRINT1("Setting state to pause %x\n", This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_PAUSE));
1116 This->State = KSSTATE_PAUSE;
1117
1118 //This->ServiceGroup->lpVtbl->RequestDelayedService(This->ServiceGroup, This->Delay);
1119
1120 return STATUS_SUCCESS;
1121 }
1122
1123 /*
1124 * @unimplemented
1125 */
1126 ULONG
1127 NTAPI
1128 IPortPinWaveCyclic_fnGetCompletedPosition(
1129 IN IPortPinWaveCyclic* iface)
1130 {
1131 UNIMPLEMENTED;
1132 return 0;
1133 }
1134
1135 /*
1136 * @unimplemented
1137 */
1138 ULONG
1139 NTAPI
1140 IPortPinWaveCyclic_fnGetCycleCount(
1141 IN IPortPinWaveCyclic* iface)
1142 {
1143 UNIMPLEMENTED;
1144 return 0;
1145 }
1146
1147 /*
1148 * @implemented
1149 */
1150 ULONG
1151 NTAPI
1152 IPortPinWaveCyclic_fnGetDeviceBufferSize(
1153 IN IPortPinWaveCyclic* iface)
1154 {
1155 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
1156
1157 return This->CommonBufferSize;
1158 }
1159
1160 /*
1161 * @implemented
1162 */
1163 PVOID
1164 NTAPI
1165 IPortPinWaveCyclic_fnGetIrpStream(
1166 IN IPortPinWaveCyclic* iface)
1167 {
1168 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
1169
1170 return (PVOID)This->IrpQueue;
1171 }
1172
1173
1174 /*
1175 * @implemented
1176 */
1177 PMINIPORT
1178 NTAPI
1179 IPortPinWaveCyclic_fnGetMiniport(
1180 IN IPortPinWaveCyclic* iface)
1181 {
1182 IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
1183
1184 return (PMINIPORT)This->Miniport;
1185 }
1186
1187 static IPortPinWaveCyclicVtbl vt_IPortPinWaveCyclic =
1188 {
1189 IPortPinWaveCyclic_fnQueryInterface,
1190 IPortPinWaveCyclic_fnAddRef,
1191 IPortPinWaveCyclic_fnRelease,
1192 IPortPinWaveCyclic_fnNewIrpTarget,
1193 IPortPinWaveCyclic_fnDeviceIoControl,
1194 IPortPinWaveCyclic_fnRead,
1195 IPortPinWaveCyclic_fnWrite,
1196 IPortPinWaveCyclic_fnFlush,
1197 IPortPinWaveCyclic_fnClose,
1198 IPortPinWaveCyclic_fnQuerySecurity,
1199 IPortPinWaveCyclic_fnSetSecurity,
1200 IPortPinWaveCyclic_fnFastDeviceIoControl,
1201 IPortPinWaveCyclic_fnFastRead,
1202 IPortPinWaveCyclic_fnFastWrite,
1203 IPortPinWaveCyclic_fnInit,
1204 IPortPinWaveCyclic_fnGetCompletedPosition,
1205 IPortPinWaveCyclic_fnGetCycleCount,
1206 IPortPinWaveCyclic_fnGetDeviceBufferSize,
1207 IPortPinWaveCyclic_fnGetIrpStream,
1208 IPortPinWaveCyclic_fnGetMiniport
1209 };
1210
1211
1212
1213
1214 NTSTATUS NewPortPinWaveCyclic(
1215 OUT IPortPinWaveCyclic ** OutPin)
1216 {
1217 IPortPinWaveCyclicImpl * This;
1218
1219 This = AllocateItem(NonPagedPool, sizeof(IPortPinWaveCyclicImpl), TAG_PORTCLASS);
1220 if (!This)
1221 return STATUS_INSUFFICIENT_RESOURCES;
1222
1223 /* initialize IPortPinWaveCyclic */
1224 This->ref = 1;
1225 This->lpVtbl = &vt_IPortPinWaveCyclic;
1226 This->lpVtblServiceSink = &vt_IServiceSink;
1227
1228
1229 /* store result */
1230 *OutPin = (IPortPinWaveCyclic*)&This->lpVtbl;
1231
1232 return STATUS_SUCCESS;
1233 }