|
|
/********************************************************************************
** 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; }
|