388 lines
9.4 KiB
C++
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);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|