windows-nt/Source/XPSP1/NT/drivers/wdm/audio/sysaudio/topology.cpp
2020-09-26 16:20:57 +08:00

388 lines
9.4 KiB
C++

//---------------------------------------------------------------------------
//
// Module: topology.c
//
// Description:
//
//
//@@BEGIN_MSINTERNAL
// Development Team:
// Mike McLaughlin
//
// History: Date Author Comment
//
// To Do: Date Author Comment
//
//@@END_MSINTERNAL
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "common.h"
//---------------------------------------------------------------------------
ENUMFUNC
EnumerateTopology(
IN PPIN_INFO pPinInfo,
IN NTSTATUS (*Function)(
IN PTOPOLOGY_CONNECTION pTopologyConnection,
IN BOOL fToDirection,
IN OUT PVOID pReference
),
IN OUT PVOID pReference
)
{
ENUM_TOPOLOGY EnumTopology;
NTSTATUS Status;
Assert(pPinInfo);
EnumTopology.cTopologyRecursion = 0;
EnumTopology.Function = Function;
EnumTopology.fToDirection = (pPinInfo->DataFlow == KSPIN_DATAFLOW_IN);
EnumTopology.pReference = pReference;
Status = EnumeratePinInfoTopology(pPinInfo, &EnumTopology);
return(Status);
}
ENUMFUNC
EnumerateGraphTopology(
IN PSTART_INFO pStartInfo,
IN NTSTATUS (*Function)(
IN PTOPOLOGY_CONNECTION pTopologyConnection,
IN BOOL fToDirection,
IN OUT PVOID pReference
),
IN OUT PVOID pReference
)
{
PCONNECT_INFO pConnectInfo;
NTSTATUS Status;
Assert(pStartInfo);
Assert(pStartInfo->GetPinInfo());
Status = EnumerateTopology(
pStartInfo->GetPinInfo(),
Function,
pReference);
if(Status != STATUS_CONTINUE) {
goto exit;
}
for(pConnectInfo = pStartInfo->GetFirstConnectInfo();
pConnectInfo != NULL;
pConnectInfo = pConnectInfo->GetNextConnectInfo()) {
Assert(pConnectInfo);
Status = EnumerateTopology(
pConnectInfo->pPinInfoSink,
Function,
pReference);
if(Status != STATUS_CONTINUE) {
goto exit;
}
}
exit:
return(Status);
}
ENUMFUNC
EnumeratePinInfoTopology(
IN PPIN_INFO pPinInfo,
IN PENUM_TOPOLOGY pEnumTopology
)
{
PTOPOLOGY_CONNECTION pTopologyConnection;
NTSTATUS Status = STATUS_CONTINUE;
Assert(pPinInfo);
Assert(pEnumTopology);
DPF2(110, "EnumerateTopologyPinInfo %08x #%x", pPinInfo, pPinInfo->PinId);
FOR_EACH_LIST_ITEM(
&pPinInfo->lstTopologyConnection,
pTopologyConnection) {
Assert(pTopologyConnection);
if(pEnumTopology->fToDirection) {
if(pTopologyConnection->pPinInfoFrom != pPinInfo) {
continue;
}
ASSERT(pTopologyConnection->pPinInfoTo != pPinInfo);
}
else {
if(pTopologyConnection->pPinInfoTo != pPinInfo) {
continue;
}
ASSERT(pTopologyConnection->pPinInfoFrom != pPinInfo);
}
Status = EnumerateTopologyConnection(
pTopologyConnection,
pEnumTopology);
if(Status != STATUS_CONTINUE) {
goto exit;
}
} END_EACH_LIST_ITEM
exit:
return(Status);
}
ENUMFUNC
EnumerateTopologyPin(
IN PTOPOLOGY_PIN pTopologyPin,
IN PENUM_TOPOLOGY pEnumTopology
)
{
PTOPOLOGY_CONNECTION pTopologyConnection;
PTOPOLOGY_PIN pTopologyPin2;
NTSTATUS Status = STATUS_CONTINUE;
BOOL fFromPinEqual = TRUE;
ULONG ulFromPinNumber = MAXULONG;
BOOL fToPinEqual = TRUE;
ULONG ulToPinNumber = MAXULONG;
BOOL fPinEqual;
ULONG ulPinNumber;
Assert(pTopologyPin);
Assert(pEnumTopology);
DPF3(110, "EnumerateTopologyPin %08x TP #%x TN #%x",
pTopologyPin,
pTopologyPin->ulPinNumber,
pTopologyPin->pTopologyNode->ulRealNodeNumber);
if(IsEqualGUID(
&KSNODETYPE_ACOUSTIC_ECHO_CANCEL,
pTopologyPin->pTopologyNode->pguidType)) {
switch(pTopologyPin->ulPinNumber) {
case KSNODEPIN_AEC_RENDER_OUT:
ASSERT(!pEnumTopology->fToDirection);
case KSNODEPIN_AEC_RENDER_IN:
ulFromPinNumber = KSNODEPIN_AEC_RENDER_IN;
ulToPinNumber = KSNODEPIN_AEC_RENDER_OUT;
break;
case KSNODEPIN_AEC_CAPTURE_OUT:
ASSERT(!pEnumTopology->fToDirection);
case KSNODEPIN_AEC_CAPTURE_IN:
ulFromPinNumber = KSNODEPIN_AEC_CAPTURE_IN;
ulToPinNumber = KSNODEPIN_AEC_CAPTURE_OUT;
break;
}
}
else if(IsEqualGUID(
&KSNODETYPE_SUM,
pTopologyPin->pTopologyNode->pguidType) ||
IsEqualGUID(
&KSNODETYPE_MUX,
pTopologyPin->pTopologyNode->pguidType)) {
ulFromPinNumber = KSNODEPIN_SUM_MUX_IN;
fFromPinEqual = FALSE;
ulToPinNumber = KSNODEPIN_SUM_MUX_OUT;
}
else if(IsEqualGUID(
&KSNODETYPE_DEMUX,
pTopologyPin->pTopologyNode->pguidType)) {
ulFromPinNumber = KSNODEPIN_DEMUX_IN;
ulToPinNumber = KSNODEPIN_DEMUX_OUT;
fToPinEqual = FALSE;
}
else {
ulFromPinNumber = KSNODEPIN_STANDARD_IN;
ulToPinNumber = KSNODEPIN_STANDARD_OUT;
}
// Swap pin numbers and flags
if(!pEnumTopology->fToDirection) {
ulPinNumber = ulToPinNumber;
ulToPinNumber = ulFromPinNumber;
ulFromPinNumber = ulPinNumber;
fPinEqual = fToPinEqual;
fToPinEqual = fFromPinEqual;
fFromPinEqual = fPinEqual;
}
ASSERT(ulToPinNumber != MAXULONG);
ASSERT(ulFromPinNumber != MAXULONG);
// Validate input/from pin(s)
if(fFromPinEqual) {
if(pTopologyPin->ulPinNumber != ulFromPinNumber) {
DPF2(5, "EnumerateTopologyPin: %s bad 'from' pin number %08x",
pTopologyPin->pTopologyNode->pFilterNode->DumpName(),
pTopologyPin->ulPinNumber);
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
}
else {
if(pTopologyPin->ulPinNumber < ulFromPinNumber) {
DPF2(5, "EnumerateTopologyPin: %s bad 'from' pin number %08x",
pTopologyPin->pTopologyNode->pFilterNode->DumpName(),
pTopologyPin->ulPinNumber);
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
}
FOR_EACH_LIST_ITEM(
&pTopologyPin->pTopologyNode->lstTopologyPin,
pTopologyPin2) {
if(pTopologyPin == pTopologyPin2) {
continue;
}
// Pick the right output/to pin(s)
if(fToPinEqual) {
if(pTopologyPin2->ulPinNumber != ulToPinNumber) {
continue;
}
}
else {
if(pTopologyPin2->ulPinNumber < ulToPinNumber) {
continue;
}
}
FOR_EACH_LIST_ITEM(
&pTopologyPin2->lstTopologyConnection,
pTopologyConnection) {
Assert(pTopologyConnection);
if(pEnumTopology->fToDirection) {
if(pTopologyConnection->pTopologyPinFrom != pTopologyPin2) {
continue;
}
ASSERT(pTopologyConnection->pTopologyPinTo != pTopologyPin2);
}
else {
if(pTopologyConnection->pTopologyPinTo != pTopologyPin2) {
continue;
}
ASSERT(pTopologyConnection->pTopologyPinFrom != pTopologyPin2);
}
Status = EnumerateTopologyConnection(
pTopologyConnection,
pEnumTopology);
if(Status != STATUS_CONTINUE) {
goto exit;
}
} END_EACH_LIST_ITEM
} END_EACH_LIST_ITEM
exit:
return(Status);
}
ENUMFUNC
EnumerateTopologyConnection(
IN PTOPOLOGY_CONNECTION pTopologyConnection,
IN PENUM_TOPOLOGY pEnumTopology
)
{
PTOPOLOGY_PIN pTopologyPin;
PPIN_INFO pPinInfo;
NTSTATUS Status;
Assert(pEnumTopology);
Assert(pTopologyConnection);
DPF1(110, "EnumerateTopologyConnection %08x", pTopologyConnection);
if(pEnumTopology->cTopologyRecursion++ > (gcTopologyConnections + 16)) {
Trap();
DPF(5, "EnumerateTopologyConnection: recursion too deep");
Status = STATUS_STACK_OVERFLOW;
goto exit;
}
// Have we visited this topology connection already?
Status = VisitedTopologyConnection(pTopologyConnection, pEnumTopology);
if(Status != STATUS_CONTINUE) {
if(Status == STATUS_DEAD_END) {
Status = STATUS_CONTINUE;
}
goto exit;
}
Status = (*pEnumTopology->Function)(
pTopologyConnection,
pEnumTopology->fToDirection,
pEnumTopology->pReference);
if(Status != STATUS_CONTINUE) {
if(Status == STATUS_DEAD_END) {
Status = STATUS_CONTINUE;
}
goto exit;
}
if(pEnumTopology->fToDirection) {
pTopologyPin = pTopologyConnection->pTopologyPinTo;
pPinInfo = pTopologyConnection->pPinInfoTo;
}
else {
pTopologyPin = pTopologyConnection->pTopologyPinFrom;
pPinInfo = pTopologyConnection->pPinInfoFrom;
}
if(pTopologyPin != NULL) {
Status = EnumerateTopologyPin(pTopologyPin, pEnumTopology);
if(Status != STATUS_CONTINUE) {
goto exit;
}
}
if(pPinInfo != NULL) {
Status = EnumeratePinInfoTopology(pPinInfo, pEnumTopology);
if(Status != STATUS_CONTINUE) {
goto exit;
}
}
exit:
pEnumTopology->cTopologyRecursion--;
return(Status);
}
ENUMFUNC
VisitedTopologyConnection(
IN PTOPOLOGY_CONNECTION pTopologyConnection,
IN PENUM_TOPOLOGY pEnumTopology
)
{
NTSTATUS Status;
Assert(pEnumTopology);
Assert(pTopologyConnection);
// Have we visited this topology connection already?
if(pTopologyConnection->CheckDupList(
&pEnumTopology->lstTopologyConnection)) {
DPF1(100, "VisitedTopologyConnection: %08x already visited",
pTopologyConnection);
Status = STATUS_DEAD_END;
goto exit; // yes, break cycle in topology
}
// Add topology pin to list of pin's visited
Status = pTopologyConnection->AddList(
&pEnumTopology->lstTopologyConnection);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = STATUS_CONTINUE;
exit:
return(Status);
}
//---------------------------------------------------------------------------