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

596 lines
15 KiB
C++

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel Streaming
* FILE: drivers/wdm/audio/backpln/portcls/port_wavecyclic.cpp
* PURPOSE: WaveCyclic Port Driver
* PROGRAMMER: Johannes Anderwald
*/
#include "private.hpp"
#ifndef YDEBUG
#define NDEBUG
#endif
#include <debug.h>
GUID IID_IDmaChannelSlave;
class CPortWaveCyclic : public IPortWaveCyclic,
public IPortEvents,
public ISubdevice
{
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_IPortWaveCyclic;
IMP_ISubdevice;
IMP_IPortEvents;
CPortWaveCyclic(IUnknown *OuterUnknown){}
virtual ~CPortWaveCyclic(){}
protected:
PDEVICE_OBJECT m_pDeviceObject;
PMINIPORTWAVECYCLIC m_pMiniport;
PPINCOUNT m_pPinCount;
PPOWERNOTIFY m_pPowerNotify;
PPCFILTER_DESCRIPTOR m_pDescriptor;
PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor;
IPortFilterWaveCyclic * m_Filter;
LONG m_Ref;
friend PMINIPORTWAVECYCLIC GetWaveCyclicMiniport(IN IPortWaveCyclic* iface);
friend PDEVICE_OBJECT GetDeviceObject(PPORTWAVECYCLIC iface);
};
GUID KSPROPERTY_SETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
static GUID InterfaceGuids[4] =
{
{
//KS_CATEGORY_AUDIO
0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
},
{
/// KSCATEGORY_RENDER
0x65E8773EL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
},
{
/// KSCATEGORY_CAPTURE
0x65E8773DL, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
},
{
///KSCATEGORY_AUDIO_DEVICE
0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}
}
};
DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterWaveCyclicTopologySet, TopologyPropertyHandler);
DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterWaveCyclicPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
KSPROPERTY_SET WaveCyclicPropertySet[] =
{
{
&KSPROPSETID_Topology,
sizeof(PortFilterWaveCyclicTopologySet) / sizeof(KSPROPERTY_ITEM),
(const KSPROPERTY_ITEM*)&PortFilterWaveCyclicTopologySet,
0,
NULL
},
{
&KSPROPSETID_Pin,
sizeof(PortFilterWaveCyclicPinSet) / sizeof(KSPROPERTY_ITEM),
(const KSPROPERTY_ITEM*)&PortFilterWaveCyclicPinSet,
0,
NULL
}
};
//KSEVENTSETID_LoopedStreaming, Type = KSEVENT_LOOPEDSTREAMING_POSITION
//KSEVENTSETID_Connection, Type = KSEVENT_CONNECTION_ENDOFSTREAM,
//---------------------------------------------------------------
// IPortEvents
//
void
NTAPI
CPortWaveCyclic::AddEventToEventList(
IN PKSEVENT_ENTRY EventEntry)
{
UNIMPLEMENTED;
}
void
NTAPI
CPortWaveCyclic::GenerateEventList(
IN GUID* Set OPTIONAL,
IN ULONG EventId,
IN BOOL PinEvent,
IN ULONG PinId,
IN BOOL NodeEvent,
IN ULONG NodeId)
{
UNIMPLEMENTED;
}
//---------------------------------------------------------------
// IUnknown interface functions
//
NTSTATUS
NTAPI
CPortWaveCyclic::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
UNICODE_STRING GuidString;
if (IsEqualGUIDAligned(refiid, IID_IPortWaveCyclic) ||
IsEqualGUIDAligned(refiid, IID_IPort) ||
IsEqualGUIDAligned(refiid, IID_IUnknown))
{
*Output = PVOID(PPORTWAVECYCLIC(this));
PUNKNOWN(*Output)->AddRef();
return STATUS_SUCCESS;
}
else if (IsEqualGUIDAligned(refiid, IID_IPortEvents))
{
*Output = PVOID(PPORTEVENTS(this));
PUNKNOWN(*Output)->AddRef();
return STATUS_SUCCESS;
}
else if (IsEqualGUIDAligned(refiid, IID_ISubdevice))
{
*Output = PVOID(PSUBDEVICE(this));
PUNKNOWN(*Output)->AddRef();
return STATUS_SUCCESS;
}
else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion))
{
return NewPortClsVersion((PPORTCLSVERSION*)Output);
}
else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) ||
IsEqualGUIDAligned(refiid, IID_IDrmPort2))
{
return NewIDrmPort((PDRMPORT2*)Output);
}
else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice))
{
return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
}
else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection))
{
return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
}
if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
{
DPRINT1("IPortWaveCyclic_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
RtlFreeUnicodeString(&GuidString);
}
return STATUS_UNSUCCESSFUL;
}
//---------------------------------------------------------------
// IPort interface functions
//
NTSTATUS
NTAPI
CPortWaveCyclic::GetDeviceProperty(
IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty,
IN ULONG BufferLength,
OUT PVOID PropertyBuffer,
OUT PULONG ReturnLength)
{
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
}
NTSTATUS
NTAPI
CPortWaveCyclic::Init(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PUNKNOWN UnknownMiniport,
IN PUNKNOWN UnknownAdapter OPTIONAL,
IN PRESOURCELIST ResourceList)
{
IMiniportWaveCyclic * Miniport;
NTSTATUS Status;
PPINCOUNT PinCount;
PPOWERNOTIFY PowerNotify;
DPRINT("IPortWaveCyclic_Init entered %p\n", this);
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
Status = UnknownMiniport->QueryInterface(IID_IMiniportWaveCyclic, (PVOID*)&Miniport);
if (!NT_SUCCESS(Status))
{
DPRINT("IPortWaveCyclic_Init called with invalid IMiniport adapter\n");
return STATUS_INVALID_PARAMETER;
}
// Initialize port object
m_pMiniport = Miniport;
m_pDeviceObject = DeviceObject;
// initialize miniport
Status = Miniport->Init(UnknownAdapter, ResourceList, this);
if (!NT_SUCCESS(Status))
{
DPRINT("IMiniportWaveCyclic_Init failed with %x\n", Status);
Miniport->Release();
return Status;
}
// get the miniport device descriptor
Status = Miniport->GetDescription(&m_pDescriptor);
if (!NT_SUCCESS(Status))
{
DPRINT("failed to get description\n");
Miniport->Release();
return Status;
}
// create the subdevice descriptor
Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor,
4,
InterfaceGuids,
0,
NULL,
2,
WaveCyclicPropertySet,
0,
0,
0,
NULL,
0,
NULL,
m_pDescriptor);
if (!NT_SUCCESS(Status))
{
DPRINT("PcCreateSubdeviceDescriptor failed with %x\n", Status);
Miniport->Release();
return Status;
}
// store for node property requests
m_SubDeviceDescriptor->UnknownMiniport = UnknownMiniport;
// check if it supports IPinCount interface
Status = UnknownMiniport->QueryInterface(IID_IPinCount, (PVOID*)&PinCount);
if (NT_SUCCESS(Status))
{
// store IPinCount interface
m_pPinCount = PinCount;
}
// does the Miniport adapter support IPowerNotify interface*/
Status = UnknownMiniport->QueryInterface(IID_IPowerNotify, (PVOID*)&PowerNotify);
if (NT_SUCCESS(Status))
{
// store reference
m_pPowerNotify = PowerNotify;
}
DPRINT("IPortWaveCyclic successfully initialized\n");
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CPortWaveCyclic::NewRegistryKey(
OUT PREGISTRYKEY *OutRegistryKey,
IN PUNKNOWN OuterUnknown OPTIONAL,
IN ULONG RegistryKeyType,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN ULONG CreateOptions OPTIONAL,
OUT PULONG Disposition OPTIONAL)
{
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
return PcNewRegistryKey(OutRegistryKey, OuterUnknown, RegistryKeyType, DesiredAccess, m_pDeviceObject, (ISubdevice*)this, ObjectAttributes, CreateOptions, Disposition);
}
//---------------------------------------------------------------
// IPortWaveCyclic interface functions
//
NTSTATUS
NTAPI
CPortWaveCyclic::NewMasterDmaChannel(
OUT PDMACHANNEL* DmaChannel,
IN PUNKNOWN OuterUnknown,
IN PRESOURCELIST ResourceList OPTIONAL,
IN ULONG MaximumLength,
IN BOOLEAN Dma32BitAddresses,
IN BOOLEAN Dma64BitAddresses,
IN DMA_WIDTH DmaWidth,
IN DMA_SPEED DmaSpeed)
{
NTSTATUS Status;
DEVICE_DESCRIPTION DeviceDescription;
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
Status = PcDmaMasterDescription(ResourceList, (Dma32BitAddresses | Dma64BitAddresses), Dma32BitAddresses, 0, Dma64BitAddresses, DmaWidth, DmaSpeed, MaximumLength, 0, &DeviceDescription);
if (NT_SUCCESS(Status))
{
return PcNewDmaChannel(DmaChannel, OuterUnknown, NonPagedPool, &DeviceDescription, m_pDeviceObject);
}
return Status;
}
NTSTATUS
NTAPI
CPortWaveCyclic::NewSlaveDmaChannel(
OUT PDMACHANNELSLAVE* OutDmaChannel,
IN PUNKNOWN OuterUnknown,
IN PRESOURCELIST ResourceList OPTIONAL,
IN ULONG DmaIndex,
IN ULONG MaximumLength,
IN BOOLEAN DemandMode,
IN DMA_SPEED DmaSpeed)
{
DEVICE_DESCRIPTION DeviceDescription;
PDMACHANNEL DmaChannel;
NTSTATUS Status;
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
// FIXME
// Check for F-Type DMA Support
//
Status = PcDmaSlaveDescription(ResourceList, DmaIndex, DemandMode, TRUE, DmaSpeed, MaximumLength, 0, &DeviceDescription);
if (NT_SUCCESS(Status))
{
Status = PcNewDmaChannel(&DmaChannel, OuterUnknown, NonPagedPool, &DeviceDescription, m_pDeviceObject);
if (NT_SUCCESS(Status))
{
Status = DmaChannel->QueryInterface(IID_IDmaChannelSlave, (PVOID*)OutDmaChannel);
DmaChannel->Release();
}
}
return Status;
}
VOID
NTAPI
CPortWaveCyclic::Notify(
IN PSERVICEGROUP ServiceGroup)
{
ServiceGroup->RequestService ();
}
//---------------------------------------------------------------
// ISubdevice interface
//
NTSTATUS
NTAPI
CPortWaveCyclic::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)
{
NTSTATUS Status;
IPortFilterWaveCyclic * Filter;
DPRINT("ISubDevice_NewIrpTarget this %p\n", this);
// is there already an instance of the filter
if (m_Filter)
{
// it is, let's return the result
*OutTarget = (IIrpTarget*)m_Filter;
// increment reference
m_Filter->AddRef();
return STATUS_SUCCESS;
}
// create new instance of filter
Status = NewPortFilterWaveCyclic(&Filter);
if (!NT_SUCCESS(Status))
{
// not enough memory
return Status;
}
// initialize the filter
Status = Filter->Init((IPortWaveCyclic*)this);
if (!NT_SUCCESS(Status))
{
// destroy filter
Filter->Release();
// return status
return Status;
}
// store result
*OutTarget = (IIrpTarget*)Filter;
// store for later re-use
m_Filter = Filter;
// return status
return Status;
}
NTSTATUS
NTAPI
CPortWaveCyclic::ReleaseChildren()
{
DPRINT("ISubDevice_fnReleaseChildren\n");
// release the filter
m_Filter->Release();
if (m_pPinCount)
{
// release pincount interface
m_pPinCount->Release();
}
if (m_pPowerNotify)
{
// release power notify interface
m_pPowerNotify->Release();
}
// now release the miniport
m_pMiniport->Release();
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CPortWaveCyclic::GetDescriptor(
IN SUBDEVICE_DESCRIPTOR ** Descriptor)
{
PC_ASSERT(m_SubDeviceDescriptor != NULL);
*Descriptor = m_SubDeviceDescriptor;
DPRINT("ISubDevice_GetDescriptor this %p desc %p\n", this, m_SubDeviceDescriptor);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CPortWaveCyclic::DataRangeIntersection(
IN ULONG PinId,
IN PKSDATARANGE DataRange,
IN PKSDATARANGE MatchingDataRange,
IN ULONG OutputBufferLength,
OUT PVOID ResultantFormat OPTIONAL,
OUT PULONG ResultantFormatLength)
{
DPRINT("ISubDevice_DataRangeIntersection this %p\n", this);
if (m_pMiniport)
{
return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
NTAPI
CPortWaveCyclic::PowerChangeNotify(
IN POWER_STATE PowerState)
{
if (m_pPowerNotify)
{
m_pPowerNotify->PowerChangeNotify(PowerState);
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CPortWaveCyclic::PinCount(
IN ULONG PinId,
IN OUT PULONG FilterNecessary,
IN OUT PULONG FilterCurrent,
IN OUT PULONG FilterPossible,
IN OUT PULONG GlobalCurrent,
IN OUT PULONG GlobalPossible)
{
if (m_pPinCount)
{
m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
return STATUS_SUCCESS;
}
// FIXME
// scan filter descriptor
return STATUS_UNSUCCESSFUL;
}
///--------------------------------------------------------------
PMINIPORTWAVECYCLIC
GetWaveCyclicMiniport(
IN IPortWaveCyclic* iface)
{
CPortWaveCyclic * This = (CPortWaveCyclic *)iface;
return This->m_pMiniport;
}
PDEVICE_OBJECT
GetDeviceObject(
PPORTWAVECYCLIC iface)
{
CPortWaveCyclic * This = (CPortWaveCyclic *)iface;
return This->m_pDeviceObject;
}
//---------------------------------------------------------------
// IPortWaveCyclic constructor
//
NTSTATUS
NewPortWaveCyclic(
OUT PPORT* OutPort)
{
NTSTATUS Status;
CPortWaveCyclic * Port;
Port = new(NonPagedPool, TAG_PORTCLASS)CPortWaveCyclic(NULL);
if (!Port)
return STATUS_INSUFFICIENT_RESOURCES;
Status = Port->QueryInterface(IID_IPort, (PVOID*)OutPort);
if (!NT_SUCCESS(Status))
{
delete Port;
}
DPRINT("NewPortWaveCyclic %p Status %u\n", Port, Status);
return Status;
}