#pragma warning (disable : 4127) #include #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()