//--------------------------------------------------------------------------- // // Module: tc.cpp // // Description: // // Topology Connection Class // //@@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" //--------------------------------------------------------------------------- ULONG gcTopologyConnections = 0; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- CTopologyConnection::CTopologyConnection( PTOPOLOGY_PIN pTopologyPinFrom, PTOPOLOGY_PIN pTopologyPinTo, PPIN_INFO pPinInfoFrom, PPIN_INFO pPinInfoTo ) { #ifdef DEBUG DPF4(110, "CTopologyConnection: PIF: %08x PIT: %08x TPF: %08x TPT: %08x", pPinInfoFrom, pPinInfoTo, pTopologyPinFrom, pTopologyPinTo); #endif this->pTopologyPinFrom = pTopologyPinFrom; this->pTopologyPinTo = pTopologyPinTo; this->pPinInfoFrom = pPinInfoFrom; this->pPinInfoTo = pPinInfoTo; ASSERT(TOPC_FLAGS_FILTER_CONNECTION_TYPE == 0); ++gcTopologyConnections; DPF1(70, "CTopologyConnection: %08x", this); } CTopologyConnection::~CTopologyConnection( ) { Assert(this); DPF1(70, "~CTopologyConnection: %08x", this); --gcTopologyConnections; } NTSTATUS CTopologyConnection::Create( PTOPOLOGY_CONNECTION *ppTopologyConnection, PFILTER_NODE pFilterNode, PGRAPH_NODE pGraphNode, PTOPOLOGY_PIN pTopologyPinFrom, PTOPOLOGY_PIN pTopologyPinTo, PPIN_INFO pPinInfoFrom, PPIN_INFO pPinInfoTo ) { NTSTATUS Status = STATUS_SUCCESS; PTOPOLOGY_CONNECTION pTopologyConnection; PLIST_DESTROY_TOPOLOGY_CONNECTION plstTopologyConnection; PFILTER_NODE pFilterNodeNext; #ifdef DEBUG DPF4(110, "CTopologyConnection::Create: PIF: %08x PIT: %08x TPF: %08x TPT: %08x", pPinInfoFrom, pPinInfoTo, pTopologyPinFrom, pTopologyPinTo); #endif ASSERT(pFilterNode != NULL || pGraphNode != NULL); pTopologyConnection = new TOPOLOGY_CONNECTION( pTopologyPinFrom, pTopologyPinTo, pPinInfoFrom, pPinInfoTo ); if(pTopologyConnection == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; Trap(); goto exit; } *ppTopologyConnection = pTopologyConnection; if(pFilterNode != NULL) { Assert(pFilterNode); ASSERT(pGraphNode == NULL); // Adding connection to filter connection list plstTopologyConnection = &pFilterNode->lstTopologyConnection; // Check if duplicate connection on filter list FOR_EACH_LIST_ITEM( &pFilterNode->lstConnectedFilterNode, pFilterNodeNext) { if(pFilterNodeNext->lstTopologyConnection.EnumerateList( CTopologyConnection::CheckDuplicate, ppTopologyConnection) == STATUS_SUCCESS) { ASSERT(NT_SUCCESS(Status)); DPF(70, "CTopologyConnection::Create: Duplicate 1"); delete pTopologyConnection; goto exit; } } END_EACH_LIST_ITEM } if(pGraphNode != NULL) { PLOGICAL_FILTER_NODE pLogicalFilterNode; Assert(pGraphNode); ASSERT(pFilterNode == NULL); // Adding connection to GraphNode connection list plstTopologyConnection = &pGraphNode->lstTopologyConnection; // Check if duplicate on GraphNode's logical filter list FOR_EACH_LIST_ITEM( &pGraphNode->pDeviceNode->lstLogicalFilterNode, pLogicalFilterNode) { if(pLogicalFilterNode->lstTopologyConnection.EnumerateList( CTopologyConnection::CheckDuplicate, ppTopologyConnection) == STATUS_SUCCESS) { ASSERT(NT_SUCCESS(Status)); DPF(70, "CTopologyConnection::Create: Duplicate 2"); delete pTopologyConnection; goto exit; } } END_EACH_LIST_ITEM // Check if duplicate on GraphNode's connected filter list FOR_EACH_LIST_ITEM( &pGraphNode->lstLogicalFilterNode, pLogicalFilterNode) { if(pLogicalFilterNode->lstTopologyConnection.EnumerateList( CTopologyConnection::CheckDuplicate, ppTopologyConnection) == STATUS_SUCCESS) { ASSERT(NT_SUCCESS(Status)); DPF(70, "CTopologyConnection::Create: Duplicate 3"); delete pTopologyConnection; goto exit; } } END_EACH_LIST_ITEM pTopologyConnection->ulFlags = TOPC_FLAGS_GRAPH_CONNECTION_TYPE; } // Check for duplicate topology connections if(plstTopologyConnection->EnumerateList( CTopologyConnection::CheckDuplicate, ppTopologyConnection) == STATUS_SUCCESS) { DPF(70, "CTopologyConnection::Create: Duplicate 4"); ASSERT(NT_SUCCESS(Status)); delete pTopologyConnection; goto exit; } if(pTopologyPinFrom != NULL) { Assert(pTopologyConnection); Status = pTopologyConnection->AddListEnd( &pTopologyPinFrom->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } if(pTopologyPinTo != NULL) { Assert(pTopologyConnection); Status = pTopologyConnection->AddListEnd( &pTopologyPinTo->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } if(pPinInfoFrom != NULL) { Assert(pTopologyConnection); Status = pTopologyConnection->AddListEnd( &pPinInfoFrom->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } if(pPinInfoTo != NULL) { Assert(pTopologyConnection); Status = pTopologyConnection->AddListEnd( &pPinInfoTo->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } Status = pTopologyConnection->AddListEnd(plstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } exit: DPF3(70, "CTopologyConnection::Create: %08x, FN: %08x GN: %08x", *ppTopologyConnection, pFilterNode, pGraphNode); return(Status); } ENUMFUNC CTopologyConnection::CheckDuplicate( PVOID pReference ) { PTOPOLOGY_CONNECTION *ppTopologyConnection = (PTOPOLOGY_CONNECTION*)pReference; if((this->pTopologyPinFrom == (*ppTopologyConnection)->pTopologyPinFrom) && (this->pTopologyPinTo == (*ppTopologyConnection)->pTopologyPinTo) && (this->pPinInfoFrom == (*ppTopologyConnection)->pPinInfoFrom) && (this->pPinInfoTo == (*ppTopologyConnection)->pPinInfoTo)) { *ppTopologyConnection = this; return(STATUS_SUCCESS); } return(STATUS_CONTINUE); } BOOL CTopologyConnection::IsTopologyConnectionOnGraphNode( PGRAPH_NODE pGraphNode ) { PLOGICAL_FILTER_NODE pLogicalFilterNodeFrom; PLOGICAL_FILTER_NODE pLogicalFilterNodeTo; PLOGICAL_FILTER_NODE pLogicalFilterNode; BOOL fStatusFrom = FALSE; BOOL fStatusTo = FALSE; Assert(pGraphNode); if(pPinInfoFrom != NULL || pPinInfoTo != NULL) { return(TRUE); } if(pTopologyPinFrom == NULL || pTopologyPinTo == NULL) { return(FALSE); } Assert(pTopologyPinFrom); Assert(pTopologyPinTo); FOR_EACH_LIST_ITEM( &pTopologyPinFrom->pTopologyNode->lstLogicalFilterNode, pLogicalFilterNodeFrom) { Assert(pLogicalFilterNodeFrom); FOR_EACH_LIST_ITEM( &pTopologyPinTo->pTopologyNode->lstLogicalFilterNode, pLogicalFilterNodeTo) { FOR_EACH_LIST_ITEM( &pGraphNode->pDeviceNode->lstLogicalFilterNode, pLogicalFilterNode) { Assert(pLogicalFilterNode); if(pLogicalFilterNode == pLogicalFilterNodeFrom) { fStatusFrom = TRUE; } if(pLogicalFilterNode == pLogicalFilterNodeTo) { fStatusTo = TRUE; } } END_EACH_LIST_ITEM if(fStatusFrom && fStatusTo) { goto exit; } FOR_EACH_LIST_ITEM( &pGraphNode->lstLogicalFilterNode, pLogicalFilterNode) { Assert(pLogicalFilterNode); if(pLogicalFilterNode == pLogicalFilterNodeFrom) { fStatusFrom = TRUE; } if(pLogicalFilterNode == pLogicalFilterNodeTo) { fStatusTo = TRUE; } } END_EACH_LIST_ITEM if(fStatusFrom && fStatusTo) { goto exit; } } END_EACH_LIST_ITEM } END_EACH_LIST_ITEM exit: return(fStatusFrom && fStatusTo); } NTSTATUS AddPinToFilterNode( PTOPOLOGY_PIN pTopologyPin, PFILTER_NODE pFilterNode ) { NTSTATUS Status = STATUS_SUCCESS; PFILTER_NODE pFilterNodeNext; Assert(pFilterNode); Assert(pTopologyPin); Assert(pTopologyPin->pTopologyNode->pFilterNode); // // Add to filter node to connected filter node list // if(pFilterNode != pTopologyPin->pTopologyNode->pFilterNode) { Status = pFilterNode->lstConnectedFilterNode.AddList( pTopologyPin->pTopologyNode->pFilterNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } // Hack for ds1wdm dmus synth topology (adds dmus to wave FN lst) if((pFilterNode->GetType() & FILTER_TYPE_ENDPOINT) == 0) { DPF2(50, "AddPinToFilterNode: (from) FN: %08x %s", pFilterNode, pFilterNode->DumpName()); FOR_EACH_LIST_ITEM( &pTopologyPin->pTopologyNode->pFilterNode->lstConnectedFilterNode, pFilterNodeNext) { if(pFilterNodeNext == pFilterNode || pFilterNodeNext == pTopologyPin->pTopologyNode->pFilterNode) { continue; } DPF2(50, "AddPinToFilterNode: (to) FN: %08x %s", pFilterNodeNext, pFilterNodeNext->DumpName()); Status = pFilterNodeNext->lstConnectedFilterNode.AddList( pFilterNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } END_EACH_LIST_ITEM } // // This fixes the bug with capture only devices. The topology for // capture only devices was not built properly, due to the missing // link between wave filter and topology filter. // Add the topology filter to wave filter ConnectedFilterNode list. // The AddList function does not allow duplicate entries. // if ((pFilterNode->GetType() & FILTER_TYPE_TOPOLOGY) && (pTopologyPin->pTopologyNode->pFilterNode->GetType() & (FILTER_TYPE_CAPTURER))) { Status = pTopologyPin->pTopologyNode->pFilterNode->lstConnectedFilterNode.AddList( pFilterNode); DPF3(20, "AddPinToFilterNode: (CAPTURE ONLY) FN: %08x FN: %08x %s", pTopologyPin->pTopologyNode->pFilterNode, pFilterNode, pFilterNode->DumpName()); } } exit: return(Status); } NTSTATUS AddPinToGraphNode( PTOPOLOGY_PIN pTopologyPin, PGRAPH_NODE pGraphNode, PTOPOLOGY_CONNECTION pTopologyConnection ) { PLOGICAL_FILTER_NODE pLogicalFilterNode2; PLOGICAL_FILTER_NODE pLogicalFilterNode; PTOPOLOGY_CONNECTION pTopologyConnection2; NTSTATUS Status = STATUS_SUCCESS; BOOL fAddLogicalFilterNode; Assert(pTopologyPin); Assert(pTopologyPin->pTopologyNode); Assert(pGraphNode); FOR_EACH_LIST_ITEM( &pTopologyPin->pTopologyNode->lstLogicalFilterNode, pLogicalFilterNode) { fAddLogicalFilterNode = FALSE; FOR_EACH_LIST_ITEM( &pLogicalFilterNode->lstTopologyConnection, pTopologyConnection2) { Assert(pTopologyConnection2); if(pTopologyPin == pTopologyConnection2->pTopologyPinFrom || pTopologyPin == pTopologyConnection2->pTopologyPinTo) { fAddLogicalFilterNode = TRUE; break; } } END_EACH_LIST_ITEM if(fAddLogicalFilterNode) { FOR_EACH_LIST_ITEM( &pGraphNode->pDeviceNode->lstLogicalFilterNode, pLogicalFilterNode2) { Assert(pLogicalFilterNode2); if(pLogicalFilterNode == pLogicalFilterNode2) { fAddLogicalFilterNode = FALSE; break; } } END_EACH_LIST_ITEM } if(fAddLogicalFilterNode) { Status = pGraphNode->lstLogicalFilterNode.AddList( pLogicalFilterNode, pTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } } } END_EACH_LIST_ITEM exit: return(Status); } NTSTATUS CreatePinInfoConnection( PTOPOLOGY_CONNECTION *ppTopologyConnection, PFILTER_NODE pFilterNode, PGRAPH_NODE pGraphNode, PPIN_INFO pPinInfoSource, PPIN_INFO pPinInfoSink ) { PTOPOLOGY_CONNECTION pTopologyConnectionSource; PTOPOLOGY_CONNECTION pTopologyConnectionSink; PTOPOLOGY_PIN pTopologyPinFrom; PTOPOLOGY_PIN pTopologyPinTo; NTSTATUS Status = STATUS_SUCCESS; Assert(pPinInfoSource); Assert(pPinInfoSink); ASSERT(pPinInfoSource != pPinInfoSink); FOR_EACH_LIST_ITEM( &pPinInfoSource->lstTopologyConnection, pTopologyConnectionSource) { Assert(pTopologyConnectionSource); if(!IS_CONNECTION_TYPE(pTopologyConnectionSource, FILTER)) { continue; } pTopologyPinFrom = NULL; pTopologyPinTo = NULL; if(pTopologyConnectionSource->pTopologyPinFrom != NULL) { ASSERT(pTopologyConnectionSource->pPinInfoTo == pPinInfoSource); ASSERT(pTopologyConnectionSource->pPinInfoFrom == NULL); ASSERT(pTopologyConnectionSource->pTopologyPinTo == NULL); pTopologyPinFrom = pTopologyConnectionSource->pTopologyPinFrom; } if(pTopologyConnectionSource->pTopologyPinTo != NULL) { ASSERT(pTopologyConnectionSource->pPinInfoFrom == pPinInfoSource); ASSERT(pTopologyConnectionSource->pPinInfoTo == NULL); ASSERT(pTopologyConnectionSource->pTopologyPinFrom == NULL); pTopologyPinTo = pTopologyConnectionSource->pTopologyPinTo; } FOR_EACH_LIST_ITEM( &pPinInfoSink->lstTopologyConnection, pTopologyConnectionSink) { Assert(pTopologyConnectionSink); if(!IS_CONNECTION_TYPE(pTopologyConnectionSink, FILTER)) { continue; } if(pTopologyConnectionSink->pTopologyPinFrom != NULL) { ASSERT(pTopologyConnectionSink->pPinInfoTo == pPinInfoSink); ASSERT(pTopologyConnectionSink->pPinInfoFrom == NULL); ASSERT(pTopologyConnectionSink->pTopologyPinTo == NULL); pTopologyPinFrom = pTopologyConnectionSink->pTopologyPinFrom; } if(pTopologyConnectionSink->pTopologyPinTo != NULL) { ASSERT(pTopologyConnectionSink->pPinInfoFrom == pPinInfoSink); ASSERT(pTopologyConnectionSink->pPinInfoTo == NULL); ASSERT(pTopologyConnectionSink->pTopologyPinFrom == NULL); pTopologyPinTo = pTopologyConnectionSink->pTopologyPinTo; } ASSERT(pTopologyPinFrom != NULL); ASSERT(pTopologyPinTo != NULL); Status = CTopologyConnection::Create( ppTopologyConnection, pFilterNode, pGraphNode, pTopologyPinFrom, // DataFlow == OUT, Pin #0 pTopologyPinTo, // DataFlow == IN, Pin #1 - n NULL, NULL); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } // Add the connections to the PinInfos Assert(*ppTopologyConnection); Status = (*ppTopologyConnection)->AddListEnd( &pPinInfoSource->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } Status = (*ppTopologyConnection)->AddListEnd( &pPinInfoSink->lstTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } if(pFilterNode != NULL) { Assert(pFilterNode); Status = AddPinToFilterNode(pTopologyPinFrom, pFilterNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } Status = AddPinToFilterNode(pTopologyPinTo, pFilterNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } // Change the connection type to physical (*ppTopologyConnection)->ulFlags = TOPC_FLAGS_PHYSICAL_CONNECTION_TYPE; } if(pGraphNode != NULL) { Assert(pGraphNode); Status = AddPinToGraphNode( pTopologyPinFrom, pGraphNode, *ppTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } Status = AddPinToGraphNode( pTopologyPinTo, pGraphNode, *ppTopologyConnection); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } ASSERT(IS_CONNECTION_TYPE(*ppTopologyConnection, GRAPH)); } } END_EACH_LIST_ITEM } END_EACH_LIST_ITEM exit: return(Status); } //--------------------------------------------------------------------------- #ifdef DEBUG ENUMFUNC CTopologyConnection::Dump( ) { PWSTR pwstrNameFrom = L""; PWSTR pwstrNameTo = L""; ULONG ulFromNode = MAXULONG; ULONG ulToNode = MAXULONG; ULONG ulFromPin = MAXULONG; ULONG ulToPin = MAXULONG; Assert(this); if(pTopologyPinFrom != NULL && pTopologyPinTo != NULL && pTopologyPinFrom->pTopologyNode->pFilterNode != pTopologyPinTo->pTopologyNode->pFilterNode) { pwstrNameFrom = pTopologyPinFrom->pTopologyNode-> pFilterNode->GetFriendlyName(); pwstrNameTo = pTopologyPinTo->pTopologyNode-> pFilterNode->GetFriendlyName(); } if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) { dprintf("TC: %08x ulFlags %08x ", this, ulFlags); if(IS_CONNECTION_TYPE(this, FILTER)) { dprintf("FILTER"); } if(IS_CONNECTION_TYPE(this, PHYSICAL)) { dprintf("PHYSICAL"); } if(IS_CONNECTION_TYPE(this, GRAPH)) { dprintf("GRAPH"); } dprintf("\n"); if(pTopologyPinFrom != NULL) { dprintf(" TPFrom: %08x TN %08x #%02x Pin # %d %s\n", pTopologyPinFrom, pTopologyPinFrom->pTopologyNode, pTopologyPinFrom->pTopologyNode->ulRealNodeNumber, pTopologyPinFrom->ulPinNumber, DbgUnicode2Sz(pwstrNameFrom)); } if(pPinInfoFrom != NULL) { dprintf(" PIFrom: %08x Pin # %d\n", pPinInfoFrom, pPinInfoFrom->PinId); } if(pTopologyPinTo != NULL) { dprintf(" TPTo: %08x TN %08x #%02x Pin # %d %s\n", pTopologyPinTo, pTopologyPinTo->pTopologyNode, pTopologyPinTo->pTopologyNode->ulRealNodeNumber, pTopologyPinTo->ulPinNumber, DbgUnicode2Sz(pwstrNameTo)); } if(pPinInfoTo != NULL) { dprintf(" PITo: %08x Pin # %d\n", pPinInfoTo, pPinInfoTo->PinId); } dprintf("\n"); } else { if(pTopologyPinFrom != NULL) { ulFromNode = pTopologyPinFrom->pTopologyNode->ulRealNodeNumber; ulFromPin = pTopologyPinFrom->ulPinNumber; } if(pTopologyPinTo != NULL) { ulToNode = pTopologyPinTo->pTopologyNode->ulRealNodeNumber; ulToPin = pTopologyPinTo->ulPinNumber; } if(pPinInfoFrom != NULL) { ulFromPin = pPinInfoFrom->PinId; } if(pPinInfoTo != NULL) { ulToPin = pPinInfoTo->PinId; } if(ulFromNode == KSFILTER_NODE) { dprintf("TC: %08x From: Filter P#%-2d %s\n", this, ulFromPin, DbgUnicode2Sz(pwstrNameFrom)); } else { dprintf("TC: %08x From: N#%-2d P#%-2d %s\n", this, ulFromNode, ulFromPin, DbgUnicode2Sz(pwstrNameFrom)); } if(ulToNode == KSFILTER_NODE) { dprintf(" To: Filter P#%-2d %s\n", ulToPin, DbgUnicode2Sz(pwstrNameTo)); } else { dprintf(" To: N#%-2d P#%-2d %s\n", ulToNode, ulToPin, DbgUnicode2Sz(pwstrNameTo)); } } return(STATUS_CONTINUE); } #endif //---------------------------------------------------------------------------