📄 prophnd.cpp
字号:
/********************************************************************************
** 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[] = "prophnd: ";
#include <limits.h>
#include "mintopo.h"
// These are the values passed to the property handler in the instance
// parameter that normally represents the channel.
const LONG CHAN_LEFT = 0;
const LONG CHAN_RIGHT = 1;
const LONG CHAN_MASTER = -1;
// paged code goes here.
#pragma code_seg("PAGE")
/*****************************************************************************
* CMiniportTopologyICH::SetMultichannelMute
*****************************************************************************
* This function is used to set one of the multichannel mutes.
* It takes the master mono into account when calculating the mute.
* Make sure that you updated the stNodeCache before calling this function.
*/
NTSTATUS CMiniportTopologyICH::SetMultichannelMute
(
IN CMiniportTopologyICH *that,
IN TopoNodes Mute
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOL bMute;
// The first calls to SetMultichannelMute could be without valid
// cache information because WDMAUD might currently query the nodes
// (this is at system startup). When WDMAUD queried all nodes then
// all cache information will be valid.
if (that->stNodeCache[NODE_VIRT_MASTERMONO_MUTE].bLeftValid &&
that->stNodeCache[Mute].bLeftValid)
{
// We get the master mono mute and the mute that is to change.
// Then we "or" them and write the value to the register.
bMute = that->stNodeCache[NODE_VIRT_MASTERMONO_MUTE].lLeft ||
that->stNodeCache[Mute].lLeft;
ntStatus = that->AdapterCommon->WriteCodecRegister (
that->AdapterCommon->GetNodeReg (Mute),
bMute ? -1 : 0,
that->AdapterCommon->GetNodeMask (Mute));
DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x", NodeStrings[Mute], (int)bMute));
}
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologyICH::SetMultichannelVolume
*****************************************************************************
* This function is used to set one of the multichannel volumes.
* It takes the master mono into account when calculating the volume.
* Make sure that you updated the stNodeCache before calling this function.
*/
NTSTATUS CMiniportTopologyICH::SetMultichannelVolume
(
IN CMiniportTopologyICH *that,
IN TopoNodes Volume
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
LONG lMinimum, lMaximum;
ULONG uStep;
LONG lLevel;
WORD wRegister;
// The first calls to SetMultichannelMute could be without valid
// cache information because WDMAUD might currently query the nodes
// (this is at system startup). When WDMAUD queried all nodes then
// all cache information will be valid.
if (that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].bLeftValid &&
that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].bRightValid &&
that->stNodeCache[Volume].bLeftValid &&
that->stNodeCache[Volume].bRightValid)
{
// We get the master mono volume and the volume that is to change.
// Then we substract master mono from it and write the value to the
// register.
lLevel = that->stNodeCache[Volume].lLeft +
that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lLeft;
// Translate the dB value into a register value.
// Get the registered DB values
ntStatus = GetDBValues (that->AdapterCommon, Volume,
&lMinimum, &lMaximum, &uStep);
if (!NT_SUCCESS(ntStatus))
return ntStatus;
// Check borders.
if (lLevel < lMinimum) lLevel = lMinimum;
if (lLevel > lMaximum) lLevel = lMaximum;
// Calculate the register value
wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep) << 8;
// Get the right value too.
lLevel = that->stNodeCache[Volume].lRight +
that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lRight;
// Check borders.
if (lLevel < lMinimum) lLevel = lMinimum;
if (lLevel > lMaximum) lLevel = lMaximum;
// Add it to the register value.
wRegister += (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
// Write it.
ntStatus = that->AdapterCommon->WriteCodecRegister (
that->AdapterCommon->GetNodeReg (Volume),
wRegister,
that->AdapterCommon->GetNodeMask (Volume));
DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x/0x%x", NodeStrings[Volume],
that->stNodeCache[Volume].lLeft +
that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lLeft,
lLevel));
}
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologyICH::GetDBValues
*****************************************************************************
* This function is used internally and does no parameter checking. The only
* parameter that could be invalid is the node.
* It returns the dB values (means minimum, maximum, step) of the node control,
* mainly for the property call "basic support". Sure, the node must be a
* volume or tone control node, not a mute or mux node.
*/
NTSTATUS CMiniportTopologyICH::GetDBValues
(
IN PADAPTERCOMMON AdapterCommon,
IN TopoNodes Node,
OUT LONG *plMinimum,
OUT LONG *plMaximum,
OUT ULONG *puStep
)
{
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::GetDBValues]"));
// This is going to be simple. Check the node and return the parameters.
switch (Node)
{
// These nodes could have 5bit or 6bit controls, so we first
// have to check this.
case NODE_MASTEROUT_VOLUME:
case NODE_FRONT_VOLUME:
case NODE_HPOUT_VOLUME:
case NODE_SURROUND_VOLUME:
case NODE_CENTER_VOLUME:
case NODE_LFE_VOLUME:
case NODE_VIRT_MONOOUT_VOLUME1:
case NODE_VIRT_MONOOUT_VOLUME2:
// needed for the config query
TopoNodeConfig config;
// which node to query?
config = NODEC_6BIT_MONOOUT_VOLUME;
if ((Node == NODE_MASTEROUT_VOLUME) || (Node == NODE_FRONT_VOLUME))
config = NODEC_6BIT_MASTER_VOLUME;
if (Node == NODE_HPOUT_VOLUME)
config = NODEC_6BIT_HPOUT_VOLUME;
if (Node == NODE_SURROUND_VOLUME)
config = NODEC_6BIT_SURROUND_VOLUME;
if ((Node == NODE_CENTER_VOLUME) || (Node == NODE_LFE_VOLUME))
config = NODEC_6BIT_CENTER_LFE_VOLUME;
// check if we have 6th bit support.
if (AdapterCommon->GetNodeConfig (config))
{
// 6bit control
*plMaximum = 0; // 0 dB
*plMinimum = 0xFFA18000; // -94.5 dB
*puStep = 0x00018000; // 1.5 dB
}
else
{
// 5bit control
*plMaximum = 0; // 0 dB
*plMinimum = 0xFFD18000; // -46.5 dB
*puStep = 0x00018000; // 1.5 dB
}
break;
case NODE_VIRT_MASTERMONO_VOLUME:
// This virtual control gets added to the speaker volumes.
// We assume 5-bit volumes.
*plMaximum = 0; // 0 dB
*plMinimum = 0xFFD18000; // -46.5 dB
*puStep = 0x00018000; // 1.5 dB
break;
case NODE_PCBEEP_VOLUME:
*plMaximum = 0; // 0 dB
*plMinimum = 0xFFD30000; // -45 dB
*puStep = 0x00030000; // 3 dB
break;
case NODE_PHONE_VOLUME:
case NODE_MICIN_VOLUME:
case NODE_LINEIN_VOLUME:
case NODE_CD_VOLUME:
case NODE_VIDEO_VOLUME:
case NODE_AUX_VOLUME:
case NODE_WAVEOUT_VOLUME:
*plMaximum = 0x000C0000; // 12 dB
*plMinimum = 0xFFDD8000; // -34.5 dB
*puStep = 0x00018000; // 1.5 dB
break;
case NODE_VIRT_MASTER_INPUT_VOLUME1:
case NODE_VIRT_MASTER_INPUT_VOLUME2:
case NODE_VIRT_MASTER_INPUT_VOLUME3:
case NODE_VIRT_MASTER_INPUT_VOLUME4:
case NODE_VIRT_MASTER_INPUT_VOLUME5:
case NODE_VIRT_MASTER_INPUT_VOLUME6:
case NODE_VIRT_MASTER_INPUT_VOLUME7:
case NODE_VIRT_MASTER_INPUT_VOLUME8:
case NODE_MIC_VOLUME:
*plMaximum = 0x00168000; // 22.5 dB
*plMinimum = 0; // 0 dB
*puStep = 0x00018000; // 1.5 dB
break;
case NODE_BASS:
case NODE_TREBLE:
*plMaximum = 0x000A8000; // 10.5 dB
*plMinimum = 0xFFF58000; // -10.5 dB
*puStep = 0x00018000; // 1.5 dB
break;
// These nodes can be fixed or variable.
// Normally we won't display a fixed volume slider, but if 3D is
// supported and both sliders are fixed, we have to display one fixed
// slider for the advanced control panel.
case NODE_VIRT_3D_CENTER:
case NODE_VIRT_3D_DEPTH:
if (AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE) &&
(Node == NODE_VIRT_3D_CENTER))
{
*plMaximum = 0x000F0000; // +15 dB
*plMinimum = 0x00000000; // 0 dB
*puStep = 0x00010000; // 1 dB
}
else
if (AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) &&
(Node == NODE_VIRT_3D_DEPTH))
{
*plMaximum = 0x000F0000; // +15 dB
*plMinimum = 0x00000000; // 0 dB
*puStep = 0x00010000; // 1 dB
}
else
{
// In case it is fixed, read the value and return it.
WORD wRegister;
// read the register
if (!NT_SUCCESS (AdapterCommon->ReadCodecRegister (
AdapterCommon->GetNodeReg (Node), &wRegister)))
wRegister = 0; // in case we fail.
// mask out the control
wRegister &= AdapterCommon->GetNodeMask (Node);
if (Node == NODE_VIRT_3D_CENTER)
{
wRegister >>= 8;
}
// calculate the dB value.
*plMaximum = (DWORD)(-wRegister) << 16; // fixed value
*plMinimum = (DWORD)(-wRegister) << 16; // fixed value
*puStep = 0x00010000; // 1 dB
}
break;
case NODE_INVALID:
default:
// poeser pupe, tu.
DOUT (DBG_ERROR, ("GetDBValues: Invalid node requested."));
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*****************************************************************************
* CMiniportTopologyICH::PropertyHandler_OnOff
*****************************************************************************
* Accesses a KSAUDIO_ONOFF value property.
* This function (property handler) is called by portcls every time there is a
* get or a set request for the node. The connection between the node type and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -