reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp

1024 lines
26 KiB
C++

/*
* 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;
}