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