[PORTCLS]
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / pin_wavepci.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
5 * PURPOSE: WavePci IRP Audio Pin
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.hpp"
10
11 class CPortPinWavePci : public IPortPinWavePci,
12 public IServiceSink,
13 public IPortWavePciStream
14 {
15 public:
16 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
17
18 STDMETHODIMP_(ULONG) AddRef()
19 {
20 InterlockedIncrement(&m_Ref);
21 return m_Ref;
22 }
23 STDMETHODIMP_(ULONG) Release()
24 {
25 InterlockedDecrement(&m_Ref);
26
27 if (!m_Ref)
28 {
29 delete this;
30 return 0;
31 }
32 return m_Ref;
33 }
34 IMP_IPortPinWavePci;
35 IMP_IServiceSink;
36 IMP_IPortWavePciStream;
37 CPortPinWavePci(IUnknown *OuterUnknown) {}
38 virtual ~CPortPinWavePci(){}
39
40 VOID NTAPI SetState( IN KSSTATE State);
41 VOID NTAPI CloseStream();
42 protected:
43
44 friend NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
45 friend NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
46 friend NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
47 friend NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
48
49 IPortWavePci * m_Port;
50 IPortFilterWavePci * m_Filter;
51 KSPIN_DESCRIPTOR * m_KsPinDescriptor;
52 PMINIPORTWAVEPCI m_Miniport;
53 PSERVICEGROUP m_ServiceGroup;
54 PDMACHANNEL m_DmaChannel;
55 PMINIPORTWAVEPCISTREAM m_Stream;
56 KSSTATE m_State;
57 PKSDATAFORMAT m_Format;
58 KSPIN_CONNECT * m_ConnectDetails;
59
60 BOOL m_Capture;
61 PDEVICE_OBJECT m_DeviceObject;
62 IIrpQueue * m_IrpQueue;
63
64 ULONG m_TotalPackets;
65 KSAUDIO_POSITION m_Position;
66 ULONG m_StopCount;
67
68 ULONG m_Delay;
69
70 BOOL m_bUsePrefetch;
71 ULONG m_PrefetchOffset;
72 SUBDEVICE_DESCRIPTOR m_Descriptor;
73
74 KSALLOCATOR_FRAMING m_AllocatorFraming;
75
76 LONG m_Ref;
77
78 NTSTATUS NTAPI HandleKsProperty(IN PIRP Irp);
79 NTSTATUS NTAPI HandleKsStream(IN PIRP Irp);
80
81
82 VOID NTAPI SetStreamState( IN KSSTATE State);
83 };
84
85 typedef struct
86 {
87 CPortPinWavePci *Pin;
88 PIO_WORKITEM WorkItem;
89 KSSTATE State;
90 }SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
91
92 NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
93 NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
94 NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
95 NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
96
97 DEFINE_KSPROPERTY_CONNECTIONSET(PinWavePciConnectionSet, PinWavePciState, PinWavePciDataFormat, PinWavePciAllocatorFraming);
98 DEFINE_KSPROPERTY_AUDIOSET(PinWavePciAudioSet, PinWavePciAudioPosition);
99
100 KSPROPERTY_SET PinWavePciPropertySet[] =
101 {
102 {
103 &KSPROPSETID_Connection,
104 sizeof(PinWavePciConnectionSet) / sizeof(KSPROPERTY_ITEM),
105 (const KSPROPERTY_ITEM*)&PinWavePciConnectionSet,
106 0,
107 NULL
108 },
109 {
110 &KSPROPSETID_Audio,
111 sizeof(PinWavePciAudioSet) / sizeof(KSPROPERTY_ITEM),
112 (const KSPROPERTY_ITEM*)&PinWavePciAudioSet,
113 0,
114 NULL
115 }
116 };
117
118
119 NTSTATUS
120 NTAPI
121 PinWavePciAllocatorFraming(
122 IN PIRP Irp,
123 IN PKSIDENTIFIER Request,
124 IN OUT PVOID Data)
125 {
126 CPortPinWavePci *Pin;
127 PSUBDEVICE_DESCRIPTOR Descriptor;
128
129 // get sub device descriptor
130 Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
131
132 // sanity check
133 PC_ASSERT(Descriptor);
134 PC_ASSERT(Descriptor->PortPin);
135 PC_ASSERT_IRQL(DISPATCH_LEVEL);
136
137 // cast to pin impl
138 Pin = (CPortPinWavePci*)Descriptor->PortPin;
139
140
141 if (Request->Flags & KSPROPERTY_TYPE_GET)
142 {
143 // copy pin framing
144 RtlMoveMemory(Data, &Pin->m_AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
145
146 Irp->IoStatus.Information = sizeof(KSALLOCATOR_FRAMING);
147 return STATUS_SUCCESS;
148 }
149
150 // not supported
151 return STATUS_NOT_SUPPORTED;
152 }
153
154 NTSTATUS
155 NTAPI
156 PinWavePciAudioPosition(
157 IN PIRP Irp,
158 IN PKSIDENTIFIER Request,
159 IN OUT PVOID Data)
160 {
161 CPortPinWavePci *Pin;
162 PSUBDEVICE_DESCRIPTOR Descriptor;
163
164 // get sub device descriptor
165 Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
166
167 // sanity check
168 PC_ASSERT(Descriptor);
169 PC_ASSERT(Descriptor->PortPin);
170 PC_ASSERT_IRQL(DISPATCH_LEVEL);
171
172 // cast to pin impl
173 Pin = (CPortPinWavePci*)Descriptor->PortPin;
174
175 //sanity check
176 PC_ASSERT(Pin->m_Stream);
177
178 if (Request->Flags & KSPROPERTY_TYPE_GET)
179 {
180 // FIXME non multithreading-safe
181 // copy audio position
182 RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION));
183
184 DPRINT("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset);
185 Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION);
186 return STATUS_SUCCESS;
187 }
188
189 // not supported
190 return STATUS_NOT_SUPPORTED;
191 }
192
193
194 NTSTATUS
195 NTAPI
196 PinWavePciState(
197 IN PIRP Irp,
198 IN PKSIDENTIFIER Request,
199 IN OUT PVOID Data)
200 {
201 NTSTATUS Status = STATUS_UNSUCCESSFUL;
202 CPortPinWavePci *Pin;
203 PSUBDEVICE_DESCRIPTOR Descriptor;
204 PKSSTATE State = (PKSSTATE)Data;
205
206 // get sub device descriptor
207 Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
208
209 // sanity check
210 PC_ASSERT(Descriptor);
211 PC_ASSERT(Descriptor->PortPin);
212 PC_ASSERT_IRQL(DISPATCH_LEVEL);
213
214 // cast to pin impl
215 Pin = (CPortPinWavePci*)Descriptor->PortPin;
216
217 //sanity check
218 PC_ASSERT(Pin->m_Stream);
219
220 if (Request->Flags & KSPROPERTY_TYPE_SET)
221 {
222 // try set stream
223 Status = Pin->m_Stream->SetState(*State);
224
225 DPRINT("Setting state %u %x\n", *State, Status);
226 if (NT_SUCCESS(Status))
227 {
228 // store new state
229 Pin->m_State = *State;
230 }
231 // store result
232 Irp->IoStatus.Information = sizeof(KSSTATE);
233 return Status;
234 }
235 else if (Request->Flags & KSPROPERTY_TYPE_GET)
236 {
237 // get current stream state
238 *State = Pin->m_State;
239 // store result
240 Irp->IoStatus.Information = sizeof(KSSTATE);
241
242 return STATUS_SUCCESS;
243 }
244
245 // unsupported request
246 return STATUS_NOT_SUPPORTED;
247 }
248
249 NTSTATUS
250 NTAPI
251 PinWavePciDataFormat(
252 IN PIRP Irp,
253 IN PKSIDENTIFIER Request,
254 IN OUT PVOID Data)
255 {
256 NTSTATUS Status = STATUS_UNSUCCESSFUL;
257 CPortPinWavePci *Pin;
258 PSUBDEVICE_DESCRIPTOR Descriptor;
259 PIO_STACK_LOCATION IoStack;
260
261 // get current irp stack location
262 IoStack = IoGetCurrentIrpStackLocation(Irp);
263
264 // get sub device descriptor
265 Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
266
267 // sanity check
268 PC_ASSERT(Descriptor);
269 PC_ASSERT(Descriptor->PortPin);
270
271 // cast to pin impl
272 Pin = (CPortPinWavePci*)Descriptor->PortPin;
273
274 //sanity check
275 PC_ASSERT(Pin->m_Stream);
276 PC_ASSERT(Pin->m_Format);
277
278 if (Request->Flags & KSPROPERTY_TYPE_SET)
279 {
280 // try to change data format
281 PKSDATAFORMAT NewDataFormat, DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
282 ULONG Size = min(Pin->m_Format->FormatSize, DataFormat->FormatSize);
283
284 if (RtlCompareMemory(DataFormat, Pin->m_Format, Size) == Size)
285 {
286 // format is identical
287 Irp->IoStatus.Information = DataFormat->FormatSize;
288 return STATUS_SUCCESS;
289 }
290
291 // new change request
292 PC_ASSERT(Pin->m_State == KSSTATE_STOP);
293 // FIXME queue a work item when Irql != PASSIVE_LEVEL
294 PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
295
296 // allocate new data format
297 NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
298 if (!NewDataFormat)
299 {
300 // not enough memory
301 return STATUS_NO_MEMORY;
302 }
303
304 // copy new data format
305 RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
306
307 // set new format
308 Status = Pin->m_Stream->SetFormat(NewDataFormat);
309 if (NT_SUCCESS(Status))
310 {
311 // free old format
312 FreeItem(Pin->m_Format, TAG_PORTCLASS);
313
314 // update irp queue with new format
315 Pin->m_IrpQueue->UpdateFormat((PKSDATAFORMAT)NewDataFormat);
316
317 // store new format
318 Pin->m_Format = NewDataFormat;
319 Irp->IoStatus.Information = NewDataFormat->FormatSize;
320
321 #if 0
322 PC_ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
323 PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, KSDATAFORMAT_TYPE_AUDIO));
324 PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, KSDATAFORMAT_SUBTYPE_PCM));
325 PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
326
327
328 DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
329 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
330 ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
331 #endif
332
333 }
334 else
335 {
336 // failed to set format
337 FreeItem(NewDataFormat, TAG_PORTCLASS);
338 }
339
340
341 // done
342 return Status;
343 }
344 else if (Request->Flags & KSPROPERTY_TYPE_GET)
345 {
346 // get current data format
347 PC_ASSERT(Pin->m_Format);
348
349 if (Pin->m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
350 {
351 // buffer too small
352 Irp->IoStatus.Information = Pin->m_Format->FormatSize;
353 return STATUS_MORE_ENTRIES;
354 }
355 // copy data format
356 RtlMoveMemory(Data, Pin->m_Format, Pin->m_Format->FormatSize);
357 // store result size
358 Irp->IoStatus.Information = Pin->m_Format->FormatSize;
359
360 // done
361 return STATUS_SUCCESS;
362 }
363
364 // unsupported request
365 return STATUS_NOT_SUPPORTED;
366 }
367
368
369 //==================================================================================================================================
370 NTSTATUS
371 NTAPI
372 CPortPinWavePci::QueryInterface(
373 IN REFIID refiid,
374 OUT PVOID* Output)
375 {
376 DPRINT("CPortPinWavePci::QueryInterface entered\n");
377
378 if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) ||
379 IsEqualGUIDAligned(refiid, IID_IUnknown))
380 {
381 *Output = PVOID(PUNKNOWN((IIrpTarget*)this));
382 PUNKNOWN(*Output)->AddRef();
383 return STATUS_SUCCESS;
384 }
385
386 if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
387 {
388 *Output = PVOID(PSERVICESINK(this));
389 PUNKNOWN(*Output)->AddRef();
390 return STATUS_SUCCESS;
391 }
392
393
394 if (IsEqualGUIDAligned(refiid, IID_IPortWavePciStream))
395 {
396 *Output = PVOID(PPORTWAVEPCISTREAM(this));
397 PUNKNOWN(*Output)->AddRef();
398 return STATUS_SUCCESS;
399 }
400
401 return STATUS_UNSUCCESSFUL;
402 }
403
404 NTSTATUS
405 NTAPI
406 CPortPinWavePci::GetMapping(
407 IN PVOID Tag,
408 OUT PPHYSICAL_ADDRESS PhysicalAddress,
409 OUT PVOID *VirtualAddress,
410 OUT PULONG ByteCount,
411 OUT PULONG Flags)
412 {
413
414 PC_ASSERT_IRQL(DISPATCH_LEVEL);
415 return m_IrpQueue->GetMappingWithTag(Tag, PhysicalAddress, VirtualAddress, ByteCount, Flags);
416 }
417
418 NTSTATUS
419 NTAPI
420 CPortPinWavePci::ReleaseMapping(
421 IN PVOID Tag)
422 {
423
424 PC_ASSERT_IRQL(DISPATCH_LEVEL);
425 return m_IrpQueue->ReleaseMappingWithTag(Tag);
426 }
427
428 NTSTATUS
429 NTAPI
430 CPortPinWavePci::TerminatePacket()
431 {
432 UNIMPLEMENTED
433 PC_ASSERT_IRQL(DISPATCH_LEVEL);
434 return STATUS_SUCCESS;
435 }
436
437
438 VOID
439 CPortPinWavePci::SetState(KSSTATE State)
440 {
441 ULONG MinimumDataThreshold;
442 ULONG MaximumDataThreshold;
443
444 // Has the audio stream resumed?
445 if (m_IrpQueue->NumMappings() && State == KSSTATE_STOP)
446 return;
447
448 // Set the state
449 if (NT_SUCCESS(m_Stream->SetState(State)))
450 {
451 // Save new internal state
452 m_State = State;
453
454 if (m_State == KSSTATE_STOP)
455 {
456 // reset start stream
457 m_IrpQueue->CancelBuffers(); //FIX function name
458 //This->ServiceGroup->lpVtbl->CancelDelayedService(This->ServiceGroup);
459 // increase stop counter
460 m_StopCount++;
461 // get current data threshold
462 MinimumDataThreshold = m_IrpQueue->GetMinimumDataThreshold();
463 // get maximum data threshold
464 MaximumDataThreshold = ((PKSDATAFORMAT_WAVEFORMATEX)m_Format)->WaveFormatEx.nAvgBytesPerSec;
465 // increase minimum data threshold by 10 frames
466 MinimumDataThreshold += m_AllocatorFraming.FrameSize * 10;
467
468 // assure it has not exceeded
469 MinimumDataThreshold = min(MinimumDataThreshold, MaximumDataThreshold);
470 // store minimum data threshold
471 m_IrpQueue->SetMinimumDataThreshold(MinimumDataThreshold);
472
473 DPRINT("Stopping TotalCompleted %u StopCount %u MinimumDataThreshold %u\n", m_TotalPackets, m_StopCount, MinimumDataThreshold);
474 }
475 if (m_State == KSSTATE_RUN)
476 {
477 // start the notification timer
478 //m_ServiceGroup->RequestDelayedService(m_ServiceGroup, m_Delay);
479 }
480 }
481
482
483 }
484
485 VOID
486 NTAPI
487 PinWavePciSetStreamWorkerRoutine(
488 IN PDEVICE_OBJECT DeviceObject,
489 IN PVOID Context)
490 {
491 CPortPinWavePci * This;
492 PSETSTREAM_CONTEXT Ctx = (PSETSTREAM_CONTEXT)Context;
493 KSSTATE State;
494
495 This = Ctx->Pin;
496 State = Ctx->State;
497
498 IoFreeWorkItem(Ctx->WorkItem);
499 FreeItem(Ctx, TAG_PORTCLASS);
500
501 This->SetState(State);
502 }
503
504 VOID
505 NTAPI
506 CPortPinWavePci::SetStreamState(
507 IN KSSTATE State)
508 {
509 PDEVICE_OBJECT DeviceObject;
510 PIO_WORKITEM WorkItem;
511 PSETSTREAM_CONTEXT Context;
512
513 PC_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
514
515 // Has the audio stream resumed?
516 if (m_IrpQueue->NumMappings() && State == KSSTATE_STOP)
517 return;
518
519 // Has the audio state already been set?
520 if (m_State == State)
521 return;
522
523 // Get device object
524 DeviceObject = GetDeviceObjectFromPortWavePci(m_Port);
525
526 // allocate set state context
527 Context = (PSETSTREAM_CONTEXT)AllocateItem(NonPagedPool, sizeof(SETSTREAM_CONTEXT), TAG_PORTCLASS);
528
529 if (!Context)
530 return;
531
532 // allocate work item
533 WorkItem = IoAllocateWorkItem(DeviceObject);
534
535 if (!WorkItem)
536 {
537 ExFreePool(Context);
538 return;
539 }
540
541 Context->Pin = this;
542 Context->WorkItem = WorkItem;
543 Context->State = State;
544
545 // queue the work item
546 IoQueueWorkItem(WorkItem, PinWavePciSetStreamWorkerRoutine, DelayedWorkQueue, (PVOID)Context);
547 }
548
549
550 VOID
551 NTAPI
552 CPortPinWavePci::RequestService()
553 {
554 PC_ASSERT_IRQL(DISPATCH_LEVEL);
555
556 if (m_IrpQueue->HasLastMappingFailed())
557 {
558 if (m_IrpQueue->NumMappings() == 0)
559 {
560 DPRINT("Stopping stream...\n");
561 SetStreamState(KSSTATE_STOP);
562 return;
563 }
564 }
565
566 m_Stream->Service();
567 //TODO
568 //generate events
569 }
570
571 //==================================================================================================================================
572
573 NTSTATUS
574 NTAPI
575 CPortPinWavePci::NewIrpTarget(
576 OUT struct IIrpTarget **OutTarget,
577 IN PCWSTR Name,
578 IN PUNKNOWN Unknown,
579 IN POOL_TYPE PoolType,
580 IN PDEVICE_OBJECT DeviceObject,
581 IN PIRP Irp,
582 IN KSOBJECT_CREATE *CreateObject)
583 {
584 UNIMPLEMENTED
585
586 Irp->IoStatus.Information = 0;
587 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
588 IoCompleteRequest(Irp, IO_NO_INCREMENT);
589
590 return STATUS_UNSUCCESSFUL;
591 }
592
593 NTSTATUS
594 NTAPI
595 CPortPinWavePci::HandleKsProperty(
596 IN PIRP Irp)
597 {
598 PKSPROPERTY Property;
599 NTSTATUS Status;
600 UNICODE_STRING GuidString;
601 PIO_STACK_LOCATION IoStack;
602
603 IoStack = IoGetCurrentIrpStackLocation(Irp);
604
605 DPRINT("IPortPinWave_HandleKsProperty entered\n");
606
607 IoStack = IoGetCurrentIrpStackLocation(Irp);
608
609 if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY)
610 {
611 DPRINT("Unhandled function %lx Length %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode, IoStack->Parameters.DeviceIoControl.InputBufferLength);
612
613 Irp->IoStatus.Status = STATUS_SUCCESS;
614
615 IoCompleteRequest(Irp, IO_NO_INCREMENT);
616 return STATUS_SUCCESS;
617 }
618
619 Status = PcHandlePropertyWithTable(Irp, m_Descriptor.FilterPropertySetCount, m_Descriptor.FilterPropertySet, &m_Descriptor);
620
621 if (Status == STATUS_NOT_FOUND)
622 {
623 Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
624
625 RtlStringFromGUID(Property->Set, &GuidString);
626 DPRINT("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
627 RtlFreeUnicodeString(&GuidString);
628 }
629
630 if (Status != STATUS_PENDING)
631 {
632 Irp->IoStatus.Status = Status;
633 IoCompleteRequest(Irp, IO_NO_INCREMENT);
634 }
635
636 return Status;
637 }
638
639 #if 0
640 else if (Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING)
641 {
642 PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING)OutputBuffer;
643
644 PC_ASSERT_IRQL(DISPATCH_LEVEL);
645 // Validate input buffer
646 if (OutputBufferLength < sizeof(KSALLOCATOR_FRAMING))
647 {
648 IoStatusBlock->Information = sizeof(KSALLOCATOR_FRAMING);
649 IoStatusBlock->Status = STATUS_BUFFER_TOO_SMALL;
650 return STATUS_BUFFER_TOO_SMALL;
651 }
652 // copy frame allocator struct
653 RtlMoveMemory(Framing, &m_AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
654
655 IoStatusBlock->Information = sizeof(KSALLOCATOR_FRAMING);
656 IoStatusBlock->Status = STATUS_SUCCESS;
657 return STATUS_SUCCESS;
658 }
659 }
660 #endif
661
662 NTSTATUS
663 NTAPI
664 CPortPinWavePci::HandleKsStream(
665 IN PIRP Irp)
666 {
667 NTSTATUS Status;
668 InterlockedIncrement((PLONG)&m_TotalPackets);
669
670 DPRINT("IPortPinWaveCyclic_HandleKsStream entered Total %u State %x MinData %u\n", m_TotalPackets, m_State, m_IrpQueue->NumData());
671
672 Status = m_IrpQueue->AddMapping(NULL, 0, Irp);
673
674 if (NT_SUCCESS(Status))
675 {
676
677 PKSSTREAM_HEADER Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
678 PC_ASSERT(Header);
679
680 if (m_Capture)
681 m_Position.WriteOffset += Header->FrameExtent;
682 else
683 m_Position.WriteOffset += Header->DataUsed;
684
685 }
686
687
688 return STATUS_PENDING;
689 }
690
691
692 NTSTATUS
693 NTAPI
694 CPortPinWavePci::DeviceIoControl(
695 IN PDEVICE_OBJECT DeviceObject,
696 IN PIRP Irp)
697 {
698 PIO_STACK_LOCATION IoStack;
699
700 IoStack = IoGetCurrentIrpStackLocation(Irp);
701
702 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
703 {
704 return HandleKsProperty(Irp);
705 }
706 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
707 {
708 return HandleKsStream(Irp);
709 }
710
711 UNIMPLEMENTED
712
713 Irp->IoStatus.Information = 0;
714 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
715 IoCompleteRequest(Irp, IO_NO_INCREMENT);
716
717 return STATUS_UNSUCCESSFUL;
718 }
719
720 NTSTATUS
721 NTAPI
722 CPortPinWavePci::Read(
723 IN PDEVICE_OBJECT DeviceObject,
724 IN PIRP Irp)
725 {
726 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
727 }
728
729 NTSTATUS
730 NTAPI
731 CPortPinWavePci::Write(
732 IN PDEVICE_OBJECT DeviceObject,
733 IN PIRP Irp)
734 {
735 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
736 }
737
738 NTSTATUS
739 NTAPI
740 CPortPinWavePci::Flush(
741 IN PDEVICE_OBJECT DeviceObject,
742 IN PIRP Irp)
743 {
744 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
745 }
746
747 VOID
748 NTAPI
749 CPortPinWavePci::CloseStream()
750 {
751 PMINIPORTWAVEPCISTREAM Stream;
752 ISubdevice *ISubDevice;
753 NTSTATUS Status;
754 PSUBDEVICE_DESCRIPTOR Descriptor;
755
756 if (m_Stream)
757 {
758 if (m_State != KSSTATE_STOP)
759 {
760 m_Stream->SetState(KSSTATE_STOP);
761 }
762 }
763
764 if (m_ServiceGroup)
765 {
766 m_ServiceGroup->RemoveMember(PSERVICESINK(this));
767 }
768
769 Status = m_Port->QueryInterface(IID_ISubdevice, (PVOID*)&ISubDevice);
770 if (NT_SUCCESS(Status))
771 {
772 Status = ISubDevice->GetDescriptor(&Descriptor);
773 if (NT_SUCCESS(Status))
774 {
775 Descriptor->Factory.Instances[m_ConnectDetails->PinId].CurrentPinInstanceCount--;
776 }
777 ISubDevice->Release();
778 }
779
780 if (m_Format)
781 {
782 ExFreePool(m_Format);
783 m_Format = NULL;
784 }
785
786 if (m_Stream)
787 {
788 Stream = m_Stream;
789 m_Stream = 0;
790 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
791 Stream->Release();
792 }
793 }
794
795 VOID
796 NTAPI
797 PinWavePciCloseStreamRoutine(
798 IN PDEVICE_OBJECT DeviceObject,
799 IN PVOID Context)
800 {
801 CPortPinWavePci * This;
802 PCLOSESTREAM_CONTEXT Ctx = (PCLOSESTREAM_CONTEXT)Context;
803
804 This = (CPortPinWavePci*)Ctx->Pin;
805
806 This->CloseStream();
807
808 // complete the irp
809 Ctx->Irp->IoStatus.Information = 0;
810 Ctx->Irp->IoStatus.Status = STATUS_SUCCESS;
811 IoCompleteRequest(Ctx->Irp, IO_NO_INCREMENT);
812
813 // free the work item
814 IoFreeWorkItem(Ctx->WorkItem);
815
816 // free work item ctx
817 FreeItem(Ctx, TAG_PORTCLASS);
818 }
819
820 NTSTATUS
821 NTAPI
822 CPortPinWavePci::Close(
823 IN PDEVICE_OBJECT DeviceObject,
824 IN PIRP Irp)
825 {
826 PCLOSESTREAM_CONTEXT Ctx;
827
828 if (m_Stream)
829 {
830 Ctx = (PCLOSESTREAM_CONTEXT)AllocateItem(NonPagedPool, sizeof(CLOSESTREAM_CONTEXT), TAG_PORTCLASS);
831 if (!Ctx)
832 {
833 DPRINT("Failed to allocate stream context\n");
834 goto cleanup;
835 }
836
837 Ctx->WorkItem = IoAllocateWorkItem(DeviceObject);
838 if (!Ctx->WorkItem)
839 {
840 DPRINT("Failed to allocate work item\n");
841 goto cleanup;
842 }
843
844 Ctx->Irp = Irp;
845 Ctx->Pin = (PVOID)this;
846
847 IoMarkIrpPending(Irp);
848 Irp->IoStatus.Information = 0;
849 Irp->IoStatus.Status = STATUS_PENDING;
850
851 // defer work item
852 IoQueueWorkItem(Ctx->WorkItem, PinWavePciCloseStreamRoutine, DelayedWorkQueue, (PVOID)Ctx);
853 // Return result
854 return STATUS_PENDING;
855 }
856
857 Irp->IoStatus.Information = 0;
858 Irp->IoStatus.Status = STATUS_SUCCESS;
859 IoCompleteRequest(Irp, IO_NO_INCREMENT);
860
861 return STATUS_SUCCESS;
862
863 cleanup:
864
865 if (Ctx)
866 FreeItem(Ctx, TAG_PORTCLASS);
867
868 Irp->IoStatus.Information = 0;
869 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
870 IoCompleteRequest(Irp, IO_NO_INCREMENT);
871 return STATUS_UNSUCCESSFUL;
872
873 }
874
875 NTSTATUS
876 NTAPI
877 CPortPinWavePci::QuerySecurity(
878 IN PDEVICE_OBJECT DeviceObject,
879 IN PIRP Irp)
880 {
881 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
882 }
883
884 NTSTATUS
885 NTAPI
886 CPortPinWavePci::SetSecurity(
887 IN PDEVICE_OBJECT DeviceObject,
888 IN PIRP Irp)
889 {
890 return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
891 }
892
893 BOOLEAN
894 NTAPI
895 CPortPinWavePci::FastDeviceIoControl(
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 FALSE;
907 }
908
909 BOOLEAN
910 NTAPI
911 CPortPinWavePci::FastRead(
912 IN PFILE_OBJECT FileObject,
913 IN PLARGE_INTEGER FileOffset,
914 IN ULONG Length,
915 IN BOOLEAN Wait,
916 IN ULONG LockKey,
917 IN PVOID Buffer,
918 OUT PIO_STATUS_BLOCK StatusBlock,
919 IN PDEVICE_OBJECT DeviceObject)
920 {
921 return FALSE;
922 }
923
924 BOOLEAN
925 NTAPI
926 CPortPinWavePci::FastWrite(
927 IN PFILE_OBJECT FileObject,
928 IN PLARGE_INTEGER FileOffset,
929 IN ULONG Length,
930 IN BOOLEAN Wait,
931 IN ULONG LockKey,
932 IN PVOID Buffer,
933 OUT PIO_STATUS_BLOCK StatusBlock,
934 IN PDEVICE_OBJECT DeviceObject)
935 {
936 return FALSE;
937 }
938
939
940 NTSTATUS
941 NTAPI
942 CPortPinWavePci::Init(
943 IN PPORTWAVEPCI Port,
944 IN PPORTFILTERWAVEPCI Filter,
945 IN KSPIN_CONNECT * ConnectDetails,
946 IN KSPIN_DESCRIPTOR * KsPinDescriptor,
947 IN PDEVICE_OBJECT DeviceObject)
948 {
949 NTSTATUS Status;
950 PKSDATAFORMAT DataFormat;
951 BOOLEAN Capture;
952
953 Port->AddRef();
954 Filter->AddRef();
955
956 m_Port = Port;
957 m_Filter = Filter;
958 m_KsPinDescriptor = KsPinDescriptor;
959 m_ConnectDetails = ConnectDetails;
960 m_Miniport = GetWavePciMiniport(Port);
961 m_DeviceObject = DeviceObject;
962
963 DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
964
965 DPRINT("IPortPinWavePci_fnInit entered\n");
966
967 m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
968 if (!m_Format)
969 return STATUS_INSUFFICIENT_RESOURCES;
970
971 RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
972
973 if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
974 {
975 Capture = FALSE;
976 }
977 else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
978 {
979 Capture = TRUE;
980 }
981 else
982 {
983 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
984 KeBugCheck(0);
985 }
986
987 Status = m_Miniport->NewStream(&m_Stream,
988 NULL,
989 NonPagedPool,
990 PPORTWAVEPCISTREAM(this),
991 ConnectDetails->PinId,
992 Capture,
993 m_Format,
994 &m_DmaChannel,
995 &m_ServiceGroup);
996
997 DPRINT("IPortPinWavePci_fnInit Status %x\n", Status);
998
999 if (!NT_SUCCESS(Status))
1000 return Status;
1001
1002 if (m_ServiceGroup)
1003 {
1004 Status = m_ServiceGroup->AddMember(PSERVICESINK(this));
1005 if (!NT_SUCCESS(Status))
1006 {
1007 DPRINT("Failed to add pin to service group\n");
1008 return Status;
1009 }
1010 m_ServiceGroup->SupportDelayedService();
1011 }
1012
1013 // delay of 10 milisec
1014 m_Delay = Int32x32To64(10, -10000);
1015
1016 Status = m_Stream->GetAllocatorFraming(&m_AllocatorFraming);
1017 if (!NT_SUCCESS(Status))
1018 {
1019 DPRINT("GetAllocatorFraming failed with %x\n", Status);
1020 return Status;
1021 }
1022
1023 DPRINT("OptionFlags %x RequirementsFlag %x PoolType %x Frames %lu FrameSize %lu FileAlignment %lu\n",
1024 m_AllocatorFraming.OptionsFlags, m_AllocatorFraming.RequirementsFlags, m_AllocatorFraming.PoolType, m_AllocatorFraming.Frames, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment);
1025
1026 ISubdevice * Subdevice = NULL;
1027 // get subdevice interface
1028 Status = Port->QueryInterface(IID_ISubdevice, (PVOID*)&Subdevice);
1029
1030 if (!NT_SUCCESS(Status))
1031 return Status;
1032
1033 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor = NULL;
1034
1035 Status = Subdevice->GetDescriptor(&SubDeviceDescriptor);
1036 if (!NT_SUCCESS(Status))
1037 {
1038 // failed to get descriptor
1039 Subdevice->Release();
1040 return Status;
1041 }
1042
1043 /* set up subdevice descriptor */
1044 RtlZeroMemory(&m_Descriptor, sizeof(SUBDEVICE_DESCRIPTOR));
1045 m_Descriptor.FilterPropertySet = PinWavePciPropertySet;
1046 m_Descriptor.FilterPropertySetCount = sizeof(PinWavePciPropertySet) / sizeof(KSPROPERTY_SET);
1047 m_Descriptor.UnknownStream = (PUNKNOWN)m_Stream;
1048 m_Descriptor.DeviceDescriptor = SubDeviceDescriptor->DeviceDescriptor;
1049 m_Descriptor.UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
1050 m_Descriptor.PortPin = (PVOID)this;
1051
1052
1053
1054 Status = NewIrpQueue(&m_IrpQueue);
1055 if (!NT_SUCCESS(Status))
1056 return Status;
1057
1058 Status = m_IrpQueue->Init(ConnectDetails, m_Format, DeviceObject, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment, NULL);
1059 if (!NT_SUCCESS(Status))
1060 {
1061 DPRINT("IrpQueue_Init failed with %x\n", Status);
1062 return Status;
1063 }
1064
1065 m_State = KSSTATE_STOP;
1066 m_Capture = Capture;
1067
1068 return STATUS_SUCCESS;
1069 }
1070
1071 PVOID
1072 NTAPI
1073 CPortPinWavePci::GetIrpStream()
1074 {
1075 return (PVOID)m_IrpQueue;
1076 }
1077
1078
1079 PMINIPORT
1080 NTAPI
1081 CPortPinWavePci::GetMiniport()
1082 {
1083 return (PMINIPORT)m_Miniport;
1084 }
1085
1086
1087 NTSTATUS
1088 NewPortPinWavePci(
1089 OUT IPortPinWavePci ** OutPin)
1090 {
1091 CPortPinWavePci * This;
1092
1093 This = new(NonPagedPool, TAG_PORTCLASS) CPortPinWavePci(NULL);
1094 if (!This)
1095 return STATUS_INSUFFICIENT_RESOURCES;
1096
1097 This->AddRef();
1098
1099 // store result
1100 *OutPin = (IPortPinWavePci*)This;
1101
1102 return STATUS_SUCCESS;
1103 }
1104