windows-nt/Source/XPSP1/NT/drivers/ddk/wdmaudio/ac97/driver/mintopo.cpp

2105 lines
75 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/********************************************************************************
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
**
** Portions Copyright (c) 1998-1999 Intel Corporation
**
********************************************************************************/
// Every debug output has "Modulname text".
static char STR_MODULENAME[] = "ICH Topology: ";
#include "mintopo.h"
/*****************************************************************************
* AC97 topology miniport tables
*/
/*****************************************************************************
* PinDataRangesBridge
*****************************************************************************
* Structures indicating range of valid format values for bridge pins.
*/
static KSDATARANGE PinDataRangesAnalogBridge[] =
{
{
sizeof(KSDATARANGE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
}
};
/*****************************************************************************
* PinDataRangePointersBridge
*****************************************************************************
* List of pointers to structures indicating range of valid format values
* for audio bridge pins.
*/
static PKSDATARANGE PinDataRangePointersAnalogBridge[] =
{
(PKSDATARANGE)&PinDataRangesAnalogBridge[0]
};
/*****************************************************************************
* PropertiesVolume
*****************************************************************************
* Properties for volume controls.
*/
static PCPROPERTY_ITEM PropertiesVolume[] =
{
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_VOLUMELEVEL,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
CMiniportTopologyICH::PropertyHandler_Level
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* AutomationVolume
*****************************************************************************
* Automation table for volume controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (AutomationVolume, PropertiesVolume);
/*****************************************************************************
* PropertiesMute
*****************************************************************************
* Properties for mute controls.
*/
static PCPROPERTY_ITEM PropertiesMute[] =
{
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MUTE,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET,
CMiniportTopologyICH::PropertyHandler_OnOff
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* AutomationMute
*****************************************************************************
* Automation table for mute controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (AutomationMute, PropertiesMute);
/*****************************************************************************
* PropertiesMux
*****************************************************************************
* Properties for mux controls.
*/
static PCPROPERTY_ITEM PropertiesMux[] =
{
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MUX_SOURCE,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET,
CMiniportTopologyICH::PropertyHandler_Ulong
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* AutomationMux
*****************************************************************************
* Automation table for mux controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (AutomationMux, PropertiesMux);
/*****************************************************************************
* PropertiesSpecial
*****************************************************************************
* Properties for Special controls like fake loudness and fake agc.
*/
static PCPROPERTY_ITEM PropertiesSpecial[] =
{
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_AGC,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET,
CMiniportTopologyICH::PropertyHandler_OnOff
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_LOUDNESS,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET,
CMiniportTopologyICH::PropertyHandler_OnOff
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* AutomationAgc
*****************************************************************************
* Automation table for agc controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (AutomationSpecial, PropertiesSpecial);
/*****************************************************************************
* PropertiesTone
*****************************************************************************
* Properties for tone controls.
*/
static PCPROPERTY_ITEM PropertiesTone[] =
{
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_BASS,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
CMiniportTopologyICH::PropertyHandler_Tone
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_TREBLE,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
CMiniportTopologyICH::PropertyHandler_Tone
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* AutomationTone
*****************************************************************************
* Automation table for tone controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (AutomationTone, PropertiesTone);
/*****************************************************************************
* Properties3D
*****************************************************************************
* Properties for 3D controls.
*/
static PCPROPERTY_ITEM Properties3D[] =
{
// are faky volume controls.
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_VOLUMELEVEL,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
CMiniportTopologyICH::PropertyHandler_Tone
},
{
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_CPU_RESOURCES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_CpuResources
}
};
/*****************************************************************************
* Automation3D
*****************************************************************************
* Automation table for 3D controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (Automation3D, Properties3D);
#ifdef INCLUDE_PRIVATE_PROPERTY
/*****************************************************************************
* FilterPropertiesPrivate
*****************************************************************************
* Properties for AC97 features.
*/
static PCPROPERTY_ITEM FilterPropertiesPrivate[] =
{
// This is a private property for getting the AC97 codec features.
{
&KSPROPSETID_Private,
KSPROPERTY_AC97_FEATURES,
KSPROPERTY_TYPE_GET,
CMiniportTopologyICH::PropertyHandler_Private
}
#ifdef PROPERTY_SHOW_SET
,
// This is a private property for getting the AC97 codec features.
{
&KSPROPSETID_Private,
KSPROPERTY_AC97_SAMPLE_SET,
KSPROPERTY_TYPE_SET,
CMiniportTopologyICH::PropertyHandler_Private
}
#endif
};
/*****************************************************************************
* FilterAutomationPrivate
*****************************************************************************
* Filter's automation table for private property controls.
*/
DEFINE_PCAUTOMATION_TABLE_PROP (FilterAutomationPrivate, FilterPropertiesPrivate);
#endif
#pragma code_seg("PAGE")
/*****************************************************************************
* CreateMiniportTopologyICH
*****************************************************************************
* Creates a topology miniport object for the ICH audio adapter. This uses a
* macro from STDUNK.H to do all the work.
*/
NTSTATUS CreateMiniportTopologyICH
(
OUT PUNKNOWN * Unknown,
IN REFCLSID,
IN PUNKNOWN UnknownOuter OPTIONAL,
IN POOL_TYPE PoolType
)
{
PAGED_CODE ();
ASSERT (Unknown);
STD_CREATE_BODY (CMiniportTopologyICH, Unknown, UnknownOuter, PoolType);
}
/*****************************************************************************
* CMiniportTopologyICH::NonDelegatingQueryInterface
*****************************************************************************
* Obtains an interface. This function works just like a COM QueryInterface
* call and is used if the object is not being aggregated.
* We basically just check any GUID we know and return this object in case we
* know it.
*/
STDMETHODIMP_(NTSTATUS) CMiniportTopologyICH::NonDelegatingQueryInterface
(
IN REFIID Interface,
OUT PVOID * Object
)
{
PAGED_CODE ();
ASSERT (Object);
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::NonDelegatingQueryInterface]"));
// Is it IID_IUnknown?
if (IsEqualGUIDAligned (Interface, IID_IUnknown))
{
*Object = (PVOID)(PUNKNOWN)this;
}
else
// or IID_IMiniport ...
if (IsEqualGUIDAligned (Interface, IID_IMiniport))
{
*Object = (PVOID)(PMINIPORT)this;
}
else
// or IID_IMiniportTopology ...
if (IsEqualGUIDAligned (Interface, IID_IMiniportTopology))
{
*Object = (PVOID)(PMINIPORTTOPOLOGY)this;
}
else
// or maybe our IID_IMiniportTopologyICH ...
if (IsEqualGUIDAligned (Interface, IID_IMiniportTopologyICH))
{
*Object = (PVOID)(PMINIPORTTOPOLOGYICH)this;
}
else
{
// nothing found, must be an unknown interface.
*Object = NULL;
return STATUS_INVALID_PARAMETER;
}
//
// We reference the interface for the caller.
//
((PUNKNOWN)(*Object))->AddRef ();
return STATUS_SUCCESS;
}
/*****************************************************************************
* CMiniportTopologyICH::~CMiniportTopologyICH
*****************************************************************************
* Destructor.
*/
CMiniportTopologyICH::~CMiniportTopologyICH ()
{
PAGED_CODE ();
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::~CMiniportTopologyICH]"));
// release all the stuff that we had referenced or allocated.
if (AdapterCommon)
{
// Notify the AdapterCommon that we go away.
AdapterCommon->SetMiniportTopology (NULL);
AdapterCommon->Release ();
AdapterCommon = NULL;
}
if (FilterDescriptor)
{
ExFreePool (FilterDescriptor);
FilterDescriptor = NULL;
}
if (ConnectionDescriptors)
{
ExFreePool (ConnectionDescriptors);
ConnectionDescriptors = NULL;
}
if (NodeDescriptors)
{
ExFreePool (NodeDescriptors);
NodeDescriptors = NULL;
}
if (PinDescriptors)
{
ExFreePool (PinDescriptors);
PinDescriptors = NULL;
}
}
/*****************************************************************************
* CMiniportTopologyICH::DataRangeIntersection
*****************************************************************************
* Is defined in the IMiniportTopology interface. We just return
* STATUS_NOT_IMPLEMENTED and portcls will use a default handler for this.
*/
STDMETHODIMP_(NTSTATUS) CMiniportTopologyICH::DataRangeIntersection
(
IN ULONG PinId,
IN PKSDATARANGE DataRange,
IN PKSDATARANGE MatchingDataRange,
IN ULONG OutputBufferLength,
OUT PVOID ResultantFormat OPTIONAL,
OUT PULONG ResultantFormatLength
)
{
return STATUS_NOT_IMPLEMENTED;
};
/*****************************************************************************
* CMiniportTopologyICH::Init
*****************************************************************************
* Initializes the miniport.
* We initialize the translation tables, add reference to the port driver and
* build the topology.
*/
STDMETHODIMP_(NTSTATUS) CMiniportTopologyICH::Init
(
IN PUNKNOWN UnknownAdapter,
IN PRESOURCELIST ResourceList,
IN PPORTTOPOLOGY Port_
)
{
PAGED_CODE ();
ASSERT (UnknownAdapter);
ASSERT (Port_);
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::Init]"));
//
// Set the copy protect flag to FALSE.
//
m_bCopyProtectFlag = FALSE;
//
// get the IAdapterCommon interface from the adapter.
//
NTSTATUS ntStatus = UnknownAdapter->QueryInterface (IID_IAdapterCommon,
(PVOID *) &AdapterCommon);
//
// initialize translation tables
//
for (int i = 0; i < PIN_TOP_ELEMENT; i++)
{
stPinTrans[i].PinDef = PIN_INVALID;
stPinTrans[i].PinNr = -1;
}
for (i = 0; i < NODE_TOP_ELEMENT; i++)
{
stNodeTrans[i].NodeDef = NODE_INVALID;
stNodeTrans[i].NodeNr = -1;
}
// build the topology (means register pins, nodes, connections).
if (NT_SUCCESS (ntStatus))
{
ntStatus = BuildTopology ();
}
if (NT_SUCCESS (ntStatus))
{
//
// Notify AdapterCommon that we are ready now.
//
AdapterCommon->SetMiniportTopology (this);
}
else
{
//
// clean up our mess
//
// clean up AdapterCommon
if (AdapterCommon)
{
AdapterCommon->Release ();
AdapterCommon = NULL;
}
}
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologyICH::GetDescription
*****************************************************************************
* Gets/returns the topology to the system.
*/
STDMETHODIMP_(NTSTATUS) CMiniportTopologyICH::GetDescription
(
OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
)
{
PAGED_CODE ();
ASSERT (OutFilterDescriptor);
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::GetDescription]"));
#if (DBG)
// Dump it here. The system requests the topology only once.
DumpTopology ();
#endif
if (FilterDescriptor)
{
*OutFilterDescriptor = FilterDescriptor;
return STATUS_SUCCESS;
}
else
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
#if (DBG)
/*****************************************************************************
* CMiniportTopologyICH::DumpTopology
*****************************************************************************
* Dumps the topology for debugging.
* See the defines at the beginning of this file?
*/
void CMiniportTopologyICH::DumpTopology (void)
{
PAGED_CODE ();
if (FilterDescriptor)
{
// dump the pins
DOUT (DBG_PINS, ("TOPOLOGY MINIPORT PINS"));
for(ULONG index = 0; index < FilterDescriptor->PinCount; index++)
{
DOUT (DBG_PINS, (" %2d %s", index,
TopoPinStrings[TransPinNrToPinDef (index)]));
}
// dump the nodes
DOUT (DBG_NODES, ("TOPOLOGY MINIPORT NODES"));
for(index = 0; index < FilterDescriptor->NodeCount; index++)
{
DOUT (DBG_NODES, (" %2d %s", index,
NodeStrings[TransNodeNrToNodeDef (index)]));
}
// dump the connections
DOUT (DBG_CONNS, ("TOPOLOGY MINIPORT CONNECTIONS"));
for(index = 0; index < FilterDescriptor->ConnectionCount; index++)
{
DOUT (DBG_CONNS, (" %2d (%d,%d)->(%d,%d)", index,
FilterDescriptor->Connections[index].FromNode,
FilterDescriptor->Connections[index].FromNodePin,
FilterDescriptor->Connections[index].ToNode,
FilterDescriptor->Connections[index].ToNodePin));
}
}
}
#endif
/*****************************************************************************
* Miniport Topology V = Volume, M = Mute, L = Loudness, A = AGC
*==================== T = Treble, B = Bass, 0-9 = PinNr of node
*
* PCBEEP ---> V ---> M -----------------------------\
* PHONE ---> V ---> M ----------------------------\ \
* \ \
* WaveOut -------> V --> M --------------> 1+-----+ \ \
* MIC1 or MIC2 --> L --> A --> V --> M --> 2| SUM | \ \
* LineIn -------> V --> M --------------> 3| | \ \
* CD -------> V --> M --------------> 4| |0--->SUM--> T --> B --> L --> V --> M (MasterOut)
* Video -------> V --> M --------------> 5| |
* AUX -------> V --> M --------------> 6| |
* 3D Depth -----> V --> L --> A --------> 7| |
* 3D Center -----> V --> L --> A --------> 8| |
* Headphone -----> V --> M --------------> 9| |
* Front Speaker -> V --> M -------------->10| |
* Surround ------> V --> M -------------->11| |
* Center ------> V --> M -------------->12| |
* LFE ------> V --> M -------------->13+-----+
*
*
* virt. Pin: Tone mix mono ---> V --> M ---> 7+-------+
* virt. Pin: Tone mix stereo ---> V --> M ---> 6| |
* Phone ---> V --> M ---> 8| M |
* Mic (after AGC) ---> V --> M ---> 1| |0-----> (WaveIn)
* LineIn ---> V --> M ---> 5| U |
* CD ---> V --> M ---> 2| |
* Video ---> V --> M ---> 3| X |
* AUX ---> V --> M ---> 4+-------+
*
*
* virt. Pin: 3D mix mono ---> V ---> M ---> 1+-----+
* | MUX |0----> (MonoOut)
* Mic (after AGC) ---> V ---> M ---> 2+-----+
*
*
* Mic (after AGC) ----> V ----> M -----> (MicIn)
*
*----------------------------------------------------------------------------
*
* As you can see, the exposed topology is somewhat different from the real AC97
* topology. This is because the system that translates the topology to "mixer
* lines" gets confused if it has to deal with all the mess. So we have to make it
* plain and simple for the system.
* Some issues block us from exposing a nice plain and simple topology. The prg.
* which displayes the "Volume Control Panel" (sndvol32) does _only_ display
* Volumes, Mutes (only one "in a row"), Treble, Bass, Loudness and AGC under
* Advanced control panel. We don't have 3D controls, and before we go into a
* Muxer, there has to be Volume controls in front.
* So what do we do?
* 1) We fake 3D controls as Volume controls. The Mutes represent 3D bypass and
* 3D on/off
* 2) All inputs (including the 3D controls) go staight into a SUM. Important is
* that there are not 2 Volumes, Mutes in a row, e.g. ---> V ---> M ---> V ---> M
* In that case, only one Volume/Mute would be displayed.
* 3) We can't make a connection from the tone controls to the Wave In muxer (even
* with Volumes in front), so we create fake pins that we name user friendly.
* Same with the connection from the 3D mixer to the Mono output.
* 4) We discard all supermixer controls that would convert stereo to mono or vice
* versa. Instead, we just connect the lines and when the control is queried we
* fail a right channel request (mono has only left channel).
* 5) We have to make virtual volume and mute controls in front of each muxer.
* As you can see, these controls can be mono or stereo and there is only one
* HW register for them, so we have to cache the values and prg. the register
* each time the select changes or the selected volume control changes.
*/
/*****************************************************************************
* CMiniportTopologyICH::BuildTopology
*****************************************************************************
* Builds the topology descriptors based on hardware configuration info
* obtained from the adapter.
*/
NTSTATUS CMiniportTopologyICH::BuildTopology (void)
{
PAGED_CODE ();
NTSTATUS ntStatus = STATUS_SUCCESS;
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::BuildTopology]"));
// allocate our filter descriptor
FilterDescriptor = (PPCFILTER_DESCRIPTOR) ExAllocatePool (PagedPool,
sizeof(PCFILTER_DESCRIPTOR));
if (FilterDescriptor)
{
// clear out the filter descriptor
RtlZeroMemory (FilterDescriptor, sizeof(PCFILTER_DESCRIPTOR));
#ifdef INCLUDE_PRIVATE_PROPERTY
// Set the Filter automation table.
FilterDescriptor->AutomationTable = &FilterAutomationPrivate;
#endif
// build the pin list
ntStatus = BuildPinDescriptors ();
if (NT_SUCCESS (ntStatus))
{
// build the node list
ntStatus = BuildNodeDescriptors ();
if (NT_SUCCESS (ntStatus))
{
// build the connection list
ntStatus = BuildConnectionDescriptors ();
}
}
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
// that's whatever one of these build... functions returned.
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologyICH::BuildPinDescriptors
*****************************************************************************
* Builds the topology pin descriptors.
*/
NTSTATUS CMiniportTopologyICH::BuildPinDescriptors (void)
{
// Improvement would be to not use a Macro, use (inline) function instead.
#define INIT_PIN( pin, pinptr, category, name, index ) \
pinptr->KsPinDescriptor.Category = (GUID*) category; \
pinptr->KsPinDescriptor.Name = (GUID*) name; \
SetPinTranslation (index++, pin); \
pinptr++
PAGED_CODE ();
ULONG Index;
PPCPIN_DESCRIPTOR CurrentPin;
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::BuildPinDescriptors]"));
// allocate our descriptor memory
PinDescriptors = PPCPIN_DESCRIPTOR (ExAllocatePool (PagedPool,
PIN_TOP_ELEMENT * sizeof(PCPIN_DESCRIPTOR)));
if (!PinDescriptors)
return STATUS_INSUFFICIENT_RESOURCES;
//
// set default pin descriptor parameters
//
RtlZeroMemory (PinDescriptors, PIN_TOP_ELEMENT * sizeof(PCPIN_DESCRIPTOR));
// spend some more time and set the pin descriptors to expected values.
for (CurrentPin = PinDescriptors, Index = 0; Index < PIN_TOP_ELEMENT;
CurrentPin++, Index++)
{
CurrentPin->KsPinDescriptor.DataRangesCount = SIZEOF_ARRAY(PinDataRangePointersAnalogBridge);
CurrentPin->KsPinDescriptor.DataRanges = PinDataRangePointersAnalogBridge;
CurrentPin->KsPinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
CurrentPin->KsPinDescriptor.Communication = KSPIN_COMMUNICATION_NONE;
}
//
// modify the individual pin descriptors
//
CurrentPin = PinDescriptors;
Index = 0;
// add the PIN_WAVEOUT_SOURCE pin descriptor (not optional)
INIT_PIN (PIN_WAVEOUT_SOURCE,
CurrentPin,
&KSCATEGORY_AUDIO,
NULL,
Index);
// add the PIN_PCBEEP_SOURCE pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_PCBEEP_PRESENT))
{
INIT_PIN (PIN_PCBEEP_SOURCE,
CurrentPin,
&KSNODETYPE_SPEAKER,
&KSAUDFNAME_PC_SPEAKER,
Index);
}
// add the PIN_PHONE_SOURCE pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
INIT_PIN (PIN_PHONE_SOURCE,
CurrentPin,
&KSNODETYPE_PHONE_LINE,
NULL,
Index);
}
// add the PIN_MIC_SOURCE pin descriptor (could be disabled)
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
INIT_PIN (PIN_MIC_SOURCE,
CurrentPin,
&KSNODETYPE_MICROPHONE,
NULL,
Index);
}
// add the PIN_LINEIN_SOURCE pin descriptor (could be disabled)
if (AdapterCommon->GetPinConfig (PINC_LINEIN_PRESENT))
{
INIT_PIN (PIN_LINEIN_SOURCE,
CurrentPin,
&KSNODETYPE_LINE_CONNECTOR,
&KSAUDFNAME_LINE_IN,
Index);
}
// add the PIN_CD_SOURCE pin descriptor (could be disabled)
if (AdapterCommon->GetPinConfig (PINC_CD_PRESENT))
{
INIT_PIN (PIN_CD_SOURCE,
CurrentPin,
&KSNODETYPE_CD_PLAYER,
&KSAUDFNAME_CD_AUDIO,
Index);
}
// add the PIN_VIDEO_SOURCE pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_VIDEO_PRESENT))
{
INIT_PIN (PIN_VIDEO_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_VIDEO,
Index);
}
// add the PIN_AUX_SOURCE pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_AUX_PRESENT))
{
INIT_PIN (PIN_AUX_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_AUX,
Index);
}
// add the PIN_VIRT_TONE_MIX_SOURCE pin descriptor (not optional)
INIT_PIN (PIN_VIRT_TONE_MIX_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_STEREO_MIX,
Index);
// add the PIN_VIRT_TONE_MIX_MONO_SOURCE pin descriptor (not optional)
INIT_PIN (PIN_VIRT_TONE_MIX_MONO_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_MONO_MIX,
Index);
// create a virt. pin for the 3D controls
if (AdapterCommon->GetNodeConfig (NODEC_3D_PRESENT))
{
if (AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE))
{
INIT_PIN (PIN_VIRT_3D_CENTER_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_3D_CENTER,
Index);
}
// A weird way would be to have 3D but only fixed sliders. In that case,
// display one fixed slider (3D depth).
if (AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) ||
(!AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE) &&
!AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE)))
{
INIT_PIN (PIN_VIRT_3D_DEPTH_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_3D_DEPTH,
Index);
}
}
// Add a "Front speaker" pin if we have multichannel or headphones.
// We use a master mono then ...
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// Add a "Front speaker" pin, because in multichannel we want
// to display a master mono that effects all channels.
INIT_PIN (PIN_VIRT_FRONT_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&ICHFNAME_FRONT,
Index);
}
// check for multichannel
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
{
// Add the Rear Speaker Volume pin.
INIT_PIN (PIN_VIRT_SURROUND_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&ICHFNAME_SURROUND,
Index);
// add the Center Volume pin if we support at least 6 channel.
if (AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
{
INIT_PIN (PIN_VIRT_CENTER_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&ICHFNAME_CENTER,
Index);
INIT_PIN (PIN_VIRT_LFE_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&ICHFNAME_LFE,
Index);
}
}
// add the PIN_MASTEROUT_DEST pin descriptor (not optional)
CurrentPin->KsPinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
INIT_PIN (PIN_MASTEROUT_DEST,
CurrentPin,
&KSNODETYPE_SPEAKER,
&KSAUDFNAME_VOLUME_CONTROL,
Index);
// add the PIN_HPOUT_SOURCE pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
INIT_PIN (PIN_HPOUT_SOURCE,
CurrentPin,
&KSNODETYPE_HEADPHONES,
NULL,
Index);
}
// add the PIN_WAVEIN_DEST pin descriptor (not optional)
CurrentPin->KsPinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
INIT_PIN (PIN_WAVEIN_DEST,
CurrentPin,
&KSCATEGORY_AUDIO,
NULL,
Index);
// add the PIN_MICIN_DEST pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_MICIN_PRESENT) &&
AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
CurrentPin->KsPinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
INIT_PIN (PIN_MICIN_DEST,
CurrentPin,
&KSCATEGORY_AUDIO,
NULL,
Index);
}
// add the PIN_MONOOUT_DEST pin descriptor (optional)
if (AdapterCommon->GetPinConfig (PINC_MONOOUT_PRESENT))
{
// add the PIN_VIRT_3D_MIX_MONO_SOURCE pin descriptor
INIT_PIN (PIN_VIRT_3D_MIX_MONO_SOURCE,
CurrentPin,
&KSNODETYPE_ANALOG_CONNECTOR,
&KSAUDFNAME_MONO_MIX,
Index);
CurrentPin->KsPinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
// and the normal output pin
INIT_PIN (PIN_MONOOUT_DEST,
CurrentPin,
&KSNODETYPE_PHONE_LINE,
&KSAUDFNAME_MONO_OUT,
Index);
}
// add the pin descriptor informatin to the filter descriptor
FilterDescriptor->PinCount = Index;
FilterDescriptor->PinSize = sizeof (PCPIN_DESCRIPTOR);
FilterDescriptor->Pins = PinDescriptors;
return STATUS_SUCCESS;
#undef INIT_PIN
}
/*****************************************************************************
* CMiniportTopologyICH::BuildNodeDescriptors
*****************************************************************************
* Builds the topology node descriptors.
*/
NTSTATUS CMiniportTopologyICH::BuildNodeDescriptors (void)
{
// Improvement would be to not use a Macro, use (inline) function instead.
#define INIT_NODE( node, nodeptr, type, name, automation, index ) \
nodeptr->Type = (GUID*) type; \
nodeptr->Name = (GUID*) name; \
nodeptr->AutomationTable = automation; \
SetNodeTranslation (index++, node); \
nodeptr++
PAGED_CODE ();
NTSTATUS ntStatus = STATUS_SUCCESS;
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::BuildNodeDescriptors]"));
// allocate our descriptor memory
NodeDescriptors = PPCNODE_DESCRIPTOR (ExAllocatePool (PagedPool,
NODE_TOP_ELEMENT * sizeof(PCNODE_DESCRIPTOR)));
if (NodeDescriptors)
{
PPCNODE_DESCRIPTOR CurrentNode = NodeDescriptors;
ULONG Index = 0;
//
// set default node descriptor parameters
//
RtlZeroMemory (NodeDescriptors, NODE_TOP_ELEMENT *
sizeof(PCNODE_DESCRIPTOR));
// We don't have loopback mode currently. It is only used for testing anyway.
// Add the NODE_WAVEOUT_VOLUME node
INIT_NODE (NODE_WAVEOUT_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_WAVE_VOLUME,
&AutomationVolume,
Index);
// add the NODE_WAVEOUT_MUTE node
INIT_NODE (NODE_WAVEOUT_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_WAVE_MUTE,
&AutomationMute,
Index);
// add the PCBEEP nodes
if (AdapterCommon->GetPinConfig (PINC_PCBEEP_PRESENT))
{
// add the NODE_PCBEEP_VOLUME node
INIT_NODE (NODE_PCBEEP_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_PC_SPEAKER_VOLUME,
&AutomationVolume,
Index);
// add the NODE_PCBEEP_MUTE node
INIT_NODE (NODE_PCBEEP_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_PC_SPEAKER_MUTE,
&AutomationMute,
Index);
}
// add the PHONE nodes
if (AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
// add the NODE_PHONE_VOLUME node
INIT_NODE (NODE_PHONE_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_PHONE_VOLUME,
&AutomationVolume,
Index);
// add the NODE_PHONE_MUTE node
INIT_NODE (NODE_PHONE_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_PHONE_MUTE,
&AutomationMute,
Index);
}
// add the MIC nodes
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
if (AdapterCommon->GetPinConfig (PINC_MIC2_PRESENT))
{
// add the NODE_MIC_SELECT node
INIT_NODE (NODE_MIC_SELECT,
CurrentNode,
&KSNODETYPE_LOUDNESS,
&KSAUDFNAME_ALTERNATE_MICROPHONE,
&AutomationSpecial,
Index);
}
// add the NODE_MIC_BOOST node
INIT_NODE (NODE_MIC_BOOST,
CurrentNode,
&KSNODETYPE_AGC,
&KSAUDFNAME_MICROPHONE_BOOST,
&AutomationSpecial,
Index);
// add the NODE_MIC_VOLUME node
INIT_NODE (NODE_MIC_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MIC_VOLUME,
&AutomationVolume,
Index);
// add the NODE_MIC_MUTE node
INIT_NODE (NODE_MIC_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_MIC_MUTE,
&AutomationMute,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_LINEIN_PRESENT))
{
// add the NODE_LINEIN_VOLUME node
INIT_NODE (NODE_LINEIN_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_LINE_IN_VOLUME,
&AutomationVolume,
Index);
// add the NODE_LINEIN_MUTE node
INIT_NODE (NODE_LINEIN_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_LINEIN_MUTE,
&AutomationMute,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_CD_PRESENT))
{
// add the NODE_CD_VOLUME node
INIT_NODE (NODE_CD_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_CD_VOLUME,
&AutomationVolume,
Index);
// add the NODE_CD_MUTE node
INIT_NODE (NODE_CD_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_CD_MUTE,
&AutomationMute,
Index);
}
// add the VIDEO nodes
if (AdapterCommon->GetPinConfig (PINC_VIDEO_PRESENT))
{
// add the NODE_VIDEO_VOLUME node
INIT_NODE (NODE_VIDEO_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_VIDEO_VOLUME,
&AutomationVolume,
Index);
// add the NODE_VIDEO_MUTE node
INIT_NODE (NODE_VIDEO_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_VIDEO_MUTE,
&AutomationMute,
Index);
}
// add the AUX nodes
if (AdapterCommon->GetPinConfig (PINC_AUX_PRESENT))
{
// add the NODE_AUX_VOLUME node
INIT_NODE (NODE_AUX_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_AUX_VOLUME,
&AutomationVolume,
Index);
// add the NODE_AUX_MUTE node
INIT_NODE (NODE_AUX_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_AUX_MUTE,
&AutomationMute,
Index);
}
// add the NODE_MAIN_MIX node
INIT_NODE (NODE_MAIN_MIX,
CurrentNode,
&KSNODETYPE_SUM,
&ICHFNAME_MAIN_MIX,
NULL,
Index);
// add the 3D nodes
if (AdapterCommon->GetNodeConfig (NODEC_3D_PRESENT))
{
if (AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE))
{
// add the NODE_VIRT_3D_CENTER node
INIT_NODE (NODE_VIRT_3D_CENTER,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_3D_CENTER,
&Automation3D,
Index);
}
if (AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) ||
(!AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) &&
!AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE)))
{
// add the NODE_VIRT_3D_DEPTH node
INIT_NODE (NODE_VIRT_3D_DEPTH,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_3D_DEPTH,
&Automation3D,
Index);
}
// add the NODE_VIRT_3D_ENABLE node
INIT_NODE (NODE_VIRT_3D_ENABLE,
CurrentNode,
&KSNODETYPE_LOUDNESS,
&ICHFNAME_3D_ENABLE,
&AutomationSpecial,
Index);
// add the NODE_VIRT_WAVEOUT_3D_BYPASS node
INIT_NODE (NODE_VIRT_WAVEOUT_3D_BYPASS,
CurrentNode,
&KSNODETYPE_AGC,
&ICHFNAME_WAVEOUT_3D_BYPASS,
&AutomationSpecial,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_PCBEEP_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
// add the NODE_BEEP_MIX node
INIT_NODE (NODE_BEEP_MIX,
CurrentNode,
&KSNODETYPE_SUM,
&ICHFNAME_BEEP_MIX,
NULL,
Index);
}
// add the tone nodes
if (AdapterCommon->GetNodeConfig (NODEC_TONE_PRESENT))
{
// add the NODE_BASS node
INIT_NODE (NODE_BASS,
CurrentNode,
&KSNODETYPE_TONE,
&KSAUDFNAME_BASS,
&AutomationTone,
Index);
// add the NODE_TREBLE node
INIT_NODE (NODE_TREBLE,
CurrentNode,
&KSNODETYPE_TONE,
&KSAUDFNAME_TREBLE,
&AutomationTone,
Index);
if (AdapterCommon->GetNodeConfig (NODEC_LOUDNESS_PRESENT))
{
// add the NODE_LOUDNESS node
INIT_NODE (NODE_LOUDNESS,
CurrentNode,
&KSNODETYPE_LOUDNESS,
NULL,
&AutomationSpecial,
Index);
}
if (AdapterCommon->GetNodeConfig (NODEC_SIMUL_STEREO_PRESENT))
{
// add the NODE_SIMUL_STEREO node
INIT_NODE (NODE_SIMUL_STEREO,
CurrentNode,
&KSNODETYPE_AGC,
&ICHFNAME_SIMUL_STEREO,
&AutomationSpecial,
Index);
}
}
// Add a "Front Speaker" volume/mute if we have surround or headphones.
// The "Master" volume/mute will be mono then
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// Add the front speaker volume.
INIT_NODE (NODE_FRONT_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_FRONT_VOLUME,
&AutomationVolume,
Index);
// Add the front speaker mute.
INIT_NODE (NODE_FRONT_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_FRONT_MUTE,
&AutomationMute,
Index);
// Add the master mono out volume.
INIT_NODE (NODE_VIRT_MASTERMONO_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MASTER_VOLUME,
&AutomationVolume,
Index);
// Add the master mono out volume.
INIT_NODE (NODE_VIRT_MASTERMONO_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_MASTER_MUTE,
&AutomationMute,
Index);
}
else
{
// add the NODE_MASTEROUT_VOLUME node
INIT_NODE (NODE_MASTEROUT_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MASTER_VOLUME,
&AutomationVolume,
Index);
// add the NODE_MASTEROUT_MUTE node
INIT_NODE (NODE_MASTEROUT_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&KSAUDFNAME_MASTER_MUTE,
&AutomationMute,
Index);
}
// Add the surround control if we have one.
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
{
// Add the surround volume.
INIT_NODE (NODE_SURROUND_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_SURROUND_VOLUME,
&AutomationVolume,
Index);
// Add the surround mute.
INIT_NODE (NODE_SURROUND_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_SURROUND_MUTE,
&AutomationMute,
Index);
// Add the center and LFE control if we have one.
if (AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
{
// Add the center volume.
INIT_NODE (NODE_CENTER_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_CENTER_VOLUME,
&AutomationVolume,
Index);
// Add the center mute.
INIT_NODE (NODE_CENTER_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_CENTER_MUTE,
&AutomationMute,
Index);
// Add the LFE volume.
INIT_NODE (NODE_LFE_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_LFE_VOLUME,
&AutomationVolume,
Index);
// Add the LFE mute.
INIT_NODE (NODE_LFE_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_LFE_MUTE,
&AutomationMute,
Index);
}
}
// add the HPOUT nodes
if (AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// add the NODE_HPOUT_VOLUME node
INIT_NODE (NODE_HPOUT_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_HPOUT_VOLUME,
&AutomationVolume,
Index);
// add the NODE_HPOUT_MUTE node
INIT_NODE (NODE_HPOUT_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_HPOUT_MUTE,
&AutomationMute,
Index);
}
// add the NODE_WAVEIN_SELECT node
INIT_NODE (NODE_WAVEIN_SELECT,
CurrentNode,
&KSNODETYPE_MUX,
&ICHFNAME_WAVEIN_SELECT,
&AutomationMux,
Index);
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME1 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME1,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MIC_VOLUME,
&AutomationVolume,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_CD_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME2 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME2,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_CD_VOLUME,
&AutomationVolume,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_VIDEO_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME3 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME3,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_VIDEO_VOLUME,
&AutomationVolume,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_AUX_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME4 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME4,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_AUX_VOLUME,
&AutomationVolume,
Index);
}
if (AdapterCommon->GetPinConfig (PINC_LINEIN_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME5 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME5,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_LINE_IN_VOLUME,
&AutomationVolume,
Index);
}
// add the NODE_VIRT_MASTER_INPUT_VOLUME6 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME6,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_STEREO_MIX_VOLUME,
&AutomationVolume,
Index);
// add the NODE_VIRT_MASTER_INPUT_VOLUME7 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME7,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MONO_MIX_VOLUME,
&AutomationVolume,
Index);
if (AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
// add the NODE_VIRT_MASTER_INPUT_VOLUME8 node
INIT_NODE (NODE_VIRT_MASTER_INPUT_VOLUME8,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_MASTER_INPUT_VOLUME,
&AutomationVolume,
Index);
}
// add the MICIN nodes
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT) &&
AdapterCommon->GetPinConfig (PINC_MICIN_PRESENT))
{
// add the NODE_MICIN_VOLUME node
INIT_NODE (NODE_MICIN_VOLUME,
CurrentNode,
&KSNODETYPE_VOLUME,
&ICHFNAME_MICIN_VOLUME,
&AutomationVolume,
Index);
// add the NODE_MICIN_MUTE node
INIT_NODE (NODE_MICIN_MUTE,
CurrentNode,
&KSNODETYPE_MUTE,
&ICHFNAME_MICIN_MUTE,
&AutomationMute,
Index);
}
// add the MONOOUT nodes
if (AdapterCommon->GetPinConfig (PINC_MONOOUT_PRESENT))
{
// add the NODE_MONOOUT_SELECT node
INIT_NODE (NODE_MONOOUT_SELECT,
CurrentNode,
&KSNODETYPE_MUX,
&ICHFNAME_MONOOUT_SELECT,
&AutomationMux,
Index);
// add the NODE_VIRT_MONOOUT_VOLUME1 node
INIT_NODE (NODE_VIRT_MONOOUT_VOLUME1,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MONO_MIX_VOLUME,
&AutomationVolume,
Index);
// add the NODE_VIRT_MONOOUT_VOLUME2 node
INIT_NODE (NODE_VIRT_MONOOUT_VOLUME2,
CurrentNode,
&KSNODETYPE_VOLUME,
&KSAUDFNAME_MIC_VOLUME,
&AutomationVolume,
Index);
}
// add the nodes to the filter descriptor
FilterDescriptor->NodeCount = Index;
FilterDescriptor->NodeSize = sizeof(PCNODE_DESCRIPTOR);
FilterDescriptor->Nodes = NodeDescriptors;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
#undef INIT_NODE
}
/*****************************************************************************
* CMiniportTopologyICH::BuildConnectionDescriptors
*****************************************************************************
* Builds the topology connection descriptors.
*/
NTSTATUS CMiniportTopologyICH::BuildConnectionDescriptors (void)
{
// Improvement would be to not use a Macro, use (inline) function instead.
// for node to node connections
#define INIT_NN_CONN( cptr, fnode, fpin, tnode, tpin ) \
cptr->FromNode = TransNodeDefToNodeNr (fnode); \
cptr->FromNodePin = fpin; \
cptr->ToNode = TransNodeDefToNodeNr (tnode); \
cptr->ToNodePin = tpin; \
cptr++,ConnectionCount++
// for filter pin to node connections
#define INIT_FN_CONN( cptr, fpin, tnode, tpin ) \
cptr->FromNode = KSFILTER_NODE; \
cptr->FromNodePin = TransPinDefToPinNr (fpin); \
cptr->ToNode = TransNodeDefToNodeNr (tnode); \
cptr->ToNodePin = tpin; \
cptr++,ConnectionCount++
// for node to filter pin connections
#define INIT_NF_CONN( cptr, fnode, fpin, tpin ) \
cptr->FromNode = TransNodeDefToNodeNr (fnode); \
cptr->FromNodePin = fpin; \
cptr->ToNode = KSFILTER_NODE; \
cptr->ToNodePin = TransPinDefToPinNr (tpin); \
cptr++,ConnectionCount++
PAGED_CODE ();
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ConnectionCount = 0;
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::BuildConnectionDescriptors]"));
// allocate our descriptor memory
ConnectionDescriptors = PPCCONNECTION_DESCRIPTOR (ExAllocatePool (PagedPool,
TOPO_MAX_CONNECTIONS * sizeof(PCCONNECTION_DESCRIPTOR)));
if (ConnectionDescriptors)
{
PPCCONNECTION_DESCRIPTOR CurrentConnection = ConnectionDescriptors;
// build the wave out (coming in) path
// PIN_WAVEOUT_SOURCE -> NODE_WAVEOUT_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_WAVEOUT_SOURCE, NODE_WAVEOUT_VOLUME, 1);
// NODE_WAVEOUT_VOLUME -> NODE_WAVEOUT_MUTE
INIT_NN_CONN (CurrentConnection, NODE_WAVEOUT_VOLUME, 0, NODE_WAVEOUT_MUTE, 1);
// NODE_WAVEOUT_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_WAVEOUT_MUTE, 0, NODE_MAIN_MIX, 1);
// build the PC beeper path
if (AdapterCommon->GetPinConfig (PINC_PCBEEP_PRESENT))
{
// PIN_PCBEEP_SOURCE -> NODE_PCBEEP_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_PCBEEP_SOURCE, NODE_PCBEEP_VOLUME, 1);
// NODE_PCBEEP_VOLUME -> NODE_PCBEEP_MUTE
INIT_NN_CONN (CurrentConnection, NODE_PCBEEP_VOLUME, 0, NODE_PCBEEP_MUTE, 1);
// NODE_PCBEEP_MUTE -> NODE_BEEP_MIX
INIT_NN_CONN (CurrentConnection, NODE_PCBEEP_MUTE, 0, NODE_BEEP_MIX, 2);
}
// build the phone path
if (AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
// PIN_PHONE_SOURCE -> NODE_PHONE_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_PHONE_SOURCE, NODE_PHONE_VOLUME, 1);
// NODE_PHONE_VOLUME -> NODE_PHONE_MUTE
INIT_NN_CONN (CurrentConnection, NODE_PHONE_VOLUME, 0, NODE_PHONE_MUTE, 1);
// NODE_PHONE_MUTE -> LINEOUT_BEEP_MIX
INIT_NN_CONN (CurrentConnection, NODE_PHONE_MUTE, 0, NODE_BEEP_MIX, 3);
// PIN_PHONE_SOURCE pin -> NODE_VIRT_MASTER_INPUT_VOLUME8
INIT_FN_CONN (CurrentConnection, PIN_PHONE_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME8, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME8 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME8, 0, NODE_WAVEIN_SELECT, 8);
}
// build MIC path
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
// build the MIC selector in case we have 2 MICs
if (AdapterCommon->GetPinConfig (PINC_MIC2_PRESENT))
{
// PIN_MIC_SOURCE pin -> NODE_MIC_SELECT
INIT_FN_CONN (CurrentConnection, PIN_MIC_SOURCE, NODE_MIC_SELECT, 1);
// NODE_MIC_SELECT -> NODE_MIC_BOOST
INIT_NN_CONN (CurrentConnection, NODE_MIC_SELECT, 0, NODE_MIC_BOOST, 1);
}
else
{
// PIN_MIC_SOURCE pin -> NODE_MIC_SELECT
INIT_FN_CONN (CurrentConnection, PIN_MIC_SOURCE, NODE_MIC_BOOST, 1);
}
// NODE_MIC_BOOST -> NODE_MIC_VOLUME
INIT_NN_CONN (CurrentConnection, NODE_MIC_BOOST, 0, NODE_MIC_VOLUME, 1);
// NODE_MIC_VOLUME -> NODE_MIC_MUTE
INIT_NN_CONN (CurrentConnection, NODE_MIC_VOLUME, 0, NODE_MIC_MUTE, 1);
// NODE_MIC_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_MIC_MUTE, 0, NODE_MAIN_MIX, 2);
// NODE_MIC_BOOST -> NODE_VIRT_MASTER_INPUT_VOLUME1
INIT_NN_CONN (CurrentConnection, NODE_MIC_BOOST, 0, NODE_VIRT_MASTER_INPUT_VOLUME1, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME1 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME1, 0, NODE_WAVEIN_SELECT, 1);
}
// build the line in path
if (AdapterCommon->GetPinConfig (PINC_LINEIN_PRESENT))
{
// PIN_LINEIN_SOURCE -> NODE_LINEIN_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_LINEIN_SOURCE, NODE_LINEIN_VOLUME, 1);
// NODE_LINEIN_VOLUME -> NODE_LINEIN_MUTE
INIT_NN_CONN (CurrentConnection, NODE_LINEIN_VOLUME, 0, NODE_LINEIN_MUTE, 1);
// NODE_LINEIN_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_LINEIN_MUTE, 0, NODE_MAIN_MIX, 3);
// PIN_LINEIN_SOURCE pin -> NODE_VIRT_MASTER_INPUT_VOLUME5
INIT_FN_CONN (CurrentConnection, PIN_LINEIN_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME5, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME5 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME5, 0, NODE_WAVEIN_SELECT, 5);
}
// build the CD path
if (AdapterCommon->GetPinConfig (PINC_CD_PRESENT))
{
// PIN_CD_SOURCE -> NODE_CD_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_CD_SOURCE, NODE_CD_VOLUME, 1);
// NODE_CD_VOLUME -> NODE_CD_MUTE
INIT_NN_CONN (CurrentConnection, NODE_CD_VOLUME, 0, NODE_CD_MUTE, 1);
// NODE_CD_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_CD_MUTE, 0, NODE_MAIN_MIX, 4);
// PIN_CD_SOURCE pin -> NODE_VIRT_MASTER_INPUT_VOLUME2
INIT_FN_CONN (CurrentConnection, PIN_CD_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME2, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME2 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME2, 0, NODE_WAVEIN_SELECT, 2);
}
// build the video path
if (AdapterCommon->GetPinConfig (PINC_VIDEO_PRESENT))
{
// PIN_VIDEO_SOURCE -> NODE_VIDEO_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_VIDEO_SOURCE, NODE_VIDEO_VOLUME, 1);
// NODE_VIDEO_VOLUME -> NODE_VIDEO_MUTE
INIT_NN_CONN (CurrentConnection, NODE_VIDEO_VOLUME, 0, NODE_VIDEO_MUTE, 1);
// NODE_VIDEO_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_VIDEO_MUTE, 0, NODE_MAIN_MIX, 5);
// PIN_VIDEO_SOURCE pin -> NODE_VIRT_MASTER_INPUT_VOLUME3
INIT_FN_CONN (CurrentConnection, PIN_VIDEO_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME3, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME3 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME3, 0, NODE_WAVEIN_SELECT, 3);
}
// build the AUX path
if (AdapterCommon->GetPinConfig (PINC_AUX_PRESENT))
{
// PIN_AUX_SOURCE pin -> NODE_AUX_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_AUX_SOURCE, NODE_AUX_VOLUME, 1);
// NODE_AUX_VOLUME -> NODE_AUX_MUTE
INIT_NN_CONN (CurrentConnection, NODE_AUX_VOLUME, 0, NODE_AUX_MUTE, 1);
// NODE_AUX_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_AUX_MUTE, 0, NODE_MAIN_MIX, 6);
// PIN_AUX_SOURCE pin -> NODE_VIRT_MASTER_INPUT_VOLUME4
INIT_FN_CONN (CurrentConnection, PIN_AUX_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME4, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME4 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME4, 0, NODE_WAVEIN_SELECT, 4);
}
// and build the head phone output.
// we connect the headphones like an input so that it's in the playback panel.
if (AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// from whatever -> NODE_HPOUT_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_HPOUT_SOURCE, NODE_HPOUT_VOLUME, 1);
// NODE_HPOUT_VOLUME -> NODE_HPOUT_MUTE
INIT_NN_CONN (CurrentConnection, NODE_HPOUT_VOLUME, 0, NODE_HPOUT_MUTE, 1);
// NODE_HPOUT_MUTE -> PIN_HPOUT_DEST pin
INIT_NN_CONN( CurrentConnection, NODE_HPOUT_MUTE, 0, NODE_MAIN_MIX, 9);
}
// build the 3D path
if (AdapterCommon->GetNodeConfig (NODEC_3D_PRESENT))
{
// Figure out what the main 3D line is.
if (AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE))
{
if (AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE))
{
// PIN_VIRT_3D_DEPTH_SOURCE -> NODE_VIRT_3D_ENABLE
INIT_FN_CONN (CurrentConnection, PIN_VIRT_3D_DEPTH_SOURCE, NODE_VIRT_3D_ENABLE, 1);
// NODE_VIRT_3D_ENABLE -> NODE_VIRT_WAVEOUT_3D_BYPASS
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_ENABLE, 0, NODE_VIRT_WAVEOUT_3D_BYPASS, 1);
// NODE_VIRT_WAVEOUT_3D_BYPASS -> NODE_VIRT_3D_DEPTH
INIT_NN_CONN (CurrentConnection, NODE_VIRT_WAVEOUT_3D_BYPASS, 0, NODE_VIRT_3D_DEPTH, 1);
// NODE_VIRT_3D_DEPTH -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_DEPTH, 0, NODE_MAIN_MIX, 7);
// PIN_VIRT_3D_CENTER_SOURCE -> NODE_VIRT_3D_CENTER
INIT_FN_CONN (CurrentConnection, PIN_VIRT_3D_CENTER_SOURCE, NODE_VIRT_3D_CENTER, 1);
// NODE_VIRT_3D_CENTER -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_CENTER, 0, NODE_MAIN_MIX, 8);
}
else
{
// PIN_VIRT_3D_CENTER_SOURCE -> NODE_VIRT_3D_ENABLE
INIT_FN_CONN (CurrentConnection, PIN_VIRT_3D_CENTER_SOURCE, NODE_VIRT_3D_ENABLE, 1);
// NODE_VIRT_3D_ENABLE -> NODE_VIRT_WAVEOUT_3D_BYPASS
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_ENABLE, 0, NODE_VIRT_WAVEOUT_3D_BYPASS, 1);
// NODE_VIRT_WAVEOUT_3D_BYPASS -> NODE_VIRT_3D_CENTER
INIT_NN_CONN (CurrentConnection, NODE_VIRT_WAVEOUT_3D_BYPASS, 0, NODE_VIRT_3D_CENTER, 1);
// NODE_VIRT_3D_CENTER -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_CENTER, 0, NODE_MAIN_MIX, 8);
}
}
else
{
// PIN_VIRT_3D_DEPTH_SOURCE -> NODE_VIRT_3D_ENABLE
INIT_FN_CONN (CurrentConnection, PIN_VIRT_3D_DEPTH_SOURCE, NODE_VIRT_3D_ENABLE, 1);
// NODE_VIRT_3D_ENABLE -> NODE_VIRT_WAVEOUT_3D_BYPASS
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_ENABLE, 0, NODE_VIRT_WAVEOUT_3D_BYPASS, 1);
// NODE_VIRT_WAVEOUT_3D_BYPASS -> NODE_VIRT_3D_DEPTH
INIT_NN_CONN (CurrentConnection, NODE_VIRT_WAVEOUT_3D_BYPASS, 0, NODE_VIRT_3D_DEPTH, 1);
// NODE_VIRT_3D_DEPTH -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_VIRT_3D_DEPTH, 0, NODE_MAIN_MIX, 7);
}
}
// build the 4 or 6 channel controls
// In case of multichannel or headphone we have "front speakers" volume/mute.
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// PIN_VIRT_FRONT_SOURCE -> NODE_FRONT_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_VIRT_FRONT_SOURCE, NODE_FRONT_VOLUME, 1);
// NODE_FRONT_VOLUME -> NODE_FRONT_MUTE
INIT_NN_CONN (CurrentConnection, NODE_FRONT_VOLUME, 0, NODE_FRONT_MUTE, 1);
// NODE_FRONT_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_FRONT_MUTE, 0, NODE_MAIN_MIX, 10);
}
// Check for surround volumes
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
{
// PIN_VIRT_SURROUND -> NODE_SURROUND_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_VIRT_SURROUND_SOURCE, NODE_SURROUND_VOLUME, 1);
// NODE_SURROUND_VOLUME -> NODE_SURROUND_MUTE
INIT_NN_CONN (CurrentConnection, NODE_SURROUND_VOLUME, 0, NODE_SURROUND_MUTE, 1);
// NODE_SURROUND_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_SURROUND_MUTE, 0, NODE_MAIN_MIX, 11);
// check also for the center and LFE volumes
if (AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
{
// PIN_VIRT_CENTER -> NODE_CENTER_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_VIRT_CENTER_SOURCE, NODE_CENTER_VOLUME, 1);
// NODE_CENTER_VOLUME -> NODE_CENTER_MUTE
INIT_NN_CONN (CurrentConnection, NODE_CENTER_VOLUME, 0, NODE_CENTER_MUTE, 1);
// NODE_CENTER_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_CENTER_MUTE, 0, NODE_MAIN_MIX, 12);
// PIN_VIRT_LFE -> NODE_LFE_VOLUME
INIT_FN_CONN (CurrentConnection, PIN_VIRT_LFE_SOURCE, NODE_LFE_VOLUME, 1);
// NODE_LFE_VOLUME -> NODE_LFE_MUTE
INIT_NN_CONN (CurrentConnection, NODE_LFE_VOLUME, 0, NODE_LFE_MUTE, 1);
// NODE_LFE_MUTE -> NODE_MAIN_MIX
INIT_NN_CONN (CurrentConnection, NODE_LFE_MUTE, 0, NODE_MAIN_MIX, 13);
}
}
// helper node variable.
TopoNodes ConnectFromNode;
// all connections go from this one
ConnectFromNode = NODE_MAIN_MIX;
// build the beeper & phone mix
if (AdapterCommon->GetPinConfig (PINC_PCBEEP_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_PHONE_PRESENT))
{
// last node -> NODE_BEEP_MIX
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_BEEP_MIX, 1);
// next connection from this point.
ConnectFromNode = NODE_BEEP_MIX;
}
// build the tone control path
if (AdapterCommon->GetNodeConfig (NODEC_TONE_PRESENT))
{
// last node -> NODE_BASS
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_BASS, 1);
// NODE_BASS -> NODE_TREBLE
INIT_NN_CONN (CurrentConnection, NODE_BASS, 0, NODE_TREBLE, 1);
// remember the last node
ConnectFromNode = NODE_TREBLE;
// build the loudness control
if (AdapterCommon->GetNodeConfig (NODEC_LOUDNESS_PRESENT))
{
// last node -> NODE_LOUDNESS
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_LOUDNESS, 1);
// remember the last node
ConnectFromNode = NODE_LOUDNESS;
}
// build the simulated stereo control
if (AdapterCommon->GetNodeConfig (NODEC_SIMUL_STEREO_PRESENT))
{
// last node -> NODE_SIMUL_STEREO
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_SIMUL_STEREO, 1);
// remember the last node
ConnectFromNode = NODE_SIMUL_STEREO;
}
}
//build the master volume output.
// In case of multichannel or headphone we use a master mono control.
if (AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
{
// build the connection from whatever to NODE_VIRT_MASTERMONO_VOLUME
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_VIRT_MASTERMONO_VOLUME, 1);
// NODE_VIRT_MASTERMONO_VOLUME -> NODE_VIRT_MASTERMONO_MUTE
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTERMONO_VOLUME, 0, NODE_VIRT_MASTERMONO_MUTE, 1);
// NODE_VIRT_MASTERMONO_MUTE -> PIN_MASTEROUT_DEST pin
INIT_NF_CONN( CurrentConnection, NODE_VIRT_MASTERMONO_MUTE, 0, PIN_MASTEROUT_DEST);
}
else
{
// build the connection from whatever to NODE_MASTEROUT_VOLUME
INIT_NN_CONN (CurrentConnection, ConnectFromNode, 0, NODE_MASTEROUT_VOLUME, 1);
// NODE_MASTEROUT_VOLUME -> NODE_MASTEROUT_MUTE
INIT_NN_CONN (CurrentConnection, NODE_MASTEROUT_VOLUME, 0, NODE_MASTEROUT_MUTE, 1);
// NODE_MASTEROUT_MUTE -> PIN_MASTEROUT_DEST pin
INIT_NF_CONN( CurrentConnection, NODE_MASTEROUT_MUTE, 0, PIN_MASTEROUT_DEST);
}
// now complete the input muxer path
// PIN_VIRT_TONE_MIX_MONO_SOURCE -> NODE_VIRT_MASTER_INPUT_VOLUME7
INIT_FN_CONN (CurrentConnection, PIN_VIRT_TONE_MIX_MONO_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME7, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME7 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME7, 0, NODE_WAVEIN_SELECT, 7);
// PIN_VIRT_TONE_MIX_SOURCE -> NODE_VIRT_MASTER_INPUT_VOLUME6
INIT_FN_CONN (CurrentConnection, PIN_VIRT_TONE_MIX_SOURCE, NODE_VIRT_MASTER_INPUT_VOLUME6, 1);
// NODE_VIRT_MASTER_INPUT_VOLUME6 -> NODE_WAVEIN_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MASTER_INPUT_VOLUME6, 0, NODE_WAVEIN_SELECT, 6);
// NODE_WAVEIN_SELECT -> PIN_WAVEIN_DEST
INIT_NF_CONN( CurrentConnection, NODE_WAVEIN_SELECT, 0, PIN_WAVEIN_DEST);
// build the mic output path (for record control)
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT) &&
AdapterCommon->GetPinConfig (PINC_MICIN_PRESENT))
{
// NODE_MIC_BOOST -> NODE_MICIN_VOLUME
INIT_NN_CONN (CurrentConnection, NODE_MIC_BOOST, 0, NODE_MICIN_VOLUME, 1);
// NODE_MICIN_VOLUME -> NODE_MICIN_MUTE
INIT_NN_CONN (CurrentConnection, NODE_MICIN_VOLUME, 0, NODE_MICIN_MUTE, 1);
// NODE_MICIN_MUTE -> PIN_MICIN_DEST
INIT_NF_CONN( CurrentConnection, NODE_MICIN_MUTE, 0, PIN_MICIN_DEST);
}
// build the mono path
if (AdapterCommon->GetPinConfig (PINC_MONOOUT_PRESENT))
{
// PIN_VIRT_3D_MIX_MONO_SOURCE -> NODE_MONOOUT_SMIX
INIT_FN_CONN (CurrentConnection, PIN_VIRT_3D_MIX_MONO_SOURCE, NODE_VIRT_MONOOUT_VOLUME1, 1);
// NODE_VIRT_MONOOUT_VOLUME1 -> NODE_MONOOUT_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MONOOUT_VOLUME1, 0, NODE_MONOOUT_SELECT, 1);
if (AdapterCommon->GetPinConfig (PINC_MIC_PRESENT))
{
// NODE_MIC_BOOST -> NODE_VIRT_MONOOUT_VOLUME2
INIT_NN_CONN (CurrentConnection, NODE_MIC_BOOST, 0, NODE_VIRT_MONOOUT_VOLUME2, 1);
// NODE_VIRT_MONOOUT_VOLUME2 -> NODE_MONOOUT_SELECT
INIT_NN_CONN (CurrentConnection, NODE_VIRT_MONOOUT_VOLUME2, 0, NODE_MONOOUT_SELECT, 2);
}
// NODE_MONOOUT_SELECT -> PIN_MONOOUT_DEST
INIT_NF_CONN( CurrentConnection, NODE_MONOOUT_SELECT, 0, PIN_MONOOUT_DEST);
}
// add the connections to the filter descriptor
FilterDescriptor->ConnectionCount = ConnectionCount;
FilterDescriptor->Connections = ConnectionDescriptors;
} else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
#undef INIT_NN_CONN
#undef INIT_FN_CONN
#undef INIT_NF_CONN
}
/*****************************************************************************
* CMiniportTopologyICH::UpdateRecordMute
*****************************************************************************
* Updates the record mute control. This is used to have DRM functionality.
* In the case that we play a DRM file that is copy protected, we have to
* mute the record if stereo or mono mix is selected. We also have to update
* the record mute every time the DRM content changes or the playback stream
* goes away. The property handler also calls this function to update the
* record mute in case stereo or mono mix is selected.
*/
void CMiniportTopologyICH::UpdateRecordMute (void)
{
PAGED_CODE ();
WORD wRegister;
TopoNodes Node;
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::UpdateRecordMute]"));
// Get the record muxer setting.
if (!NT_SUCCESS (AdapterCommon->ReadCodecRegister (
AdapterCommon->GetNodeReg (NODE_WAVEIN_SELECT), &wRegister)))
return;
// Mask out every unused bit.
wRegister &= (AdapterCommon->GetNodeMask (NODE_WAVEIN_SELECT) & AC97REG_MASK_RIGHT);
// Calculate how we would program the mute.
switch (wRegister)
{
// This is stereo mix.
case 5:
Node = NODE_VIRT_MASTER_INPUT_VOLUME6;
break;
// This is mono mix.
case 6:
Node = NODE_VIRT_MASTER_INPUT_VOLUME7;
break;
// Something else selected than stereo mix or mono mix.
default:
return;
}
// Program the mute.
AdapterCommon->WriteCodecRegister (AC97REG_RECORD_GAIN,
(m_bCopyProtectFlag ? AC97REG_MASK_MUTE : 0), AC97REG_MASK_MUTE);
}
/*****************************************************************************
* CMiniportTopologyICH::GetPhysicalConnectionPins
*****************************************************************************
* Returns the system pin IDs of the bridge pins that are connected with the
* wave miniport.
* If one pin is not used, the value is -1, that could only happen for MinInDest.
*/
STDMETHODIMP CMiniportTopologyICH::GetPhysicalConnectionPins
(
OUT PULONG WaveOutSource,
OUT PULONG WaveInDest,
OUT PULONG MicInDest
)
{
PAGED_CODE ();
ASSERT (WaveOutSource);
ASSERT (WaveInDest);
ASSERT (MicInDest);
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::GetPhysicalConnectionPins]"));
// set the pin IDs.
*WaveOutSource = TransPinDefToPinNr (PIN_WAVEOUT_SOURCE);
*WaveInDest = TransPinDefToPinNr (PIN_WAVEIN_DEST);
// this is optional
if (AdapterCommon->GetPinConfig (PINC_MICIN_PRESENT))
*MicInDest = TransPinDefToPinNr (PIN_MICIN_DEST);
else
*MicInDest = -1;
return STATUS_SUCCESS;
}