Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / wdm / audio / backpln / portcls / pin_wavepci.cpp
diff --git a/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp b/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
new file mode 100644 (file)
index 0000000..263df56
--- /dev/null
@@ -0,0 +1,1023 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel Streaming
+ * FILE:            drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp
+ * PURPOSE:         WavePci IRP Audio Pin
+ * PROGRAMMER:      Johannes Anderwald
+ */
+
+#include "private.hpp"
+
+#ifndef YDEBUG
+#define NDEBUG
+#endif
+
+#include <debug.h>
+
+class CPortPinWavePci : public IPortPinWavePci,
+                        public IServiceSink,
+                        public IPortWavePciStream
+{
+public:
+    STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
+
+    STDMETHODIMP_(ULONG) AddRef()
+    {
+        InterlockedIncrement(&m_Ref);
+        return m_Ref;
+    }
+    STDMETHODIMP_(ULONG) Release()
+    {
+        InterlockedDecrement(&m_Ref);
+
+        if (!m_Ref)
+        {
+            delete this;
+            return 0;
+        }
+        return m_Ref;
+    }
+    IMP_IPortPinWavePci;
+    IMP_IServiceSink;
+    IMP_IPortWavePciStream;
+    CPortPinWavePci(IUnknown *OuterUnknown) {}
+    virtual ~CPortPinWavePci(){}
+protected:
+
+    friend NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+    friend NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+    friend NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+    friend NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+
+    IPortWavePci * m_Port;
+    IPortFilterWavePci * m_Filter;
+    KSPIN_DESCRIPTOR * m_KsPinDescriptor;
+    PMINIPORTWAVEPCI m_Miniport;
+    PSERVICEGROUP m_ServiceGroup;
+    PDMACHANNEL m_DmaChannel;
+    PMINIPORTWAVEPCISTREAM m_Stream;
+    KSSTATE m_State;
+    PKSDATAFORMAT m_Format;
+    KSPIN_CONNECT * m_ConnectDetails;
+
+    BOOL m_Capture;
+    PDEVICE_OBJECT m_DeviceObject;
+    IIrpQueue * m_IrpQueue;
+
+    ULONG m_TotalPackets;
+    KSAUDIO_POSITION m_Position;
+    ULONG m_StopCount;
+
+    BOOL m_bUsePrefetch;
+    ULONG m_PrefetchOffset;
+    SUBDEVICE_DESCRIPTOR m_Descriptor;
+
+    KSALLOCATOR_FRAMING m_AllocatorFraming;
+
+    LONG m_Ref;
+
+    NTSTATUS NTAPI HandleKsProperty(IN PIRP Irp);
+    NTSTATUS NTAPI HandleKsStream(IN PIRP Irp);
+};
+
+typedef struct
+{
+    CPortPinWavePci *Pin;
+    PIO_WORKITEM WorkItem;
+    KSSTATE State;
+}SETSTREAM_CONTEXT, *PSETSTREAM_CONTEXT;
+
+NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+
+DEFINE_KSPROPERTY_CONNECTIONSET(PinWavePciConnectionSet, PinWavePciState, PinWavePciDataFormat, PinWavePciAllocatorFraming);
+DEFINE_KSPROPERTY_AUDIOSET(PinWavePciAudioSet, PinWavePciAudioPosition);
+
+KSPROPERTY_SET PinWavePciPropertySet[] =
+{
+    {
+        &KSPROPSETID_Connection,
+        sizeof(PinWavePciConnectionSet) / sizeof(KSPROPERTY_ITEM),
+        (const KSPROPERTY_ITEM*)&PinWavePciConnectionSet,
+        0,
+        NULL
+    },
+    {
+        &KSPROPSETID_Audio,
+        sizeof(PinWavePciAudioSet) / sizeof(KSPROPERTY_ITEM),
+        (const KSPROPERTY_ITEM*)&PinWavePciAudioSet,
+        0,
+        NULL
+    }
+};
+
+
+NTSTATUS
+NTAPI
+PinWavePciAllocatorFraming(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER Request,
+    IN OUT PVOID Data)
+{
+    CPortPinWavePci *Pin;
+    PSUBDEVICE_DESCRIPTOR Descriptor;
+
+    // get sub device descriptor 
+    Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+    // sanity check 
+    PC_ASSERT(Descriptor);
+    PC_ASSERT(Descriptor->PortPin);
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+    // cast to pin impl
+    Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+
+    if (Request->Flags & KSPROPERTY_TYPE_GET)
+    {
+        // copy pin framing
+        RtlMoveMemory(Data, &Pin->m_AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
+
+        Irp->IoStatus.Information = sizeof(KSALLOCATOR_FRAMING);
+        return STATUS_SUCCESS;
+    }
+
+    // not supported
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PinWavePciAudioPosition(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER Request,
+    IN OUT PVOID Data)
+{
+    CPortPinWavePci *Pin;
+    PSUBDEVICE_DESCRIPTOR Descriptor;
+
+    // get sub device descriptor 
+    Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+    // sanity check 
+    PC_ASSERT(Descriptor);
+    PC_ASSERT(Descriptor->PortPin);
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+    // cast to pin impl
+    Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+    //sanity check
+    PC_ASSERT(Pin->m_Stream);
+
+    if (Request->Flags & KSPROPERTY_TYPE_GET)
+    {
+        // FIXME non multithreading-safe
+        // copy audio position
+        RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION));
+
+        DPRINT("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset);
+        Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION);
+        return STATUS_SUCCESS;
+    }
+
+    // not supported
+    return STATUS_NOT_SUPPORTED;
+}
+
+
+NTSTATUS
+NTAPI
+PinWavePciState(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER Request,
+    IN OUT PVOID Data)
+{
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    CPortPinWavePci *Pin;
+    PSUBDEVICE_DESCRIPTOR Descriptor;
+    PVOID FirstTag, LastTag;
+    ULONG MappingsRevoked;
+    PKSSTATE State = (PKSSTATE)Data;
+
+    // get sub device descriptor 
+    Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+    // sanity check 
+    PC_ASSERT(Descriptor);
+    PC_ASSERT(Descriptor->PortPin);
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+    // cast to pin impl
+    Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+    //sanity check
+    PC_ASSERT(Pin->m_Stream);
+
+    if (Request->Flags & KSPROPERTY_TYPE_SET)
+    {
+        // try set stream
+        Status = Pin->m_Stream->SetState(*State);
+
+        DPRINT("Setting state %u %x\n", *State, Status);
+        if (NT_SUCCESS(Status))
+        {
+            // store new state
+            Pin->m_State = *State;
+            if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING && Pin->m_State == KSSTATE_STOP)
+            {
+                // FIXME
+                // complete with successful state
+                Pin->m_IrpQueue->CancelBuffers();
+                while(Pin->m_IrpQueue->GetAcquiredTagRange(&FirstTag, &LastTag))
+                {
+                    Status = Pin->m_Stream->RevokeMappings(FirstTag, LastTag, &MappingsRevoked);
+                    DPRINT("RevokeMappings Status %lx MappingsRevoked: %lu\n", Status, MappingsRevoked);
+                    KeStallExecutionProcessor(10);
+                }
+                Pin->m_Position.PlayOffset = 0;
+                Pin->m_Position.WriteOffset = 0;
+            }
+            else if (Pin->m_State == KSSTATE_STOP)
+            {
+                Pin->m_IrpQueue->CancelBuffers();
+                while(Pin->m_IrpQueue->GetAcquiredTagRange(&FirstTag, &LastTag))
+                {
+                    Status = Pin->m_Stream->RevokeMappings(FirstTag, LastTag, &MappingsRevoked);
+                    DPRINT("RevokeMappings Status %lx MappingsRevoked: %lu\n", Status, MappingsRevoked);
+                    KeStallExecutionProcessor(10);
+                }
+                Pin->m_Position.PlayOffset = 0;
+                Pin->m_Position.WriteOffset = 0;
+            }
+            // store result
+            Irp->IoStatus.Information = sizeof(KSSTATE);
+
+        }
+        // store result
+        Irp->IoStatus.Information = sizeof(KSSTATE);
+        return Status;
+    }
+    else if (Request->Flags & KSPROPERTY_TYPE_GET)
+    {
+        // get current stream state
+        *State = Pin->m_State;
+        // store result
+        Irp->IoStatus.Information = sizeof(KSSTATE);
+
+        return STATUS_SUCCESS;
+    }
+
+    // unsupported request
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PinWavePciDataFormat(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER Request,
+    IN OUT PVOID Data)
+{
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    CPortPinWavePci *Pin;
+    PSUBDEVICE_DESCRIPTOR Descriptor;
+    PIO_STACK_LOCATION IoStack;
+
+    // get current irp stack location
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    // get sub device descriptor 
+    Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+    // sanity check 
+    PC_ASSERT(Descriptor);
+    PC_ASSERT(Descriptor->PortPin);
+
+    // cast to pin impl
+    Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+    //sanity check
+    PC_ASSERT(Pin->m_Stream);
+    PC_ASSERT(Pin->m_Format);
+
+    if (Request->Flags & KSPROPERTY_TYPE_SET)
+    {
+        // try to change data format
+        PKSDATAFORMAT NewDataFormat, DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
+        ULONG Size = min(Pin->m_Format->FormatSize, DataFormat->FormatSize);
+
+        if (RtlCompareMemory(DataFormat, Pin->m_Format, Size) == Size)
+        {
+            // format is identical
+            Irp->IoStatus.Information = DataFormat->FormatSize;
+            return STATUS_SUCCESS;
+        }
+
+        // new change request
+        PC_ASSERT(Pin->m_State == KSSTATE_STOP);
+        // FIXME queue a work item when Irql != PASSIVE_LEVEL
+        PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+        // allocate new data format
+        NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
+        if (!NewDataFormat)
+        {
+            // not enough memory
+            return STATUS_NO_MEMORY;
+        }
+
+        // copy new data format
+        RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
+
+        // set new format
+        Status = Pin->m_Stream->SetFormat(NewDataFormat);
+        if (NT_SUCCESS(Status))
+        {
+            // free old format
+            FreeItem(Pin->m_Format, TAG_PORTCLASS);
+
+            // store new format
+            Pin->m_Format = NewDataFormat;
+            Irp->IoStatus.Information = NewDataFormat->FormatSize;
+
+#if 0
+            PC_ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
+            PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, KSDATAFORMAT_TYPE_AUDIO));
+            PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, KSDATAFORMAT_SUBTYPE_PCM));
+            PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
+
+
+            DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
+                                                                       ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
+                                                                       ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
+#endif
+
+        }
+        else
+        {
+            // failed to set format
+            FreeItem(NewDataFormat, TAG_PORTCLASS);
+        }
+
+
+        // done
+        return Status;
+    }
+    else if (Request->Flags & KSPROPERTY_TYPE_GET)
+    {
+        // get current data format
+        PC_ASSERT(Pin->m_Format);
+
+        if (Pin->m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+        {
+            // buffer too small
+            Irp->IoStatus.Information = Pin->m_Format->FormatSize;
+            return STATUS_MORE_ENTRIES;
+        }
+        // copy data format
+        RtlMoveMemory(Data, Pin->m_Format, Pin->m_Format->FormatSize);
+        // store result size
+        Irp->IoStatus.Information = Pin->m_Format->FormatSize;
+
+        // done
+        return STATUS_SUCCESS;
+    }
+
+    // unsupported request
+    return STATUS_NOT_SUPPORTED;
+}
+
+
+//==================================================================================================================================
+NTSTATUS
+NTAPI
+CPortPinWavePci::QueryInterface(
+    IN  REFIID refiid,
+    OUT PVOID* Output)
+{
+    //DPRINT("CPortPinWavePci::QueryInterface entered\n");
+
+    if (IsEqualGUIDAligned(refiid, IID_IIrpTarget) || 
+        IsEqualGUIDAligned(refiid, IID_IUnknown))
+    {
+        *Output = PVOID(PUNKNOWN((IIrpTarget*)this));
+        PUNKNOWN(*Output)->AddRef();
+        return STATUS_SUCCESS;
+    }
+
+    if (IsEqualGUIDAligned(refiid, IID_IServiceSink))
+    {
+        *Output = PVOID(PSERVICESINK(this));
+        PUNKNOWN(*Output)->AddRef();
+        return STATUS_SUCCESS;
+    }
+
+
+    if (IsEqualGUIDAligned(refiid, IID_IPortWavePciStream))
+    {
+        *Output = PVOID(PPORTWAVEPCISTREAM(this));
+        PUNKNOWN(*Output)->AddRef();
+        return STATUS_SUCCESS;
+    }
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::GetMapping(
+    IN PVOID Tag,
+    OUT PPHYSICAL_ADDRESS  PhysicalAddress,
+    OUT PVOID  *VirtualAddress,
+    OUT PULONG  ByteCount,
+    OUT PULONG  Flags)
+{
+
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+    return m_IrpQueue->GetMappingWithTag(Tag, PhysicalAddress, VirtualAddress, ByteCount, Flags);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::ReleaseMapping(
+    IN PVOID  Tag)
+{
+
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+    return m_IrpQueue->ReleaseMappingWithTag(Tag);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::TerminatePacket()
+{
+    UNIMPLEMENTED;
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+    return STATUS_SUCCESS;
+}
+
+
+VOID
+NTAPI
+CPortPinWavePci::RequestService()
+{
+    PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+    if (m_State == KSSTATE_RUN)
+    {
+        m_Stream->Service();
+        //TODO
+        //generate events
+    }
+}
+
+//==================================================================================================================================
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::NewIrpTarget(
+    OUT struct IIrpTarget **OutTarget,
+    IN PCWSTR Name,
+    IN PUNKNOWN Unknown,
+    IN POOL_TYPE PoolType,
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN KSOBJECT_CREATE *CreateObject)
+{
+    UNIMPLEMENTED;
+
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::HandleKsProperty(
+    IN PIRP Irp)
+{
+    //PKSPROPERTY Property;
+    NTSTATUS Status;
+    //UNICODE_STRING GuidString;
+    PIO_STACK_LOCATION IoStack;
+
+    //DPRINT("IPortPinWave_HandleKsProperty entered\n");
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY)
+    {
+        //DPRINT("Unhandled function %lx Length %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode, IoStack->Parameters.DeviceIoControl.InputBufferLength);
+        
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
+    Status = PcHandlePropertyWithTable(Irp,  m_Descriptor.FilterPropertySetCount, m_Descriptor.FilterPropertySet, &m_Descriptor);
+
+    if (Status == STATUS_NOT_FOUND)
+    {
+        //Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+#if 0
+        RtlStringFromGUID(Property->Set, &GuidString);
+        //DPRINT("Unhandled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
+        RtlFreeUnicodeString(&GuidString);
+#endif
+    }
+
+    if (Status != STATUS_PENDING)
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::HandleKsStream(
+    IN PIRP Irp)
+{
+    NTSTATUS Status;
+    ULONG Data = 0;
+    BOOLEAN bFailed;
+    InterlockedIncrement((PLONG)&m_TotalPackets);
+
+    DPRINT("IPortPinWaveCyclic_HandleKsStream entered Total %u State %x MinData %u\n", m_TotalPackets, m_State, m_IrpQueue->NumData());
+
+    bFailed = m_IrpQueue->HasLastMappingFailed();
+
+    Status = m_IrpQueue->AddMapping(Irp, &Data);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (m_Capture)
+            m_Position.WriteOffset += Data;
+        else
+            m_Position.PlayOffset += Data;
+
+        if (bFailed)
+        {
+            // notify stream of new mapping
+            m_Stream->MappingAvailable();
+        }
+
+        return STATUS_PENDING;
+    }
+
+    return Status;
+}
+
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::DeviceIoControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
+    {
+        return HandleKsProperty(Irp);
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_WRITE_STREAM || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_READ_STREAM)
+    {
+       return HandleKsStream(Irp);
+    }
+
+    UNIMPLEMENTED;
+
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::Read(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::Write(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::Flush(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::Close(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    NTSTATUS Status;
+
+    if (m_Format)
+    {
+        // free format
+        FreeItem(m_Format, TAG_PORTCLASS);
+
+        // format is freed
+        m_Format = NULL;
+    }
+
+    if (m_IrpQueue)
+    {
+        // cancel remaining irps
+        m_IrpQueue->CancelBuffers();
+
+        // release irp queue
+        m_IrpQueue->Release();
+
+        // queue is freed
+        m_IrpQueue = NULL;
+    }
+
+
+    if (m_ServiceGroup)
+    {
+        // remove member from service group
+        m_ServiceGroup->RemoveMember(PSERVICESINK(this));
+
+        // do not release service group, it is released by the miniport object
+        m_ServiceGroup = NULL;
+    }
+
+    if (m_Stream)
+    {
+        if (m_State != KSSTATE_STOP)
+        {
+            // stop stream
+            Status = m_Stream->SetState(KSSTATE_STOP);
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT("Warning: failed to stop stream with %x\n", Status);
+                PC_ASSERT(0);
+            }
+        }
+        // set state to stop
+        m_State = KSSTATE_STOP;
+
+        DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
+
+        // release stream
+        m_Stream->Release();
+
+        // stream is now freed
+        m_Stream = NULL;
+    }
+
+    if (m_Filter)
+    {
+        // disconnect pin from filter
+        m_Filter->FreePin((PPORTPINWAVEPCI)this);
+
+        // release filter reference
+        m_Filter->Release();
+
+        // pin is done with filter
+        m_Filter = NULL;
+    }
+
+    if (m_Port)
+    {
+        // release reference to port driver
+        m_Port->Release();
+
+        // work is done for port
+        m_Port = NULL;
+    }
+
+    // successfully complete irp
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::QuerySecurity(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::SetSecurity(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+}
+
+BOOLEAN
+NTAPI
+CPortPinWavePci::FastDeviceIoControl(
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    IN PVOID InputBuffer,
+    IN ULONG InputBufferLength,
+    OUT PVOID OutputBuffer,
+    IN ULONG OutputBufferLength,
+    IN ULONG IoControlCode,
+    OUT PIO_STATUS_BLOCK StatusBlock,
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    return FALSE;
+}
+
+BOOLEAN
+NTAPI
+CPortPinWavePci::FastRead(
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN ULONG LockKey,
+    IN PVOID Buffer,
+    OUT PIO_STATUS_BLOCK StatusBlock,
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    return FALSE;
+}
+
+BOOLEAN
+NTAPI
+CPortPinWavePci::FastWrite(
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN ULONG LockKey,
+    IN PVOID Buffer,
+    OUT PIO_STATUS_BLOCK StatusBlock,
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    return FALSE;
+}
+
+
+NTSTATUS
+NTAPI
+CPortPinWavePci::Init(
+    IN PPORTWAVEPCI Port,
+    IN PPORTFILTERWAVEPCI Filter,
+    IN KSPIN_CONNECT * ConnectDetails,
+    IN KSPIN_DESCRIPTOR * KsPinDescriptor,
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    NTSTATUS Status;
+    PKSDATAFORMAT DataFormat;
+    BOOLEAN Capture;
+    ISubdevice * Subdevice = NULL;
+    PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor = NULL;
+
+    // check if it is a source / sink pin
+    if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_IN)
+    {
+        // sink pin
+        Capture = FALSE;
+    }
+    else if (KsPinDescriptor->Communication == KSPIN_COMMUNICATION_SINK && KsPinDescriptor->DataFlow == KSPIN_DATAFLOW_OUT)
+    {
+        // source pin
+        Capture = TRUE;
+    }
+    else
+    {
+        DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor->Communication, KsPinDescriptor->DataFlow);
+        DbgBreakPoint();
+        while(TRUE);
+    }
+
+    // add port / filter reference
+    Port->AddRef();
+    Filter->AddRef();
+
+    // initialize pin
+    m_Port = Port;
+    m_Filter = Filter;
+    m_KsPinDescriptor = KsPinDescriptor;
+    m_ConnectDetails = ConnectDetails;
+    m_Miniport = GetWavePciMiniport(Port);
+    m_DeviceObject = DeviceObject;
+    m_State = KSSTATE_STOP;
+    m_Capture = Capture;
+
+    DPRINT("IPortPinWavePci_fnInit entered\n");
+
+    // get dataformat
+    DataFormat = (PKSDATAFORMAT)(ConnectDetails + 1);
+
+    // allocate data format
+    m_Format = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
+    if (!m_Format)
+    {
+        // release references
+        m_Port->Release();
+        m_Filter->Release();
+
+        // no dangling pointers
+        Port = NULL;
+        Filter = NULL;
+
+        // failed to allocate data format
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    // copy data format
+    RtlMoveMemory(m_Format, DataFormat, DataFormat->FormatSize);
+
+    // allocate new stream
+    Status = m_Miniport->NewStream(&m_Stream,
+                                   NULL,
+                                   NonPagedPool,
+                                   PPORTWAVEPCISTREAM(this),
+                                   ConnectDetails->PinId,
+                                   Capture,
+                                   m_Format,
+                                   &m_DmaChannel,
+                                   &m_ServiceGroup);
+
+    DPRINT("IPortPinWavePci_fnInit Status %x\n", Status);
+
+    if (!NT_SUCCESS(Status))
+    {
+        // free references
+        Port->Release();
+        Filter->Release();
+
+        // free data format
+        FreeItem(m_Format, TAG_PORTCLASS);
+
+        // no dangling pointers
+        m_Port = NULL;
+        m_Filter = NULL;
+        m_Format = NULL;
+
+        // failed to allocate stream
+        return Status;
+    }
+
+    // get allocator requirements for pin
+    Status = m_Stream->GetAllocatorFraming(&m_AllocatorFraming);
+    if (NT_SUCCESS(Status))
+    {
+        DPRINT("OptionFlags %x RequirementsFlag %x PoolType %x Frames %lu FrameSize %lu FileAlignment %lu\n",
+               m_AllocatorFraming.OptionsFlags, m_AllocatorFraming.RequirementsFlags, m_AllocatorFraming.PoolType, m_AllocatorFraming.Frames, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment);
+    }
+
+    // allocate new irp queue
+    Status = NewIrpQueue(&m_IrpQueue);
+    if (!NT_SUCCESS(Status))
+    {
+        // free references
+        Port->Release();
+        Filter->Release();
+        m_Stream->Release();
+
+        // free data format
+        FreeItem(m_Format, TAG_PORTCLASS);
+
+        // no dangling pointers
+        m_Port = NULL;
+        m_Filter = NULL;
+        m_Format = NULL;
+        m_Stream = NULL;
+
+        // failed to allocate irp queue
+        return Status;
+    }
+
+    // initialize irp queue
+    Status = m_IrpQueue->Init(ConnectDetails, KsPinDescriptor, m_AllocatorFraming.FrameSize, m_AllocatorFraming.FileAlignment, TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        // this should never happen
+        ASSERT(0);
+    }
+
+    // get subdevice interface
+    Status = Port->QueryInterface(IID_ISubdevice, (PVOID*)&Subdevice);
+
+    if (!NT_SUCCESS(Status))
+    {
+        // this function should never fail
+        ASSERT(0);
+    }
+
+    // get subdevice descriptor
+    Status = Subdevice->GetDescriptor(&SubDeviceDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        // this function should never fail
+        ASSERT(0);
+    }
+
+    // release subdevice
+    Subdevice->Release();
+
+    /* set up subdevice descriptor */
+    RtlZeroMemory(&m_Descriptor, sizeof(SUBDEVICE_DESCRIPTOR));
+    m_Descriptor.FilterPropertySet = PinWavePciPropertySet;
+    m_Descriptor.FilterPropertySetCount = sizeof(PinWavePciPropertySet) / sizeof(KSPROPERTY_SET);
+    m_Descriptor.UnknownStream = (PUNKNOWN)m_Stream;
+    m_Descriptor.DeviceDescriptor = SubDeviceDescriptor->DeviceDescriptor;
+    m_Descriptor.UnknownMiniport = SubDeviceDescriptor->UnknownMiniport;
+    m_Descriptor.PortPin = (PVOID)this;
+
+    if (m_ServiceGroup)
+    {
+        Status = m_ServiceGroup->AddMember(PSERVICESINK(this));
+        if (!NT_SUCCESS(Status))
+        {
+            // free references
+            m_Stream->Release();
+            Port->Release();
+            Filter->Release();
+
+            // free data format
+            FreeItem(m_Format, TAG_PORTCLASS);
+
+            // no dangling pointers
+            m_Stream = NULL;
+            m_Port = NULL;
+            m_Filter = NULL;
+            m_Format = NULL;
+
+            // failed to add to service group
+            return Status;
+        }
+    }
+
+
+    return STATUS_SUCCESS;
+}
+
+PVOID
+NTAPI
+CPortPinWavePci::GetIrpStream()
+{
+    return (PVOID)m_IrpQueue;
+}
+
+
+PMINIPORT
+NTAPI
+CPortPinWavePci::GetMiniport()
+{
+    return (PMINIPORT)m_Miniport;
+}
+
+
+NTSTATUS
+NewPortPinWavePci(
+    OUT IPortPinWavePci ** OutPin)
+{
+    CPortPinWavePci * This;
+
+    This = new(NonPagedPool, TAG_PORTCLASS) CPortPinWavePci(NULL);
+    if (!This)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    This->AddRef();
+
+    // store result
+    *OutPin = (IPortPinWavePci*)This;
+
+    return STATUS_SUCCESS;
+}
+