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