|
|
//---------------------------------------------------------------------------
//
// Module: gn.cpp
//
// 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"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
ULONG gcGraphRecursion = 0;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CGraphNode::CGraphNode( PDEVICE_NODE pDeviceNode, ULONG ulFlags ) { Assert(pDeviceNode); this->pDeviceNode = pDeviceNode; this->ulFlags = ulFlags; AddList(&pDeviceNode->lstGraphNode); DPF2(80, "CGraphNode %08x, DN: %08x", this, pDeviceNode); }
CGraphNode::~CGraphNode( ) { DPF1(80, "~CGraphNode: %08x", this); Assert(this); RemoveList(); }
NTSTATUS CGraphNode::Create( ) { PGRAPH_NODE_INSTANCE pGraphNodeInstance; PLOGICAL_FILTER_NODE pLogicalFilterNode; NTSTATUS Status = STATUS_SUCCESS;
DPF3(80, "CGraphNode::Create: GN %08x F %08x %s", this, this->ulFlags, pDeviceNode->DumpName());
FOR_EACH_LIST_ITEM(&pDeviceNode->lstLogicalFilterNode, pLogicalFilterNode) {
Status = Create(pLogicalFilterNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; }
} END_EACH_LIST_ITEM
if(!lstLogicalFilterNodeNoBypass.IsLstEmpty()) { lstStartNode.EnumerateList(CStartNode::RemoveBypassPaths, this); } if(this->ulFlags & FLAGS_MIXER_TOPOLOGY) { lstStartNode.EnumerateList(CStartNode::RemoveConnectedStartNode, this); } lstStartInfo.EnumerateList(CStartInfo::CreatePinInfoConnection, this);
pGraphNodeInstance = new GRAPH_NODE_INSTANCE(this); if(pGraphNodeInstance == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; Trap(); goto exit; } Status = pGraphNodeInstance->Create(); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } //
// The "ulSysaudioNodeNumber" field in the topology node isn't
// valid until CGraphNodeInstance::Create and they are only valid
// for this pGraphNode.
//
lstStartInfo.EnumerateList(CStartInfo::EnumStartInfo); delete pGraphNodeInstance; exit: return(Status); }
NTSTATUS CGraphNode::Create( PLOGICAL_FILTER_NODE pLogicalFilterNode ) { NTSTATUS Status = STATUS_SUCCESS; ULONG ulFlagsCurrent; PPIN_NODE pPinNode;
DPF2(80, "CGraphNode::Create: LFN %08x %s", pLogicalFilterNode, pLogicalFilterNode->pFilterNode->DumpName());
Assert(pLogicalFilterNode); FOR_EACH_LIST_ITEM(&pLogicalFilterNode->lstPinNode, pPinNode) {
Assert(pPinNode); Assert(pPinNode->pPinInfo); ASSERT( (pLogicalFilterNode->GetFlags() & LFN_FLAGS_REFLECT_DATARANGE) == 0); gcGraphRecursion = 0; ulFlagsCurrent = 0;
// Determine whether it is an input stream or output stream
if(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) { ulFlagsCurrent |= LFN_FLAGS_CONNECT_RENDER; } if(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) { ulFlagsCurrent |= LFN_FLAGS_CONNECT_CAPTURE; }
// Determine the kind of graph to build
if(this->ulFlags & FLAGS_MIXER_TOPOLOGY) { ulFlagsCurrent |= LFN_FLAGS_CONNECT_MIXER_TOPOLOGY; } else { ulFlagsCurrent |= LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY; }
Status = CreateGraph( pPinNode, NULL, pLogicalFilterNode, NULL, ulFlagsCurrent, pPinNode->GetOverhead() + pLogicalFilterNode->GetOverhead());
if(!NT_SUCCESS(Status)) { Trap(); goto exit; }
} END_EACH_LIST_ITEM exit: return(Status); }
NTSTATUS CGraphNode::CreateGraph( PPIN_NODE pPinNode, PCONNECT_NODE pConnectNodePrevious, PLOGICAL_FILTER_NODE pLogicalFilterNodePrevious, PGRAPH_PIN_INFO pGraphPinInfoPrevious, ULONG ulFlagsCurrent, ULONG ulOverhead ) { PLOGICAL_FILTER_NODE pLogicalFilterNode; PGRAPH_PIN_INFO pGraphPinInfo = NULL; NTSTATUS Status = STATUS_SUCCESS;
Assert(this); Assert(pPinNode); Assert(pPinNode->pPinInfo); Assert(pLogicalFilterNodePrevious); if(pConnectNodePrevious != NULL) { Assert(pConnectNodePrevious); } ASSERT(pPinNode->pLogicalFilterNode == pLogicalFilterNodePrevious);
//
// Don't allow unlimited nesting, allow graphs number of LFNs deep
//
if(gcGraphRecursion++ > (gcLogicalFilterNodes + 8)) { DPF(10, "CreateGraph: recursion too deep"); Status = STATUS_STACK_OVERFLOW; goto exit; }
if(pGraphPinInfoPrevious == NULL) { Status = CGraphPinInfo::Create( &pGraphPinInfo, pPinNode->pPinInfo, 0, this);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } pGraphPinInfoPrevious = pGraphPinInfo; }
FOR_EACH_LIST_ITEM(gplstLogicalFilterNode, pLogicalFilterNode) { ULONG ulFlagsDiff;
ASSERT(pLogicalFilterNode->GetOverhead() != OVERHEAD_NONE); //ASSERT(pLogicalFilterNode->GetOrder() != ORDER_NONE);
DPF5(100, "CreateGraph: %s F %x LFN %08x F %x T %x", pLogicalFilterNode->pFilterNode->DumpName(), ulFlagsCurrent, pLogicalFilterNode, pLogicalFilterNode->GetFlags(), pLogicalFilterNode->GetType());
//
// Rule: don't allow the same filter be connected twice
//
if(pLogicalFilterNode == pLogicalFilterNodePrevious) { DPF1(100, "CreateGraph: same LFN: %08x", pLogicalFilterNode); continue; } ulFlagsDiff = ~(ulFlagsCurrent ^ pLogicalFilterNode->GetFlags());
if((ulFlagsDiff & (LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER)) == 0) { DPF1(100, "CreateGraph: i/o no match: LFN %08x", pLogicalFilterNode); continue; } if((ulFlagsDiff & LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY) == 0) { DPF1(100, "CreateGraph: norm no match: LFN %08x", pLogicalFilterNode); continue; } if((ulFlagsDiff & LFN_FLAGS_CONNECT_MIXER_TOPOLOGY) == 0) { DPF1(100, "CreateGraph: mixer no match: LFN %08x", pLogicalFilterNode); continue; } if(pLogicalFilterNode->GetOrder() < pLogicalFilterNodePrevious->GetOrder()) { DPF2(100, "CreateGraph: ulOrder(%x) < Previous Order (%x)", pLogicalFilterNode->GetOrder(), pLogicalFilterNodePrevious->GetOrder()); continue; } #ifndef CONNECT_DIRECT_TO_HW
if(pLogicalFilterNode->GetType() & FILTER_TYPE_PRE_MIXER) { if(pLogicalFilterNodePrevious->GetOrder() < ORDER_MIXER) { if(gcMixers > 0) { // 100
DPF2(50, "CreateGraph: previous order (%x) < ORDER_MIXER LFN %08x", pLogicalFilterNodePrevious->GetOrder(), pLogicalFilterNode); continue; } } } #endif
if(!pLogicalFilterNode->pFilterNode->IsDeviceInterfaceMatch( pDeviceNode)) { DPF1(100, "CreateGraph: no dev interface match DN %08x", pDeviceNode); continue; } //
// Enumerate each "To" pin on the LFN to see if it matchs the input pin
//
Status = CreateGraphToPin( pPinNode, pConnectNodePrevious, pLogicalFilterNode, pGraphPinInfoPrevious, ulFlagsCurrent, ulOverhead);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; }
} END_EACH_LIST_ITEM // end each LFN
Status = CStartNode::Create( pPinNode, pConnectNodePrevious, pGraphPinInfoPrevious, ulFlagsCurrent, ulOverhead, this);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } exit: //
// Remove the GPI if it doesn't have any other references from SIs or CIs
//
if (pGraphPinInfo) { pGraphPinInfo->Destroy(); } gcGraphRecursion--; return(Status); }
NTSTATUS CGraphNode::CreateGraphToPin( PPIN_NODE pPinNode, PCONNECT_NODE pConnectNodePrevious, PLOGICAL_FILTER_NODE pLogicalFilterNode, PGRAPH_PIN_INFO pGraphPinInfo, ULONG ulFlagsCurrent, ULONG ulOverhead ) { PCONNECT_NODE pConnectNode = NULL; NTSTATUS Status = STATUS_SUCCESS; PPIN_NODE pPinNodeTo;
Assert(this); Assert(pPinNode); Assert(pPinNode->pPinInfo); Assert(pLogicalFilterNode);
FOR_EACH_LIST_ITEM(&pLogicalFilterNode->lstPinNode, pPinNodeTo) { Assert(pPinNodeTo); Assert(pPinNodeTo->pPinInfo); ASSERT(pPinNodeTo->pLogicalFilterNode == pLogicalFilterNode); //
// The dataflow, communication, interface, medium and data
// formats must be compatible.
//
if(!pPinNode->ComparePins(pPinNodeTo)) { DPF2(100, "CreateGraph: pins mis: PN %08x PNTo %08x", pPinNode, pPinNodeTo); continue; } Status = CConnectNode::Create( &pConnectNode, pLogicalFilterNode, pConnectNodePrevious, pGraphPinInfo, pPinNode, pPinNodeTo, ulFlagsCurrent, this);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } //
// Enumerate each "from" pin on the LFN and recurse building the graph
//
Status = CreateGraphFromPin( pPinNode, pPinNodeTo, pConnectNode, pLogicalFilterNode, pConnectNode->IsPinInstanceReserved() ? NULL : pGraphPinInfo, ulFlagsCurrent, ulOverhead);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } //
// Remove CN if it doesn't have any other refs from other CNs or SNs.
//
pConnectNode->Destroy(); pConnectNode = NULL;
} END_EACH_LIST_ITEM // end each LFN node "to" pin node
exit: if(!NT_SUCCESS(Status)) { //
// Clean up the last CN created if error
//
Trap(); pConnectNode->Destroy(); } return(Status); }
NTSTATUS CGraphNode::CreateGraphFromPin( PPIN_NODE pPinNode, PPIN_NODE pPinNodeTo, PCONNECT_NODE pConnectNode, PLOGICAL_FILTER_NODE pLogicalFilterNode, PGRAPH_PIN_INFO pGraphPinInfo, ULONG ulFlagsCurrent, ULONG ulOverhead ) { NTSTATUS Status = STATUS_SUCCESS; PPIN_NODE pPinNodeFrom;
Assert(this); Assert(pPinNode); Assert(pPinNodeTo); Assert(pPinNodeTo->pPinInfo); Assert(pLogicalFilterNode);
FOR_EACH_LIST_ITEM(&pLogicalFilterNode->lstPinNode, pPinNodeFrom) { ASSERT(pPinNodeFrom->pLogicalFilterNode == pLogicalFilterNode);
if(pPinNodeTo->pPinInfo == pPinNodeFrom->pPinInfo) { continue; } if(pLogicalFilterNode->GetFlags() & LFN_FLAGS_REFLECT_DATARANGE) {
pPinNodeFrom = new PIN_NODE(this, pPinNodeFrom); if(pPinNodeFrom == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; Trap(); goto exit; } pPinNodeFrom->pDataRange = pPinNode->pDataRange; } //
// Recurse building the graph
//
Status = CreateGraph( pPinNodeFrom, pConnectNode, pLogicalFilterNode, pGraphPinInfo, ulFlagsCurrent, ulOverhead + pPinNodeFrom->GetOverhead() + pLogicalFilterNode->GetOverhead());
if(!NT_SUCCESS(Status)) { Trap(); goto exit; }
} END_EACH_LIST_ITEM // end each LFN "from" pin node
exit: return(Status); }
//---------------------------------------------------------------------------
|