📄 prophnd.cpp
字号:
Range->Reserved = 0;
// set the return value size
PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG);
DOUT (DBG_PROPERTY, ("BASIC_SUPPORT: %s max=0x%x min=0x%x step=0x%x",
NodeStrings[that->TransNodeNrToNodeDef (PropertyRequest->Node)],
Range->Bounds.SignedMaximum, Range->Bounds.SignedMinimum,
Range->SteppingDelta));
} else
{
// we hadn't enough space for the range information;
// set the return value size
PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
}
ntStatus = STATUS_SUCCESS;
}
else if (PropertyRequest->ValueSize >= sizeof(ULONG))
{
// if return buffer can hold a ULONG, return the access flags
PULONG AccessFlags = (PULONG)PropertyRequest->Value;
*AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET |
KSPROPERTY_TYPE_SET;
// set the return value size
PropertyRequest->ValueSize = sizeof(ULONG);
ntStatus = STATUS_SUCCESS;
}
// In case there was not even enough space for a ULONG in the return buffer,
// we fail this request with STATUS_INVALID_DEVICE_REQUEST.
// Any other case will return STATUS_SUCCESS.
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologyICH::PropertyHandler_Level
*****************************************************************************
* Accesses a KSAUDIO_LEVEL property.
* This function (property handler) is called by portcls every time there is a
* get, set or basic support request for the node. The connection between the
* node type and the property handler is made in the automation table which is
* referenced when you register the node.
* We use this property handler for all volume controls (and virtual volume
* controls for recording).
*/
NTSTATUS CMiniportTopologyICH::PropertyHandler_Level
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE ();
ASSERT (PropertyRequest);
DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_Level]"));
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
TopoNodes NodeDef;
LONG channel;
LONG lMinimum, lMaximum;
ULONG uStep;
// The major target is the object pointer to the topology miniport.
CMiniportTopologyICH *that =
(CMiniportTopologyICH *) PropertyRequest->MajorTarget;
ASSERT (that);
// validate node
if (PropertyRequest->Node == (ULONG)-1)
return ntStatus;
// do the appropriate action for the request.
// we should do a get or a set?
if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) ||
(PropertyRequest->Verb & KSPROPERTY_TYPE_SET))
{
// validate parameters
if ((PropertyRequest->InstanceSize < sizeof(LONG)) ||
(PropertyRequest->ValueSize < sizeof(LONG)))
return ntStatus;
// get channel information
channel = *((PLONG)PropertyRequest->Instance);
// check channel types, return when unknown
// as you can see, we have no multichannel support.
if ((channel != CHAN_LEFT) &&
(channel != CHAN_RIGHT) &&
(channel != CHAN_MASTER))
return ntStatus;
// get the buffer
PLONG Level = (PLONG)PropertyRequest->Value;
// Switch on the node id. This is just for parameter checking.
// If something goes wrong, we will immideately return with
// ntStatus, which is STATUS_INVALID_PARAMETER.
switch(NodeDef = that->TransNodeNrToNodeDef (PropertyRequest->Node))
{
// these are mono channels, don't respond to a right channel
// request.
case NODE_PCBEEP_VOLUME:
case NODE_PHONE_VOLUME:
case NODE_MIC_VOLUME:
case NODE_VIRT_MONOOUT_VOLUME1:
case NODE_VIRT_MONOOUT_VOLUME2:
case NODE_VIRT_MASTER_INPUT_VOLUME1:
case NODE_VIRT_MASTER_INPUT_VOLUME7:
case NODE_VIRT_MASTER_INPUT_VOLUME8:
case NODE_MICIN_VOLUME:
case NODE_VIRT_MASTERMONO_VOLUME:
case NODE_CENTER_VOLUME:
case NODE_LFE_VOLUME:
// check type
if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_VOLUMELEVEL)
return ntStatus;
// check channel
if (channel == CHAN_RIGHT)
return ntStatus;
// Well, this is a fake for the routine below that should work
// for all nodes ... On AC97 the right channel are the LSBs and
// mono channels have only LSBs used. Windows however thinks that
// mono channels are left channels (only). So we could say here
// we have a right channel request (to prg. the LSBs) instead of
// a left channel request. But we have some controls that are HW-
// stereo, but exposed to the system as mono. These are the virtual
// volume controls in front of the wave-in muxer for the MIC, PHONE
// and MONO MIX signals (see to the switch:
// NODE_VIRT_MASTER_INPUT_VOLUME1, 7 and 8). Saying we have a MASTER
// request makes sure the value is prg. for left and right channel,
// but on HW-mono controls the right channel is prg. only, cause the
// mask in ac97reg.h leads to a 0-mask for left channel prg. which
// just does nothing ;)
channel = CHAN_MASTER;
break;
// These are stereo channels.
case NODE_MASTEROUT_VOLUME:
case NODE_FRONT_VOLUME:
case NODE_SURROUND_VOLUME:
case NODE_HPOUT_VOLUME:
case NODE_LINEIN_VOLUME:
case NODE_CD_VOLUME:
case NODE_VIDEO_VOLUME:
case NODE_AUX_VOLUME:
case NODE_WAVEOUT_VOLUME:
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:
// check type
if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_VOLUMELEVEL)
return ntStatus;
// check channel; we don't support a get with master
if ((channel == CHAN_MASTER) &&
(PropertyRequest->Verb & KSPROPERTY_TYPE_GET))
return ntStatus;
break;
case NODE_INVALID:
default:
// Ooops
DOUT (DBG_ERROR, ("PropertyHandler_Level: Invalid node requested."));
return ntStatus;
}
// Now, do some action!
// get the registered dB values.
ntStatus = GetDBValues (that->AdapterCommon, NodeDef, &lMinimum,
&lMaximum, &uStep);
if (!NT_SUCCESS (ntStatus))
return ntStatus;
// do a get
if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
WORD wRegister;
// Read the HW register for the node except NODE_VIRT_MASTERMONO_VOLUME
// since this is pure virtual.
if (NodeDef != NODE_VIRT_MASTERMONO_VOLUME)
{
// Get the register and read it.
ntStatus = that->AdapterCommon->ReadCodecRegister (
that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
if (!NT_SUCCESS (ntStatus))
return ntStatus;
// mask out every unused bit and rotate.
if (channel == CHAN_LEFT)
{
wRegister = (wRegister & (that->AdapterCommon->GetNodeMask (NodeDef)
& AC97REG_MASK_LEFT)) >> 8;
}
else // here goes mono or stereo-right
{
wRegister &= (that->AdapterCommon->GetNodeMask (NodeDef) &
AC97REG_MASK_RIGHT);
}
// Oops - NODE_PCBEEP_VOLUME doesn't use bit0. We have to adjust.
if (NodeDef == NODE_PCBEEP_VOLUME)
wRegister >>= 1;
// we have to translate the reg to dB.dB value.
switch (NodeDef)
{
// for record, we calculate it reverse.
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_MICIN_VOLUME:
*Level = lMinimum + uStep * wRegister;
break;
default:
*Level = lMaximum - uStep * wRegister;
break;
}
// For the virtual controls, which are in front of a muxer, there
// is no mute control displayed. But we have a HW mute control, so
// what we do is enabling this mute when the user moves the slider
// down to the bottom and disabling it on every other position.
// We will return a PROP_MOST_NEGATIVE value in case the slider
// is moved to the bottom.
// We do this only for the "mono muxer" since the volume there ranges
// from 0 to -46.5dB. The record volumes only have a range from
// 0 to +22.5dB and we cannot mute them when the slider is down.
if ((NodeDef == NODE_VIRT_MONOOUT_VOLUME1) ||
(NodeDef == NODE_VIRT_MONOOUT_VOLUME2))
{
// read the register again.
ntStatus = that->AdapterCommon->ReadCodecRegister (
that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
if (!NT_SUCCESS (ntStatus))
return ntStatus;
// return most negative value in case it is checked.
if (wRegister & AC97REG_MASK_MUTE)
*Level = PROP_MOST_NEGATIVE;
}
}
else // This is master mono volume.
{
// Assume 0dB for master mono volume.
*Level = 0;
}
// when we have cache information then return this instead
// of the calculated value. if we don't, store the calculated
// value.
// We do that twice for master because in case we didn't set
// the NodeCache yet it will be set then.
if ((channel == CHAN_LEFT) || (channel == CHAN_MASTER))
{
if (that->stNodeCache[NodeDef].bLeftValid)
*Level = that->stNodeCache[NodeDef].lLeft;
else
{
that->stNodeCache[NodeDef].lLeft = *Level;
that->stNodeCache[NodeDef].bLeftValid = -1;
}
}
if ((channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
{
if (that->stNodeCache[NodeDef].bRightValid)
*Level = that->stNodeCache[NodeDef].lRight;
else
{
that->stNodeCache[NodeDef].lRight = *Level;
that->stNodeCache[NodeDef].bRightValid = -1;
}
}
// thats all, good bye.
PropertyRequest->ValueSize = sizeof(LONG);
DOUT (DBG_PROPERTY, ("GET: %s(%s) = 0x%x",NodeStrings[NodeDef],
channel==CHAN_LEFT ? "L" : "R", *Level));
// ntStatus was set with the read call! whatever this is, return it.
}
else // this must be a set
{
WORD wRegister;
LONG lLevel = *Level;
//
// Check borders.
//
// These 2 lines will have a special effect on sndvol32.
// Whenever you move the balance slider on a volume, one channel
// keeps the same and the other volume channel gets descreased.
// With ac97 on recording controls, the default slider position
// is at 0dB and the range of the volume is 0dB till +22.5dB.
// That means that panning (moving the balance slider) is simply
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -