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

1521 lines
61 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************
* mintopo.cpp - SB16 topology miniport implementation
*****************************************************************************
* Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
*/
#include "limits.h"
#include "mintopo.h"
#define STR_MODULENAME "sb16topo: "
#define CHAN_LEFT 0
#define CHAN_RIGHT 1
#define CHAN_MASTER (-1)
#pragma code_seg("PAGE")
/*****************************************************************************
* CreateMiniportTopologySB16()
*****************************************************************************
* Creates a topology miniport object for the SB16 adapter. This uses a
* macro from STDUNK.H to do all the work.
*/
NTSTATUS
CreateMiniportTopologySB16
(
OUT PUNKNOWN * Unknown,
IN REFCLSID,
IN PUNKNOWN UnknownOuter OPTIONAL,
IN POOL_TYPE PoolType
)
{
PAGED_CODE();
ASSERT(Unknown);
STD_CREATE_BODY_(CMiniportTopologySB16,Unknown,UnknownOuter,PoolType,PMINIPORTTOPOLOGY);
}
/*****************************************************************************
* CMiniportTopologySB16::NonDelegatingQueryInterface()
*****************************************************************************
* Obtains an interface. This function works just like a COM QueryInterface
* call and is used if the object is not being aggregated.
*/
STDMETHODIMP
CMiniportTopologySB16::
NonDelegatingQueryInterface
(
IN REFIID Interface,
OUT PVOID * Object
)
{
PAGED_CODE();
ASSERT(Object);
_DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::NonDelegatingQueryInterface]"));
if (IsEqualGUIDAligned(Interface,IID_IUnknown))
{
*Object = PVOID(PUNKNOWN(PMINIPORTTOPOLOGY(this)));
}
else
if (IsEqualGUIDAligned(Interface,IID_IMiniport))
{
*Object = PVOID(PMINIPORT(this));
}
else
if (IsEqualGUIDAligned(Interface,IID_IMiniportTopology))
{
*Object = PVOID(PMINIPORTTOPOLOGY(this));
}
else
{
*Object = NULL;
}
if (*Object)
{
//
// We reference the interface for the caller.
//
PUNKNOWN(*Object)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
/*****************************************************************************
* CMiniportTopologySB16::~CMiniportTopologySB16()
*****************************************************************************
* Destructor.
*/
CMiniportTopologySB16::
~CMiniportTopologySB16
( void
)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::~CMiniportTopologySB16]"));
if (AdapterCommon)
{
#ifdef EVENT_SUPPORT
AdapterCommon->SetTopologyMiniport (NULL);
#endif
AdapterCommon->SaveMixerSettingsToRegistry();
AdapterCommon->Release();
}
#ifdef EVENT_SUPPORT
if (PortEvents)
{
PortEvents->Release ();
PortEvents = NULL;
}
#endif
}
/*****************************************************************************
* CMiniportTopologySB16::Init()
*****************************************************************************
* Initializes a the miniport.
*/
STDMETHODIMP
CMiniportTopologySB16::
Init
(
IN PUNKNOWN UnknownAdapter,
IN PRESOURCELIST ResourceList,
IN PPORTTOPOLOGY Port
)
{
PAGED_CODE();
ASSERT(UnknownAdapter);
ASSERT(Port);
_DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::Init]"));
NTSTATUS ntStatus =
UnknownAdapter->QueryInterface
(
IID_IAdapterCommon,
(PVOID *) &AdapterCommon
);
if (NT_SUCCESS(ntStatus))
{
#ifdef EVENT_SUPPORT
//
// Get the port event interface.
//
NTSTATUS ntStatus2 = Port->QueryInterface (IID_IPortEvents, (PVOID *)&PortEvents);
if (NT_SUCCESS(ntStatus2))
{
//
// We need to notify AdapterCommon of the miniport interface.
// AdapterCommon needs this in his ISR to fire the event.
//
AdapterCommon->SetTopologyMiniport ((PTOPOMINIPORTSB16)this);
//
// Enable external volume control interrupt.
//
BYTE bIntrMask = AdapterCommon->MixerRegRead (0x83);
bIntrMask |= 0x10;
AdapterCommon->MixerRegWrite (0x83, bIntrMask);
}
#endif
AdapterCommon->MixerReset();
}
return ntStatus;
}
/*****************************************************************************
* CMiniportTopologySB16::GetDescription()
*****************************************************************************
* Gets the topology.
*/
STDMETHODIMP
CMiniportTopologySB16::
GetDescription
(
OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
)
{
PAGED_CODE();
ASSERT(OutFilterDescriptor);
_DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::GetDescription]"));
*OutFilterDescriptor = &MiniportFilterDescriptor;
return STATUS_SUCCESS;
}
/*****************************************************************************
* PropertyHandler_OnOff()
*****************************************************************************
* Accesses a KSAUDIO_ONOFF value property.
*/
static
NTSTATUS
PropertyHandler_OnOff
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_OnOff]"));
CMiniportTopologySB16 *that =
(CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
BYTE data;
LONG channel;
// validate node
if (PropertyRequest->Node != ULONG(-1))
{
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
// get the instance channel parameter
if(PropertyRequest->InstanceSize >= sizeof(LONG))
{
channel = *(PLONG(PropertyRequest->Instance));
// validate and get the output parameter
if (PropertyRequest->ValueSize >= sizeof(BOOL))
{
PBOOL OnOff = PBOOL(PropertyRequest->Value);
// switch on node id
switch(PropertyRequest->Node)
{
case MIC_AGC: // Microphone AGC Control (mono)
// check if AGC property request on mono/left channel
if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC ) &&
( channel == CHAN_LEFT ) )
{
data = that->ReadBitsFromMixer( DSP_MIX_AGCIDX,
1,
MIXBIT_MIC_AGC );
*OnOff = data ? FALSE : TRUE;
PropertyRequest->ValueSize = sizeof(BOOL);
ntStatus = STATUS_SUCCESS;
}
break;
case MIC_LINEOUT_MUTE: // Microphone Lineout Mute Control (mono)
// check if MUTE property request on mono/left channel
if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE ) &&
( channel == CHAN_LEFT ) )
{
data = that->ReadBitsFromMixer( DSP_MIX_OUTMIXIDX,
1,
MIXBIT_MIC_LINEOUT );
*OnOff = data ? FALSE : TRUE;
PropertyRequest->ValueSize = sizeof(BOOL);
ntStatus = STATUS_SUCCESS;
}
break;
}
}
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
{
// get the instance channel parameter
if(PropertyRequest->InstanceSize >= sizeof(LONG))
{
channel = *(PLONG(PropertyRequest->Instance));
// validate and get the input parameter
if (PropertyRequest->ValueSize == sizeof(BOOL))
{
BYTE value = *(PBOOL(PropertyRequest->Value)) ? 0 : 1;
// switch on the node id
switch(PropertyRequest->Node)
{
case MIC_AGC: // Microphone AGC Control (mono)
// check if AGC property request on mono/left channel
if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC ) &&
( channel == CHAN_LEFT ) )
{
that->WriteBitsToMixer( DSP_MIX_AGCIDX,
1,
MIXBIT_MIC_AGC,
value );
ntStatus = STATUS_SUCCESS;
}
break;
case MIC_LINEOUT_MUTE: // Microphone Lineout Mute Control (mono)
// check if MUTE property request on mono/left channel
if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE ) &&
( channel == CHAN_LEFT ) )
{
that->WriteBitsToMixer( DSP_MIX_OUTMIXIDX,
1,
MIXBIT_MIC_LINEOUT,
value );
ntStatus = STATUS_SUCCESS;
}
break;
}
}
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
if ( ( (PropertyRequest->Node == MIC_AGC) && (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC) ) ||
( (PropertyRequest->Node == MIC_LINEOUT_MUTE) && (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE) ) )
{
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
{
// if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET |
KSPROPERTY_TYPE_SET;
PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
PropDesc->PropTypeSet.Id = VT_BOOL;
PropDesc->PropTypeSet.Flags = 0;
PropDesc->MembersListCount = 0;
PropDesc->Reserved = 0;
// 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;
}
}
}
}
return ntStatus;
}
/*****************************************************************************
* BasicSupportHandler()
*****************************************************************************
* Assists in BASICSUPPORT accesses on level properties
*/
static
NTSTATUS
BasicSupportHandler
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[BasicSupportHandler]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
{
// if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET |
KSPROPERTY_TYPE_SET;
PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG);
PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
PropDesc->PropTypeSet.Id = VT_I4;
PropDesc->PropTypeSet.Flags = 0;
PropDesc->MembersListCount = 1;
PropDesc->Reserved = 0;
// if return buffer cn also hold a range description, return it too
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG)))
{
// fill in the members header
PKSPROPERTY_MEMBERSHEADER Members = PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
Members->MembersCount = 1;
Members->Flags = 0;
// fill in the stepped range
PKSPROPERTY_STEPPING_LONG Range = PKSPROPERTY_STEPPING_LONG(Members + 1);
switch(PropertyRequest->Node)
{
case WAVEOUT_VOLUME:
case SYNTH_VOLUME:
case CD_VOLUME:
case LINEIN_VOLUME:
case MIC_VOLUME:
case LINEOUT_VOL:
Range->Bounds.SignedMaximum = 0; // 0 (dB) * 0x10000
Range->Bounds.SignedMinimum = 0xFFC20000; // -62 (dB) * 0x10000
Range->SteppingDelta = 0x20000; // 2 (dB) * 0x10000
break;
case LINEOUT_GAIN:
case WAVEIN_GAIN:
Range->Bounds.SignedMaximum = 0x120000; // 18 (dB) * 0x10000
Range->Bounds.SignedMinimum = 0; // 0 (dB) * 0x10000
Range->SteppingDelta = 0x60000; // 6 (dB) * 0x10000
break;
case LINEOUT_BASS:
case LINEOUT_TREBLE:
Range->Bounds.SignedMaximum = 0xE0000; // 14 (dB) * 0x10000
Range->Bounds.SignedMinimum = 0xFFF20000; // -14 (dB) * 0x10000
Range->SteppingDelta = 0x20000; // 2 (dB) * 0x10000
break;
}
Range->Reserved = 0;
_DbgPrintF(DEBUGLVL_BLAB, ("---Node: %d Max: 0x%X Min: 0x%X Step: 0x%X",PropertyRequest->Node,
Range->Bounds.SignedMaximum,
Range->Bounds.SignedMinimum,
Range->SteppingDelta));
// set the return value size
PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG);
} else
{
// 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;
}
return ntStatus;
}
/*****************************************************************************
* PropertyHandler_Level()
*****************************************************************************
* Accesses a KSAUDIO_LEVEL property.
*/
static
NTSTATUS
PropertyHandler_Level
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_Level]"));
CMiniportTopologySB16 *that =
(CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
ULONG count;
LONG channel;
// validate node
if(PropertyRequest->Node != ULONG(-1))
{
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
// get the instance channel parameter
if(PropertyRequest->InstanceSize >= sizeof(LONG))
{
channel = *(PLONG(PropertyRequest->Instance));
// only support get requests on either mono/left (0) or right (1) channels
if ( (channel == CHAN_LEFT) || (channel == CHAN_RIGHT) )
{
// validate and get the output parameter
if (PropertyRequest->ValueSize >= sizeof(LONG))
{
PLONG Level = (PLONG)PropertyRequest->Value;
// switch on node if
switch(PropertyRequest->Node)
{
case WAVEOUT_VOLUME:
case SYNTH_VOLUME:
case CD_VOLUME:
case LINEIN_VOLUME:
case MIC_VOLUME:
case LINEOUT_VOL:
// check if volume property request
if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
{
// bail out if a right channel request on the mono mic volume
if( (PropertyRequest->Node == MIC_VOLUME) && (channel != CHAN_LEFT) )
{
break;
}
*Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
#ifdef EVENT_SUPPORT
//
// see if there is a volume changed, update if neccessary.
//
BYTE data = that->ReadBitsFromMixer (
BYTE(AccessParams[PropertyRequest->Node].BaseRegister
+channel+DSP_MIX_BASEIDX),
5, 3);
//
// Convert the dB value into a register value. No boundary check.
// Register is 0 - 31 representing -62dB - 0dB.
//
if (data != ((*Level >> 17) + 31))
{
//
// Convert the register into dB value.
// Register is 0 - 31 representing -62dB - 0dB.
//
*Level = (data - 31) << 17;
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel] = *Level;
}
#endif
PropertyRequest->ValueSize = sizeof(LONG);
ntStatus = STATUS_SUCCESS;
}
break;
case LINEOUT_GAIN:
case WAVEIN_GAIN:
// check if volume property request
if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
{
*Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
PropertyRequest->ValueSize = sizeof(LONG);
ntStatus = STATUS_SUCCESS;
}
break;
case LINEOUT_BASS:
case LINEOUT_TREBLE:
if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
(PropertyRequest->Node == LINEOUT_BASS) ) ||
( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
(PropertyRequest->Node == LINEOUT_TREBLE) ) )
{
*Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
PropertyRequest->ValueSize = sizeof(LONG);
ntStatus = STATUS_SUCCESS;
}
break;
}
}
}
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
{
// get the instance channel parameter
if(PropertyRequest->InstanceSize >= sizeof(LONG))
{
channel = *(PLONG(PropertyRequest->Instance));
// only support set requests on either mono/left (0), right (1), or master (-1) channels
if ( (channel == CHAN_LEFT) || (channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
{
// validate and get the input parameter
if (PropertyRequest->ValueSize == sizeof(LONG))
{
PLONG Level = (PLONG)PropertyRequest->Value;
// switch on the node id
switch(PropertyRequest->Node)
{
case WAVEOUT_VOLUME:
case SYNTH_VOLUME:
case CD_VOLUME:
case LINEIN_VOLUME:
case MIC_VOLUME:
case LINEOUT_VOL:
if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
{
// convert the level to register bits
if(*Level <= (-62 << 16))
{
count = 0;
} else if(*Level >= 0)
{
count = 0x1F;
} else
{
count = ((*Level >> 17) + 31) & 0x1F;
}
// set right channel if channel requested is right or master
// and node is not mic volume (mono)
if ( ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) ) &&
( PropertyRequest->Node != MIC_VOLUME ) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister+1,
5,
3,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
// set the left channel if channel requested is left or master
if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
5,
3,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
}
break;
case LINEOUT_GAIN:
case WAVEIN_GAIN:
if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
{
// determine register bits
if(*Level >= (18 << 16))
{
count = 0x3;
} else if(*Level <= 0)
{
count = 0;
} else
{
count = (*Level >> 17) / 3;
}
// set right channel if channel requested is right or master
if ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister+1,
2,
6,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
// set the left channel if channel requested is left or master
if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
2,
6,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
}
break;
case LINEOUT_BASS:
case LINEOUT_TREBLE:
if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
(PropertyRequest->Node == LINEOUT_BASS) ) ||
( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
(PropertyRequest->Node == LINEOUT_TREBLE) ) )
{
// determine register bits
if(*Level <= (-14 << 16))
{
count = 0;
} else if(*Level >= (14 << 16))
{
count = 0xF;
} else
{
count = ((*Level >> 16) + 14) >> 1;
}
// set right channel if channel requested is right or master
if ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister + 1,
4,
4,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
// set the left channel if channel requested is left or master
if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
{
// cache the commanded control value
ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
4,
4,
BYTE(count) );
ntStatus = STATUS_SUCCESS;
}
}
break;
}
}
}
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
// service basic support request
switch(PropertyRequest->Node)
{
case WAVEOUT_VOLUME:
case SYNTH_VOLUME:
case CD_VOLUME:
case LINEIN_VOLUME:
case MIC_VOLUME:
case LINEOUT_VOL:
case LINEOUT_GAIN:
case WAVEIN_GAIN:
if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
{
ntStatus = BasicSupportHandler(PropertyRequest);
}
break;
case LINEOUT_BASS:
case LINEOUT_TREBLE:
if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
(PropertyRequest->Node == LINEOUT_BASS) ) ||
( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
(PropertyRequest->Node == LINEOUT_TREBLE) ) )
{
ntStatus = BasicSupportHandler(PropertyRequest);
}
break;
}
}
}
return ntStatus;
}
/*****************************************************************************
* PropertyHandler_SuperMixCaps()
*****************************************************************************
* Handles supermixer caps accesses
*/
static
NTSTATUS
PropertyHandler_SuperMixCaps
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_SuperMixCaps]"));
CMiniportTopologySB16 *that =
(CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
ULONG count;
// validate node
if(PropertyRequest->Node != ULONG(-1))
{
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
switch(PropertyRequest->Node)
{
// Full 2x2 Switches
case SYNTH_WAVEIN_SUPERMIX:
case CD_WAVEIN_SUPERMIX:
case LINEIN_WAVEIN_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
{
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 2;
MixCaps->OutputChannels = 2;
ntStatus = STATUS_SUCCESS;
} else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS))
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 2;
MixCaps->OutputChannels = 2;
for(count = 0; count < 4; count++)
{
MixCaps->Capabilities[count].Mute = TRUE;
MixCaps->Capabilities[count].Minimum = 0;
MixCaps->Capabilities[count].Maximum = 0;
MixCaps->Capabilities[count].Reset = 0;
}
ntStatus = STATUS_SUCCESS;
}
break;
// Limited 2x2 Switches
case CD_LINEOUT_SUPERMIX:
case LINEIN_LINEOUT_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
{
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 2;
MixCaps->OutputChannels = 2;
ntStatus = STATUS_SUCCESS;
} else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS))
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 2;
MixCaps->OutputChannels = 2;
for(count = 0; count < 4; count++)
{
if((count == 0) || (count == 3))
{
MixCaps->Capabilities[count].Mute = TRUE;
MixCaps->Capabilities[count].Minimum = 0;
MixCaps->Capabilities[count].Maximum = 0;
MixCaps->Capabilities[count].Reset = 0;
} else
{
MixCaps->Capabilities[count].Mute = FALSE;
MixCaps->Capabilities[count].Minimum = LONG_MIN;
MixCaps->Capabilities[count].Maximum = LONG_MIN;
MixCaps->Capabilities[count].Reset = LONG_MIN;
}
}
ntStatus = STATUS_SUCCESS;
}
break;
// 1x2 Switch
case MIC_WAVEIN_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
{
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 1;
MixCaps->OutputChannels = 2;
ntStatus = STATUS_SUCCESS;
} else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS))
{
PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS);
PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
MixCaps->InputChannels = 1;
MixCaps->OutputChannels = 2;
for(count = 0; count < 2; count++)
{
MixCaps->Capabilities[count].Mute = TRUE;
MixCaps->Capabilities[count].Minimum = 0;
MixCaps->Capabilities[count].Maximum = 0;
MixCaps->Capabilities[count].Reset = 0;
}
ntStatus = STATUS_SUCCESS;
}
break;
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
// service basic support request
switch(PropertyRequest->Node)
{
case SYNTH_WAVEIN_SUPERMIX:
case CD_WAVEIN_SUPERMIX:
case LINEIN_WAVEIN_SUPERMIX:
case CD_LINEOUT_SUPERMIX:
case LINEIN_LINEOUT_SUPERMIX:
case MIC_WAVEIN_SUPERMIX:
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
{
// if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET;
PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
PropDesc->PropTypeSet.Id = VT_ARRAY;
PropDesc->PropTypeSet.Flags = 0;
PropDesc->MembersListCount = 0;
PropDesc->Reserved = 0;
// 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;
// set the return value size
PropertyRequest->ValueSize = sizeof(ULONG);
ntStatus = STATUS_SUCCESS;
}
ntStatus = STATUS_SUCCESS;
break;
}
}
}
return ntStatus;
}
/*****************************************************************************
* PropertyHandler_SuperMixTable()
*****************************************************************************
* Handles supermixer level accesses
*/
static
NTSTATUS
PropertyHandler_SuperMixTable
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_SuperMixTable]"));
CMiniportTopologySB16 *that =
(CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
BYTE dataL,dataR;
// validate node
if(PropertyRequest->Node != ULONG(-1))
{
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
switch(PropertyRequest->Node)
{
// Full 2x2 Switches
case SYNTH_WAVEIN_SUPERMIX:
case CD_WAVEIN_SUPERMIX:
case LINEIN_WAVEIN_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize >= 4 * sizeof(KSAUDIO_MIXLEVEL))
{
PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_L,
2,
AccessParams[PropertyRequest->Node].BaseRegister );
dataR = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_R,
2,
AccessParams[PropertyRequest->Node].BaseRegister );
MixLevel[0].Mute = dataL & 0x2 ? FALSE : TRUE; // left to left mute
MixLevel[0].Level = 0;
MixLevel[1].Mute = dataR & 0x2 ? FALSE : TRUE; // left to right mute
MixLevel[1].Level = 0;
MixLevel[2].Mute = dataL & 0x1 ? FALSE : TRUE; // right to left mute
MixLevel[2].Level = 0;
MixLevel[3].Mute = dataR & 0x1 ? FALSE : TRUE; // right to right mute
MixLevel[3].Level = 0;
ntStatus = STATUS_SUCCESS;
}
break;
// Limited 2x2 Switches
case CD_LINEOUT_SUPERMIX:
case LINEIN_LINEOUT_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize >= 4 * sizeof(KSAUDIO_MIXLEVEL))
{
PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = that->ReadBitsFromMixer( DSP_MIX_OUTMIXIDX,
2,
AccessParams[PropertyRequest->Node].BaseRegister );
MixLevel[0].Mute = dataL & 0x2 ? FALSE : TRUE; // left to left mute
MixLevel[0].Level = 0;
MixLevel[1].Mute = FALSE;
MixLevel[1].Level = LONG_MIN;
MixLevel[2].Mute = FALSE;
MixLevel[2].Level = LONG_MIN;
MixLevel[3].Mute = dataL & 0x1 ? FALSE : TRUE; // right to right mute
MixLevel[3].Level = 0;
ntStatus = STATUS_SUCCESS;
}
break;
// 1x2 Switch
case MIC_WAVEIN_SUPERMIX:
if(!PropertyRequest->ValueSize)
{
PropertyRequest->ValueSize = 2 * sizeof(KSAUDIO_MIXLEVEL);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else if(PropertyRequest->ValueSize >= 2 * sizeof(KSAUDIO_MIXLEVEL))
{
PropertyRequest->ValueSize = 2 * sizeof(KSAUDIO_MIXLEVEL);
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_L,
1,
MIXBIT_MIC_WAVEIN );
dataR = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_R,
1,
MIXBIT_MIC_WAVEIN );
MixLevel[0].Mute = dataL & 0x1 ? FALSE : TRUE; // mono to left mute
MixLevel[0].Level = 0;
MixLevel[1].Mute = dataR & 0x1 ? FALSE : TRUE; // mono to right mute
MixLevel[1].Level = 0;
ntStatus = STATUS_SUCCESS;
}
break;
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
{
switch(PropertyRequest->Node)
{
// Full 2x2 Switches
case SYNTH_WAVEIN_SUPERMIX:
case CD_WAVEIN_SUPERMIX:
case LINEIN_WAVEIN_SUPERMIX:
if(PropertyRequest->ValueSize == 4 * sizeof(KSAUDIO_MIXLEVEL))
{
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = MixLevel[0].Mute ? 0x0 : 0x2;
dataL |= MixLevel[2].Mute ? 0x0 : 0x1;
dataR = MixLevel[1].Mute ? 0x0 : 0x2;
dataR |= MixLevel[3].Mute ? 0x0 : 0x1;
that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_L,
2,
AccessParams[PropertyRequest->Node].BaseRegister,
dataL );
that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_R,
2,
AccessParams[PropertyRequest->Node].BaseRegister,
dataR );
ntStatus = STATUS_SUCCESS;
}
break;
// Limited 2x2 Switches
case CD_LINEOUT_SUPERMIX:
case LINEIN_LINEOUT_SUPERMIX:
if(PropertyRequest->ValueSize == 4 * sizeof(KSAUDIO_MIXLEVEL))
{
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = MixLevel[0].Mute ? 0x0 : 0x2;
dataL |= MixLevel[3].Mute ? 0x0 : 0x1;
that->WriteBitsToMixer( DSP_MIX_OUTMIXIDX,
2,
AccessParams[PropertyRequest->Node].BaseRegister,
dataL );
ntStatus = STATUS_SUCCESS;
}
break;
// 1x2 Switch
case MIC_WAVEIN_SUPERMIX:
if(PropertyRequest->ValueSize == 2 * sizeof(KSAUDIO_MIXLEVEL))
{
PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
dataL = MixLevel[0].Mute ? 0x0 : 0x1;
dataR = MixLevel[1].Mute ? 0x0 : 0x1;
that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_L,
1,
MIXBIT_MIC_WAVEIN,
dataL );
that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_R,
1,
MIXBIT_MIC_WAVEIN,
dataR );
ntStatus = STATUS_SUCCESS;
}
break;
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
// service basic support request
switch(PropertyRequest->Node)
{
case SYNTH_WAVEIN_SUPERMIX:
case CD_WAVEIN_SUPERMIX:
case LINEIN_WAVEIN_SUPERMIX:
case CD_LINEOUT_SUPERMIX:
case LINEIN_LINEOUT_SUPERMIX:
case MIC_WAVEIN_SUPERMIX:
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
{
// if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET |
KSPROPERTY_TYPE_SET;
PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
PropDesc->PropTypeSet.Id = VT_ARRAY;
PropDesc->PropTypeSet.Flags = 0;
PropDesc->MembersListCount = 0;
PropDesc->Reserved = 0;
// 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;
}
break;
}
}
}
return ntStatus;
}
/*****************************************************************************
* PropertyHandler_CpuResources()
*****************************************************************************
* Processes a KSPROPERTY_AUDIO_CPU_RESOURCES request
*/
static
NTSTATUS
PropertyHandler_CpuResources
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_CpuResources]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
// validate node
if(PropertyRequest->Node != ULONG(-1))
{
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
if(PropertyRequest->ValueSize >= sizeof(LONG))
{
*(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
PropertyRequest->ValueSize = sizeof(LONG);
ntStatus = STATUS_SUCCESS;
} else
{
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
{
// if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
KSPROPERTY_TYPE_GET;
PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
PropDesc->PropTypeSet.Id = VT_I4;
PropDesc->PropTypeSet.Flags = 0;
PropDesc->MembersListCount = 0;
PropDesc->Reserved = 0;
// 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;
}
}
}
return ntStatus;
}
/*****************************************************************************
* PropertyHandler_ComponentId()
*****************************************************************************
* Processes a KSPROPERTY_GENERAL_COMPONENTID request
*/
NTSTATUS
PropertyHandler_ComponentId
(
IN PPCPROPERTY_REQUEST PropertyRequest
)
{
PAGED_CODE();
ASSERT(PropertyRequest);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_ComponentId]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
if(PropertyRequest->ValueSize >= sizeof(KSCOMPONENTID))
{
PKSCOMPONENTID pComponentId = (PKSCOMPONENTID)
PropertyRequest->Value;
INIT_MMREG_MID(&pComponentId->Manufacturer, MM_MICROSOFT);
pComponentId->Product = PID_MSSB16;
pComponentId->Name = NAME_MSSB16;
pComponentId->Component = GUID_NULL; // Not used for extended caps.
pComponentId->Version = MSSB16_VERSION;
pComponentId->Revision = MSSB16_REVISION;
PropertyRequest->ValueSize = sizeof(KSCOMPONENTID);
ntStatus = STATUS_SUCCESS;
} else if(PropertyRequest->ValueSize == 0)
{
PropertyRequest->ValueSize = sizeof(KSCOMPONENTID);
ntStatus = STATUS_BUFFER_OVERFLOW;
} else
{
PropertyRequest->ValueSize = 0;
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
} else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
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;
// set the return value size
PropertyRequest->ValueSize = sizeof(ULONG);
ntStatus = STATUS_SUCCESS;
} else
{
PropertyRequest->ValueSize = 0;
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
}
return ntStatus;
}
/*****************************************************************************
* ThisManyOnes()
*****************************************************************************
* Returns a byte with the indicated number of ones in the low end.
*/
inline
BYTE
ThisManyOnes
(
IN BYTE Ones
)
{
return ~(BYTE(0xff) << Ones);
}
/*****************************************************************************
* CMiniportTopologySB16::ReadBitsFromMixer()
*****************************************************************************
* Reads specified bits from a mixer register.
*/
BYTE
CMiniportTopologySB16::
ReadBitsFromMixer
(
BYTE Reg,
BYTE Bits,
BYTE Shift
)
{
BYTE data = AdapterCommon->MixerRegRead(Reg);
return( data >> Shift) & ThisManyOnes(Bits);
}
/*****************************************************************************
* CMiniportTopologySB16::WriteBitsToMixer()
*****************************************************************************
* Writes specified bits to a mixer register.
*/
void
CMiniportTopologySB16::
WriteBitsToMixer
(
BYTE Reg,
BYTE Bits,
BYTE Shift,
BYTE Value
)
{
BYTE mask = ThisManyOnes(Bits) << Shift;
BYTE data = AdapterCommon->MixerRegRead(Reg);
if(Reg < DSP_MIX_MAXREGS)
{
AdapterCommon->MixerRegWrite( Reg,
(data & ~mask) | ( (Value << Shift) & mask));
}
}
#ifdef EVENT_SUPPORT
/*****************************************************************************
* CMiniportTopologySB16::EventHandler
*****************************************************************************
* This is the generic event handler.
*/
NTSTATUS CMiniportTopologySB16::EventHandler
(
IN PPCEVENT_REQUEST EventRequest
)
{
PAGED_CODE();
ASSERT(EventRequest);
_DbgPrintF (DEBUGLVL_VERBOSE, ("CMiniportTopologyICH::EventHandler"));
// The major target is the object pointer to the topology miniport.
CMiniportTopologySB16 *that =
(CMiniportTopologySB16 *)(PMINIPORTTOPOLOGY(EventRequest->MajorTarget));
ASSERT (that);
// Validate the node.
if (EventRequest->Node != LINEOUT_VOL)
return STATUS_INVALID_PARAMETER;
// What is to do?
switch (EventRequest->Verb)
{
// Do we support event handling?!?
case PCEVENT_VERB_SUPPORT:
_DbgPrintF (DEBUGLVL_VERBOSE, ("BasicSupport Query for Event."));
break;
// We should add the event now!
case PCEVENT_VERB_ADD:
_DbgPrintF (DEBUGLVL_VERBOSE, ("Adding Event."));
// If we have the interface and EventEntry is defined ...
if ((EventRequest->EventEntry) && (that->PortEvents))
{
that->PortEvents->AddEventToEventList (EventRequest->EventEntry);
}
else
{
return STATUS_UNSUCCESSFUL;
}
break;
case PCEVENT_VERB_REMOVE:
// We cannot remove the event but we can stop generating the
// events. However, it also doesn't hurt to always generate them ...
_DbgPrintF (DEBUGLVL_VERBOSE, ("Removing Event."));
break;
default:
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
#pragma code_seg()
/*****************************************************************************
* CMiniportTopologySB16::ServiceEvent()
*****************************************************************************
* This routine is called by the ISR to handle the event (volume) interrupt.
*/
STDMETHODIMP_(void) CMiniportTopologySB16::ServiceEvent (void)
{
//
// Generate an event for the master volume (as an example)
//
if (PortEvents)
{
PortEvents->GenerateEventList (NULL, KSEVENT_CONTROL_CHANGE,
FALSE, ULONG(-1), TRUE,
LINEOUT_VOL);
}
}
#endif // EVENT_SUPPORT