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

538 lines
13 KiB
C++

//---------------------------------------------------------------------------
//
// 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);
}
//---------------------------------------------------------------------------
#ifdef DEBUG
ENUMFUNC
CGraphNode::Dump(
)
{
Assert(this);
dprintf("GN: %08x DN %08x ulFlags: %08x ",
this,
pDeviceNode,
ulFlags);
if(ulFlags & FLAGS_MIXER_TOPOLOGY) {
dprintf("MIXER_TOPOLOGY ");
}
if(ulFlags & FLAGS_COMBINE_PINS) {
dprintf("COMBINE_PINS ");
}
if(ulFlags & GN_FLAGS_PLAYBACK) {
dprintf("PLAYBACK ");
}
if(ulFlags & GN_FLAGS_RECORD) {
dprintf("RECORD ");
}
if(ulFlags & GN_FLAGS_MIDI) {
dprintf("MIDI ");
}
dprintf("\n");
// .sgv
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
dprintf(" lstLFN:");
lstLogicalFilterNode.DumpAddress();
dprintf("\n lstGNI:");
lstGraphNodeInstance.DumpAddress();
dprintf("\n lstPN: ");
lstPinNode.DumpAddress();
dprintf("\n lstTC: ");
lstTopologyConnection.DumpAddress();
dprintf("\n lstGPI:");
lstGraphPinInfo.DumpAddress();
dprintf("\n lstSI: ");
lstStartInfo.DumpAddress();
dprintf("\n lstCI: ");
lstConnectInfo.DumpAddress();
dprintf("\n lstLfnNoBypass:");
lstLogicalFilterNodeNoBypass.DumpAddress();
dprintf("\n");
}
// .sg[x]
else {
if((ulDebugFlags & ~DEBUG_FLAGS_DETAILS) == DEBUG_FLAGS_GRAPH) {
if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
lstStartNode.Dump();
}
else {
lstStartInfo.Dump();
}
}
}
// .sgl[p][t]
if(ulDebugFlags & DEBUG_FLAGS_LOGICAL_FILTER) {
lstLogicalFilterNode.Dump();
}
// .sgt
if(ulDebugFlags & DEBUG_FLAGS_TOPOLOGY) {
lstTopologyConnection.Dump();
}
// .sgi[p][t]
if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
lstGraphNodeInstance.Dump();
}
dprintf("\n");
return(STATUS_CONTINUE);
}
#endif