Files
appsandbox/tools/vad/adaptercommon.cpp
James Stringer e25fedb943 Fix VAD audio driver validation and refcount bugs
- M15 wavminiport.cpp: reject PinId >= WaveDescriptor->PinCount in the
  proposed-format property handler.
- M16 wavstream.cpp: guard divide-by-zero on m_ulDmaMovementRate and
  nAvgBytesPerSec in buffer allocation and presentation-position.
- L14 topology.cpp: set PropertyRequest->ValueSize in both jack
  description GET paths.
- L15 adaptercommon.cpp: balance the adapter instance count on the
  allocation-failure path.
2026-06-02 21:51:42 -04:00

1311 lines
41 KiB
C++

#pragma warning (disable : 4127)
#include <initguid.h>
#include "driverdefs.h"
#include "pinnodes.h"
//=============================================================================
// Mixer register counts
//=============================================================================
#define MAX_TOPOLOGY_NODES 2
#define MAX_CHANNELS 2
//=============================================================================
// Sub-device cache entry
//=============================================================================
typedef struct _MINIPAIR_UNKNOWN
{
LIST_ENTRY ListEntry;
WCHAR Name[MAX_PATH];
PUNKNOWN PortInterface;
PUNKNOWN MiniportInterface;
PADAPTERPOWERMANAGEMENT PowerInterface;
} MINIPAIR_UNKNOWN;
//=============================================================================
// CVadAdapterCommon
//=============================================================================
class CVadAdapterCommon :
public IAdapterCommon,
public IAdapterPowerManagement,
public CUnknown
{
private:
PSERVICEGROUP m_pServiceGroupWave;
PDEVICE_OBJECT m_pDeviceObject;
PDEVICE_OBJECT m_pPhysicalDeviceObject;
WDFDEVICE m_WdfDevice;
DEVICE_POWER_STATE m_PowerState;
PPORTCLSETWHELPER m_pPortClsEtwHelper;
LIST_ENTRY m_SubdeviceCache;
static LONG m_AdapterInstances;
// Inline mixer state (no separate HW object)
BOOL m_MixerMute[MAX_TOPOLOGY_NODES][MAX_CHANNELS];
LONG m_MixerVolume[MAX_TOPOLOGY_NODES][MAX_CHANNELS];
LONG m_PeakMeter[MAX_TOPOLOGY_NODES][MAX_CHANNELS];
ULONG m_MixerMux;
BOOL m_bDevSpecific;
INT m_iDevSpecific;
UINT m_uiDevSpecific;
public:
DECLARE_STD_UNKNOWN();
DEFINE_STD_CONSTRUCTOR(CVadAdapterCommon);
~CVadAdapterCommon();
IMP_IAdapterPowerManagement;
STDMETHODIMP_(NTSTATUS) Init
(
_In_ PDEVICE_OBJECT DeviceObject
);
STDMETHODIMP_(PDEVICE_OBJECT) GetDeviceObject(void);
STDMETHODIMP_(PDEVICE_OBJECT) GetPhysicalDeviceObject(void);
STDMETHODIMP_(WDFDEVICE) GetWdfDevice(void);
STDMETHODIMP_(void) SetWaveServiceGroup
(
_In_ PSERVICEGROUP ServiceGroup
);
STDMETHODIMP_(BOOL) bDevSpecificRead();
STDMETHODIMP_(void) bDevSpecificWrite(_In_ BOOL bDevSpecific);
STDMETHODIMP_(INT) iDevSpecificRead();
STDMETHODIMP_(void) iDevSpecificWrite(_In_ INT iDevSpecific);
STDMETHODIMP_(UINT) uiDevSpecificRead();
STDMETHODIMP_(void) uiDevSpecificWrite(_In_ UINT uiDevSpecific);
STDMETHODIMP_(BOOL) MixerMuteRead(_In_ ULONG Index, _In_ ULONG Channel);
STDMETHODIMP_(void) MixerMuteWrite(_In_ ULONG Index, _In_ ULONG Channel, _In_ BOOL Value);
STDMETHODIMP_(ULONG) MixerMuxRead(void);
STDMETHODIMP_(void) MixerMuxWrite(_In_ ULONG Index);
STDMETHODIMP_(void) MixerReset(void);
STDMETHODIMP_(LONG) MixerVolumeRead(_In_ ULONG Index, _In_ ULONG Channel);
STDMETHODIMP_(void) MixerVolumeWrite(_In_ ULONG Index, _In_ ULONG Channel, _In_ LONG Value);
STDMETHODIMP_(LONG) MixerPeakMeterRead(_In_ ULONG Index, _In_ ULONG Channel);
STDMETHODIMP_(NTSTATUS) WriteEtwEvent
(
_In_ EPcMiniportEngineEvent miniportEventType,
_In_ ULONGLONG ullData1,
_In_ ULONGLONG ullData2,
_In_ ULONGLONG ullData3,
_In_ ULONGLONG ullData4
);
STDMETHODIMP_(VOID) SetEtwHelper(PPORTCLSETWHELPER _pPortClsEtwHelper);
STDMETHODIMP_(NTSTATUS) InstallSubdevice
(
_In_opt_ PIRP Irp,
_In_ PWSTR Name,
_In_ REFGUID PortClassId,
_In_ REFGUID MiniportClassId,
_In_opt_ PFNCREATEMINIPORT MiniportCreate,
_In_ ULONG cPropertyCount,
_In_reads_opt_(cPropertyCount) const VAD_DEVPROPERTY * pProperties,
_In_opt_ PVOID DeviceContext,
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PRESOURCELIST ResourceList,
_In_ REFGUID PortInterfaceId,
_Out_opt_ PUNKNOWN * OutPortInterface,
_Out_opt_ PUNKNOWN * OutPortUnknown,
_Out_opt_ PUNKNOWN * OutMiniportUnknown
);
STDMETHODIMP_(NTSTATUS) UnregisterSubdevice(_In_opt_ PUNKNOWN UnknownPort);
STDMETHODIMP_(NTSTATUS) ConnectTopologies
(
_In_ PUNKNOWN UnknownTopology,
_In_ PUNKNOWN UnknownWave,
_In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
_In_ ULONG PhysicalConnectionCount
);
STDMETHODIMP_(NTSTATUS) DisconnectTopologies
(
_In_ PUNKNOWN UnknownTopology,
_In_ PUNKNOWN UnknownWave,
_In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
_In_ ULONG PhysicalConnectionCount
);
STDMETHODIMP_(NTSTATUS) InstallEndpointFilters
(
_In_opt_ PIRP Irp,
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PVOID DeviceContext,
_Out_opt_ PUNKNOWN * UnknownTopology,
_Out_opt_ PUNKNOWN * UnknownWave,
_Out_opt_ PUNKNOWN * UnknownMiniportTopology,
_Out_opt_ PUNKNOWN * UnknownMiniportWave
);
STDMETHODIMP_(NTSTATUS) RemoveEndpointFilters
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PUNKNOWN UnknownTopology,
_In_opt_ PUNKNOWN UnknownWave
);
STDMETHODIMP_(NTSTATUS) GetFilters
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_Out_opt_ PUNKNOWN *UnknownTopologyPort,
_Out_opt_ PUNKNOWN *UnknownTopologyMiniport,
_Out_opt_ PUNKNOWN *UnknownWavePort,
_Out_opt_ PUNKNOWN *UnknownWaveMiniport
);
STDMETHODIMP_(NTSTATUS) SetIdlePowerManagement
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_ BOOL bEnabled
);
STDMETHODIMP_(VOID) Cleanup();
friend NTSTATUS NewAdapterCommon
(
_Out_ PUNKNOWN * Unknown,
_In_ REFCLSID,
_In_opt_ PUNKNOWN UnknownOuter,
_In_ POOL_FLAGS PoolFlags
);
private:
NTSTATUS GetCachedSubdevice(_In_ PWSTR Name, _Out_opt_ PUNKNOWN *OutUnknownPort, _Out_opt_ PUNKNOWN *OutUnknownMiniport);
NTSTATUS CacheSubdevice(_In_ PWSTR Name, _In_ PUNKNOWN UnknownPort, _In_ PUNKNOWN UnknownMiniport);
NTSTATUS RemoveCachedSubdevice(_In_ PWSTR Name);
VOID EmptySubdeviceCache();
NTSTATUS CreateAudioInterfaceWithProperties
(
_In_ PCWSTR ReferenceString,
_In_ ULONG cPropertyCount,
_In_reads_opt_(cPropertyCount) const VAD_DEVPROPERTY *pProperties,
_Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
);
};
LONG CVadAdapterCommon::m_AdapterInstances = 0;
//=============================================================================
// Helper: set device interface properties
//=============================================================================
#pragma code_seg("PAGE")
static
NTSTATUS VadIoSetDeviceInterfacePropertyDataMultiple
(
_In_ PUNICODE_STRING SymbolicLinkName,
_In_ ULONG cPropertyCount,
_In_reads_opt_(cPropertyCount) const VAD_DEVPROPERTY *pProperties
)
{
NTSTATUS ntStatus;
PAGED_CODE();
if (pProperties)
{
for (ULONG i = 0; i < cPropertyCount; i++)
{
ntStatus = IoSetDeviceInterfacePropertyData(
SymbolicLinkName,
pProperties[i].PropertyKey,
LOCALE_NEUTRAL,
PLUGPLAY_PROPERTY_PERSISTENT,
pProperties[i].Type,
pProperties[i].BufferSize,
pProperties[i].Buffer);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
}
}
return STATUS_SUCCESS;
}
//=============================================================================
// NewAdapterCommon
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
NewAdapterCommon
(
_Out_ PUNKNOWN * Unknown,
_In_ REFCLSID,
_In_opt_ PUNKNOWN UnknownOuter,
_In_ POOL_FLAGS PoolFlags
)
{
PAGED_CODE();
ASSERT(Unknown);
NTSTATUS ntStatus;
if (InterlockedCompareExchange(&CVadAdapterCommon::m_AdapterInstances, 1, 0) != 0)
{
ntStatus = STATUS_DEVICE_BUSY;
DPF(D_ERROR, ("NewAdapterCommon failed, only one instance is allowed"));
goto Done;
}
{
CVadAdapterCommon *p = new(PoolFlags, VAD_ADAPTER_POOLTAG) CVadAdapterCommon(UnknownOuter);
if (p == NULL)
{
InterlockedDecrement(&CVadAdapterCommon::m_AdapterInstances);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
DPF(D_ERROR, ("NewAdapterCommon failed, 0x%x", ntStatus));
goto Done;
}
*Unknown = PUNKNOWN((PADAPTERCOMMON)(p));
(*Unknown)->AddRef();
ntStatus = STATUS_SUCCESS;
}
Done:
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
CVadAdapterCommon::~CVadAdapterCommon(void)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::~CVadAdapterCommon]"));
SAFE_RELEASE(m_pPortClsEtwHelper);
SAFE_RELEASE(m_pServiceGroupWave);
if (m_WdfDevice)
{
WdfObjectDelete(m_WdfDevice);
m_WdfDevice = NULL;
}
InterlockedDecrement(&CVadAdapterCommon::m_AdapterInstances);
ASSERT(CVadAdapterCommon::m_AdapterInstances == 0);
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(PDEVICE_OBJECT) CVadAdapterCommon::GetDeviceObject(void)
{
PAGED_CODE();
return m_pDeviceObject;
}
#pragma code_seg("PAGE")
STDMETHODIMP_(PDEVICE_OBJECT) CVadAdapterCommon::GetPhysicalDeviceObject(void)
{
PAGED_CODE();
return m_pPhysicalDeviceObject;
}
#pragma code_seg("PAGE")
STDMETHODIMP_(WDFDEVICE) CVadAdapterCommon::GetWdfDevice(void)
{
PAGED_CODE();
return m_WdfDevice;
}
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CVadAdapterCommon::Init
(
_In_ PDEVICE_OBJECT DeviceObject
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::Init]"));
ASSERT(DeviceObject);
NTSTATUS ntStatus = STATUS_SUCCESS;
m_pServiceGroupWave = NULL;
m_pDeviceObject = DeviceObject;
m_pPhysicalDeviceObject = NULL;
m_WdfDevice = NULL;
m_PowerState = PowerDeviceD0;
m_pPortClsEtwHelper = NULL;
InitializeListHead(&m_SubdeviceCache);
ntStatus = PcGetPhysicalDeviceObject(DeviceObject, &m_pPhysicalDeviceObject);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("PcGetPhysicalDeviceObject failed, 0x%x", ntStatus)),
Done);
ntStatus = WdfDeviceMiniportCreate(WdfGetDriver(),
WDF_NO_OBJECT_ATTRIBUTES,
DeviceObject,
NULL,
NULL,
&m_WdfDevice);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("WdfDeviceMiniportCreate failed, 0x%x", ntStatus)),
Done);
// Initialize mixer state
MixerReset();
Done:
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(void) CVadAdapterCommon::MixerReset(void)
{
PAGED_CODE();
RtlZeroMemory(m_MixerMute, sizeof(m_MixerMute));
RtlZeroMemory(m_PeakMeter, sizeof(m_PeakMeter));
m_MixerMux = 0;
m_bDevSpecific = FALSE;
m_iDevSpecific = 0;
m_uiDevSpecific = 0;
for (ULONG i = 0; i < MAX_TOPOLOGY_NODES; i++)
{
for (ULONG j = 0; j < MAX_CHANNELS; j++)
{
m_MixerVolume[i][j] = VOLUME_SIGNED_MAXIMUM;
}
}
}
//=============================================================================
#pragma code_seg()
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::WriteEtwEvent
(
_In_ EPcMiniportEngineEvent miniportEventType,
_In_ ULONGLONG ullData1,
_In_ ULONGLONG ullData2,
_In_ ULONGLONG ullData3,
_In_ ULONGLONG ullData4
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
if (m_pPortClsEtwHelper)
{
ntStatus = m_pPortClsEtwHelper->MiniportWriteEtwEvent(miniportEventType, ullData1, ullData2, ullData3, ullData4);
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(VOID) CVadAdapterCommon::SetEtwHelper(PPORTCLSETWHELPER _pPortClsEtwHelper)
{
PAGED_CODE();
SAFE_RELEASE(m_pPortClsEtwHelper);
m_pPortClsEtwHelper = _pPortClsEtwHelper;
if (m_pPortClsEtwHelper)
{
m_pPortClsEtwHelper->AddRef();
}
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP CVadAdapterCommon::NonDelegatingQueryInterface
(
_In_ REFIID Interface,
_COM_Outptr_ PVOID * Object
)
{
PAGED_CODE();
ASSERT(Object);
if (IsEqualGUIDAligned(Interface, IID_IUnknown))
{
*Object = PVOID(PUNKNOWN(PADAPTERCOMMON(this)));
}
else if (IsEqualGUIDAligned(Interface, IID_IAdapterCommon))
{
*Object = PVOID(PADAPTERCOMMON(this));
}
else if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement))
{
*Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
}
else
{
*Object = NULL;
}
if (*Object)
{
PUNKNOWN(*Object)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(void) CVadAdapterCommon::SetWaveServiceGroup(_In_ PSERVICEGROUP ServiceGroup)
{
PAGED_CODE();
SAFE_RELEASE(m_pServiceGroupWave);
m_pServiceGroupWave = ServiceGroup;
if (m_pServiceGroupWave)
{
m_pServiceGroupWave->AddRef();
}
}
//=============================================================================
// Mixer accessors
//=============================================================================
#pragma code_seg()
STDMETHODIMP_(BOOL) CVadAdapterCommon::bDevSpecificRead() { return m_bDevSpecific; }
STDMETHODIMP_(void) CVadAdapterCommon::bDevSpecificWrite(_In_ BOOL b) { m_bDevSpecific = b; }
STDMETHODIMP_(INT) CVadAdapterCommon::iDevSpecificRead() { return m_iDevSpecific; }
STDMETHODIMP_(void) CVadAdapterCommon::iDevSpecificWrite(_In_ INT i) { m_iDevSpecific = i; }
STDMETHODIMP_(UINT) CVadAdapterCommon::uiDevSpecificRead() { return m_uiDevSpecific; }
STDMETHODIMP_(void) CVadAdapterCommon::uiDevSpecificWrite(_In_ UINT ui) { m_uiDevSpecific = ui; }
STDMETHODIMP_(BOOL) CVadAdapterCommon::MixerMuteRead(_In_ ULONG Index, _In_ ULONG Channel)
{
if (Index < MAX_TOPOLOGY_NODES && Channel < MAX_CHANNELS)
{
return m_MixerMute[Index][Channel];
}
return FALSE;
}
STDMETHODIMP_(void) CVadAdapterCommon::MixerMuteWrite(_In_ ULONG Index, _In_ ULONG Channel, _In_ BOOL Value)
{
if (Index < MAX_TOPOLOGY_NODES && Channel < MAX_CHANNELS)
{
m_MixerMute[Index][Channel] = Value;
}
}
STDMETHODIMP_(ULONG) CVadAdapterCommon::MixerMuxRead(void) { return m_MixerMux; }
STDMETHODIMP_(void) CVadAdapterCommon::MixerMuxWrite(_In_ ULONG Index) { m_MixerMux = Index; }
STDMETHODIMP_(LONG) CVadAdapterCommon::MixerVolumeRead(_In_ ULONG Index, _In_ ULONG Channel)
{
if (Index < MAX_TOPOLOGY_NODES && Channel < MAX_CHANNELS)
{
return m_MixerVolume[Index][Channel];
}
return 0;
}
STDMETHODIMP_(void) CVadAdapterCommon::MixerVolumeWrite(_In_ ULONG Index, _In_ ULONG Channel, _In_ LONG Value)
{
if (Index < MAX_TOPOLOGY_NODES && Channel < MAX_CHANNELS)
{
m_MixerVolume[Index][Channel] = Value;
}
}
STDMETHODIMP_(LONG) CVadAdapterCommon::MixerPeakMeterRead(_In_ ULONG Index, _In_ ULONG Channel)
{
if (Index < MAX_TOPOLOGY_NODES && Channel < MAX_CHANNELS)
{
return m_PeakMeter[Index][Channel];
}
return 0;
}
//=============================================================================
// Power management
//=============================================================================
#pragma code_seg()
STDMETHODIMP_(void) CVadAdapterCommon::PowerChangeState(_In_ POWER_STATE NewState)
{
DPF_ENTER(("[CVadAdapterCommon::PowerChangeState]"));
PLIST_ENTRY le = NULL;
for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache; le = le->Flink)
{
MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
if (pRecord->PowerInterface)
{
pRecord->PowerInterface->PowerChangeState(NewState);
}
}
if (NewState.DeviceState != m_PowerState)
{
switch (NewState.DeviceState)
{
case PowerDeviceD0:
case PowerDeviceD1:
case PowerDeviceD2:
case PowerDeviceD3:
m_PowerState = NewState.DeviceState;
DPF(D_VERBOSE, ("Entering D%u", ULONG(m_PowerState) - ULONG(PowerDeviceD0)));
break;
default:
DPF(D_VERBOSE, ("Unknown Device Power State"));
break;
}
}
}
#pragma code_seg()
STDMETHODIMP_(NTSTATUS) CVadAdapterCommon::QueryDeviceCapabilities(
_Inout_updates_bytes_(sizeof(DEVICE_CAPABILITIES)) PDEVICE_CAPABILITIES PowerDeviceCaps
)
{
UNREFERENCED_PARAMETER(PowerDeviceCaps);
return STATUS_SUCCESS;
}
#pragma code_seg()
STDMETHODIMP_(NTSTATUS) CVadAdapterCommon::QueryPowerChangeState(_In_ POWER_STATE NewStateQuery)
{
NTSTATUS status = STATUS_SUCCESS;
PLIST_ENTRY le = NULL;
for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && NT_SUCCESS(status); le = le->Flink)
{
MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
if (pRecord->PowerInterface)
{
status = pRecord->PowerInterface->QueryPowerChangeState(NewStateQuery);
}
}
return status;
}
//=============================================================================
// Audio interface creation
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CVadAdapterCommon::CreateAudioInterfaceWithProperties
(
_In_ PCWSTR ReferenceString,
_In_ ULONG cPropertyCount,
_In_reads_opt_(cPropertyCount) const VAD_DEVPROPERTY *pProperties,
_Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::CreateAudioInterfaceWithProperties]"));
NTSTATUS ntStatus;
UNICODE_STRING referenceString;
RtlInitUnicodeString(&referenceString, ReferenceString);
RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
ntStatus = IoRegisterDeviceInterface(
GetPhysicalDeviceObject(),
&KSCATEGORY_AUDIO,
&referenceString,
AudioSymbolicLinkName);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: IoRegisterDeviceInterface failed, 0x%x", ntStatus)),
Done);
ntStatus = VadIoSetDeviceInterfacePropertyDataMultiple(AudioSymbolicLinkName, cPropertyCount, pProperties);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("VadIoSetDeviceInterfacePropertyDataMultiple failed, 0x%x", ntStatus)),
Done);
ntStatus = STATUS_SUCCESS;
Done:
if (!NT_SUCCESS(ntStatus))
{
RtlFreeUnicodeString(AudioSymbolicLinkName);
RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
}
return ntStatus;
}
//=============================================================================
// InstallSubdevice
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::InstallSubdevice
(
_In_opt_ PIRP Irp,
_In_ PWSTR Name,
_In_ REFGUID PortClassId,
_In_ REFGUID MiniportClassId,
_In_opt_ PFNCREATEMINIPORT MiniportCreate,
_In_ ULONG cPropertyCount,
_In_reads_opt_(cPropertyCount) const VAD_DEVPROPERTY * pProperties,
_In_opt_ PVOID DeviceContext,
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PRESOURCELIST ResourceList,
_In_ REFGUID PortInterfaceId,
_Out_opt_ PUNKNOWN * OutPortInterface,
_Out_opt_ PUNKNOWN * OutPortUnknown,
_Out_opt_ PUNKNOWN * OutMiniportUnknown
)
{
PAGED_CODE();
DPF_ENTER(("[InstallSubDevice %S]", Name));
ASSERT(Name != NULL);
ASSERT(m_pDeviceObject != NULL);
NTSTATUS ntStatus;
PPORT port = NULL;
PUNKNOWN miniport = NULL;
PADAPTERCOMMON adapterCommon = NULL;
UNICODE_STRING symbolicLink = { 0 };
adapterCommon = PADAPTERCOMMON(this);
ntStatus = CreateAudioInterfaceWithProperties(Name, cPropertyCount, pProperties, &symbolicLink);
if (NT_SUCCESS(ntStatus))
{
RtlFreeUnicodeString(&symbolicLink);
ntStatus = PcNewPort(&port, PortClassId);
}
if (NT_SUCCESS(ntStatus))
{
if (MiniportCreate)
{
ntStatus =
MiniportCreate
(
&miniport,
MiniportClassId,
NULL,
POOL_FLAG_NON_PAGED,
adapterCommon,
DeviceContext,
MiniportPair
);
}
else
{
ntStatus =
PcNewMiniport
(
(PMINIPORT *)&miniport,
MiniportClassId
);
}
}
if (NT_SUCCESS(ntStatus))
{
#pragma warning(push)
#pragma warning(disable:6387)
ntStatus =
port->Init
(
m_pDeviceObject,
Irp,
miniport,
adapterCommon,
ResourceList
);
#pragma warning (pop)
if (NT_SUCCESS(ntStatus))
{
ntStatus =
PcRegisterSubdevice
(
m_pDeviceObject,
Name,
port
);
}
}
if (NT_SUCCESS(ntStatus))
{
if (OutPortUnknown)
{
ntStatus = port->QueryInterface(IID_IUnknown, (PVOID *)OutPortUnknown);
}
if (OutPortInterface)
{
ntStatus = port->QueryInterface(PortInterfaceId, (PVOID *)OutPortInterface);
}
if (OutMiniportUnknown)
{
ntStatus = miniport->QueryInterface(IID_IUnknown, (PVOID *)OutMiniportUnknown);
}
}
if (port)
{
port->Release();
}
if (miniport)
{
miniport->Release();
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS) CVadAdapterCommon::UnregisterSubdevice(_In_opt_ PUNKNOWN UnknownPort)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::UnregisterSubdevice]"));
ASSERT(m_pDeviceObject != NULL);
NTSTATUS ntStatus = STATUS_SUCCESS;
PUNREGISTERSUBDEVICE unregisterSubdevice = NULL;
if (NULL == UnknownPort)
{
return ntStatus;
}
ntStatus = UnknownPort->QueryInterface(
IID_IUnregisterSubdevice,
(PVOID *)&unregisterSubdevice);
if (NT_SUCCESS(ntStatus))
{
ntStatus = unregisterSubdevice->UnregisterSubdevice(m_pDeviceObject, UnknownPort);
unregisterSubdevice->Release();
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS) CVadAdapterCommon::ConnectTopologies
(
_In_ PUNKNOWN UnknownTopology,
_In_ PUNKNOWN UnknownWave,
_In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
_In_ ULONG PhysicalConnectionCount
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::ConnectTopologies]"));
ASSERT(m_pDeviceObject != NULL);
NTSTATUS ntStatus = STATUS_SUCCESS;
for (ULONG i = 0; i < PhysicalConnectionCount && NT_SUCCESS(ntStatus); i++)
{
switch (PhysicalConnections[i].eType)
{
case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
ntStatus = PcRegisterPhysicalConnection(
m_pDeviceObject,
UnknownTopology,
PhysicalConnections[i].ulTopology,
UnknownWave,
PhysicalConnections[i].ulWave);
break;
case CONNECTIONTYPE_WAVE_OUTPUT:
ntStatus = PcRegisterPhysicalConnection(
m_pDeviceObject,
UnknownWave,
PhysicalConnections[i].ulWave,
UnknownTopology,
PhysicalConnections[i].ulTopology);
break;
}
}
if (!NT_SUCCESS(ntStatus))
{
DisconnectTopologies(UnknownTopology, UnknownWave, PhysicalConnections, PhysicalConnectionCount);
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS) CVadAdapterCommon::DisconnectTopologies
(
_In_ PUNKNOWN UnknownTopology,
_In_ PUNKNOWN UnknownWave,
_In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
_In_ ULONG PhysicalConnectionCount
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::DisconnectTopologies]"));
ASSERT(m_pDeviceObject != NULL);
NTSTATUS ntStatus = STATUS_SUCCESS;
NTSTATUS ntStatus2 = STATUS_SUCCESS;
PUNREGISTERPHYSICALCONNECTION unregisterPhysicalConnection = NULL;
ntStatus = UnknownTopology->QueryInterface(
IID_IUnregisterPhysicalConnection,
(PVOID *)&unregisterPhysicalConnection);
if (NT_SUCCESS(ntStatus))
{
for (ULONG i = 0; i < PhysicalConnectionCount; i++)
{
switch (PhysicalConnections[i].eType)
{
case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
ntStatus2 = unregisterPhysicalConnection->UnregisterPhysicalConnection(
m_pDeviceObject,
UnknownTopology,
PhysicalConnections[i].ulTopology,
UnknownWave,
PhysicalConnections[i].ulWave);
break;
case CONNECTIONTYPE_WAVE_OUTPUT:
ntStatus2 = unregisterPhysicalConnection->UnregisterPhysicalConnection(
m_pDeviceObject,
UnknownWave,
PhysicalConnections[i].ulWave,
UnknownTopology,
PhysicalConnections[i].ulTopology);
break;
}
if (NT_SUCCESS(ntStatus))
{
ntStatus = ntStatus2;
}
}
}
SAFE_RELEASE(unregisterPhysicalConnection);
return ntStatus;
}
//=============================================================================
// Sub-device cache
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS CVadAdapterCommon::GetCachedSubdevice(
_In_ PWSTR Name,
_Out_opt_ PUNKNOWN *OutUnknownPort,
_Out_opt_ PUNKNOWN *OutUnknownMiniport
)
{
PAGED_CODE();
PLIST_ENTRY le = NULL;
BOOL bFound = FALSE;
for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bFound; le = le->Flink)
{
MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
if (0 == wcscmp(Name, pRecord->Name))
{
if (OutUnknownPort)
{
*OutUnknownPort = pRecord->PortInterface;
(*OutUnknownPort)->AddRef();
}
if (OutUnknownMiniport)
{
*OutUnknownMiniport = pRecord->MiniportInterface;
(*OutUnknownMiniport)->AddRef();
}
bFound = TRUE;
}
}
return bFound ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
}
#pragma code_seg("PAGE")
NTSTATUS CVadAdapterCommon::CacheSubdevice(
_In_ PWSTR Name,
_In_ PUNKNOWN UnknownPort,
_In_ PUNKNOWN UnknownMiniport
)
{
PAGED_CODE();
NTSTATUS ntStatus = STATUS_SUCCESS;
MINIPAIR_UNKNOWN *pNewSubdevice = NULL;
pNewSubdevice = new(POOL_FLAG_NON_PAGED, VAD_ADAPTER_POOLTAG) MINIPAIR_UNKNOWN;
if (!pNewSubdevice)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus))
{
memset(pNewSubdevice, 0, sizeof(MINIPAIR_UNKNOWN));
ntStatus = RtlStringCchCopyW(pNewSubdevice->Name, SIZEOF_ARRAY(pNewSubdevice->Name), Name);
}
if (NT_SUCCESS(ntStatus))
{
pNewSubdevice->PortInterface = UnknownPort;
pNewSubdevice->PortInterface->AddRef();
pNewSubdevice->MiniportInterface = UnknownMiniport;
pNewSubdevice->MiniportInterface->AddRef();
UnknownMiniport->QueryInterface(IID_IAdapterPowerManagement, (PVOID *)&(pNewSubdevice->PowerInterface));
InsertTailList(&m_SubdeviceCache, &pNewSubdevice->ListEntry);
}
if (!NT_SUCCESS(ntStatus))
{
if (pNewSubdevice)
{
delete pNewSubdevice;
}
}
return ntStatus;
}
#pragma code_seg("PAGE")
NTSTATUS CVadAdapterCommon::RemoveCachedSubdevice(_In_ PWSTR Name)
{
PAGED_CODE();
PLIST_ENTRY le = NULL;
BOOL bRemoved = FALSE;
for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bRemoved; le = le->Flink)
{
MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
if (0 == wcscmp(Name, pRecord->Name))
{
SAFE_RELEASE(pRecord->PortInterface);
SAFE_RELEASE(pRecord->MiniportInterface);
SAFE_RELEASE(pRecord->PowerInterface);
memset(pRecord->Name, 0, sizeof(pRecord->Name));
RemoveEntryList(le);
bRemoved = TRUE;
delete pRecord;
break;
}
}
return bRemoved ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
}
#pragma code_seg("PAGE")
VOID CVadAdapterCommon::EmptySubdeviceCache()
{
PAGED_CODE();
while (!IsListEmpty(&m_SubdeviceCache))
{
PLIST_ENTRY le = RemoveHeadList(&m_SubdeviceCache);
MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
SAFE_RELEASE(pRecord->PortInterface);
SAFE_RELEASE(pRecord->MiniportInterface);
SAFE_RELEASE(pRecord->PowerInterface);
memset(pRecord->Name, 0, sizeof(pRecord->Name));
delete pRecord;
}
}
#pragma code_seg("PAGE")
STDMETHODIMP_(VOID) CVadAdapterCommon::Cleanup()
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::Cleanup]"));
EmptySubdeviceCache();
}
//=============================================================================
// InstallEndpointFilters
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::InstallEndpointFilters
(
_In_opt_ PIRP Irp,
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PVOID DeviceContext,
_Out_opt_ PUNKNOWN * UnknownTopology,
_Out_opt_ PUNKNOWN * UnknownWave,
_Out_opt_ PUNKNOWN * UnknownMiniportTopology,
_Out_opt_ PUNKNOWN * UnknownMiniportWave
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::InstallEndpointFilters]"));
NTSTATUS ntStatus = STATUS_SUCCESS;
PUNKNOWN unknownTopology = NULL;
PUNKNOWN unknownWave = NULL;
BOOL bTopologyCreated = FALSE;
BOOL bWaveCreated = FALSE;
PUNKNOWN unknownMiniTopo = NULL;
PUNKNOWN unknownMiniWave = NULL;
if (UnknownTopology) { *UnknownTopology = NULL; }
if (UnknownWave) { *UnknownWave = NULL; }
if (UnknownMiniportTopology) { *UnknownMiniportTopology = NULL; }
if (UnknownMiniportWave) { *UnknownMiniportWave = NULL; }
ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopology, &unknownMiniTopo);
if (!NT_SUCCESS(ntStatus) || NULL == unknownTopology || NULL == unknownMiniTopo)
{
bTopologyCreated = TRUE;
ntStatus = InstallSubdevice(Irp,
MiniportPair->TopoName,
CLSID_PortTopology,
CLSID_PortTopology,
MiniportPair->TopoCreateCallback,
MiniportPair->TopoInterfacePropertyCount,
MiniportPair->TopoInterfaceProperties,
DeviceContext,
MiniportPair,
NULL,
IID_IPortTopology,
NULL,
&unknownTopology,
&unknownMiniTopo);
if (NT_SUCCESS(ntStatus))
{
ntStatus = CacheSubdevice(MiniportPair->TopoName, unknownTopology, unknownMiniTopo);
}
}
ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWave, &unknownMiniWave);
if (!NT_SUCCESS(ntStatus) || NULL == unknownWave || NULL == unknownMiniWave)
{
bWaveCreated = TRUE;
ntStatus = InstallSubdevice(Irp,
MiniportPair->WaveName,
CLSID_PortWaveRT,
CLSID_PortWaveRT,
MiniportPair->WaveCreateCallback,
MiniportPair->WaveInterfacePropertyCount,
MiniportPair->WaveInterfaceProperties,
DeviceContext,
MiniportPair,
NULL,
IID_IPortWaveRT,
NULL,
&unknownWave,
&unknownMiniWave);
if (NT_SUCCESS(ntStatus))
{
ntStatus = CacheSubdevice(MiniportPair->WaveName, unknownWave, unknownMiniWave);
}
}
if (unknownTopology && unknownWave)
{
ntStatus = ConnectTopologies(
unknownTopology,
unknownWave,
MiniportPair->PhysicalConnections,
MiniportPair->PhysicalConnectionCount);
}
if (NT_SUCCESS(ntStatus))
{
if (UnknownTopology != NULL && unknownTopology != NULL)
{
unknownTopology->AddRef();
*UnknownTopology = unknownTopology;
}
if (UnknownWave != NULL && unknownWave != NULL)
{
unknownWave->AddRef();
*UnknownWave = unknownWave;
}
if (UnknownMiniportTopology != NULL && unknownMiniTopo != NULL)
{
unknownMiniTopo->AddRef();
*UnknownMiniportTopology = unknownMiniTopo;
}
if (UnknownMiniportWave != NULL && unknownMiniWave != NULL)
{
unknownMiniWave->AddRef();
*UnknownMiniportWave = unknownMiniWave;
}
}
else
{
if (bTopologyCreated && unknownTopology != NULL)
{
UnregisterSubdevice(unknownTopology);
RemoveCachedSubdevice(MiniportPair->TopoName);
}
if (bWaveCreated && unknownWave != NULL)
{
UnregisterSubdevice(unknownWave);
RemoveCachedSubdevice(MiniportPair->WaveName);
}
}
SAFE_RELEASE(unknownMiniTopo);
SAFE_RELEASE(unknownTopology);
SAFE_RELEASE(unknownMiniWave);
SAFE_RELEASE(unknownWave);
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::RemoveEndpointFilters
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_opt_ PUNKNOWN UnknownTopology,
_In_opt_ PUNKNOWN UnknownWave
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::RemoveEndpointFilters]"));
NTSTATUS ntStatus = STATUS_SUCCESS;
if (UnknownTopology != NULL && UnknownWave != NULL)
{
ntStatus = DisconnectTopologies(
UnknownTopology,
UnknownWave,
MiniportPair->PhysicalConnections,
MiniportPair->PhysicalConnectionCount);
UnregisterSubdevice(UnknownWave);
RemoveCachedSubdevice(MiniportPair->WaveName);
UnregisterSubdevice(UnknownTopology);
RemoveCachedSubdevice(MiniportPair->TopoName);
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::GetFilters
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_Out_opt_ PUNKNOWN *UnknownTopologyPort,
_Out_opt_ PUNKNOWN *UnknownTopologyMiniport,
_Out_opt_ PUNKNOWN *UnknownWavePort,
_Out_opt_ PUNKNOWN *UnknownWaveMiniport
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::GetFilters]"));
NTSTATUS ntStatus;
PUNKNOWN unknownTopoPort = NULL;
PUNKNOWN unknownTopoMiniport = NULL;
PUNKNOWN unknownWavePort = NULL;
PUNKNOWN unknownWaveMiniport = NULL;
ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopoPort, &unknownTopoMiniport);
if (!NT_SUCCESS(ntStatus))
{
goto Done;
}
ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWavePort, &unknownWaveMiniport);
if (!NT_SUCCESS(ntStatus))
{
goto Done;
}
if (UnknownTopologyPort && unknownTopoPort)
{
unknownTopoPort->AddRef();
*UnknownTopologyPort = unknownTopoPort;
}
if (UnknownTopologyMiniport && unknownTopoMiniport)
{
unknownTopoMiniport->AddRef();
*UnknownTopologyMiniport = unknownTopoMiniport;
}
if (UnknownWavePort && unknownWavePort)
{
unknownWavePort->AddRef();
*UnknownWavePort = unknownWavePort;
}
if (UnknownWaveMiniport && unknownWaveMiniport)
{
unknownWaveMiniport->AddRef();
*UnknownWaveMiniport = unknownWaveMiniport;
}
Done:
SAFE_RELEASE(unknownTopoPort);
SAFE_RELEASE(unknownTopoMiniport);
SAFE_RELEASE(unknownWavePort);
SAFE_RELEASE(unknownWaveMiniport);
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CVadAdapterCommon::SetIdlePowerManagement
(
_In_ PENDPOINT_MINIPAIR MiniportPair,
_In_ BOOL bEnabled
)
{
PAGED_CODE();
DPF_ENTER(("[CVadAdapterCommon::SetIdlePowerManagement]"));
UNREFERENCED_PARAMETER(MiniportPair);
UNREFERENCED_PARAMETER(bEnabled);
return STATUS_SUCCESS;
}
#pragma code_seg()