Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1171 lines
30 KiB

/*++
"@(#) NEC mixer.c 1.1 95/03/22 21:23:31"
Copyright (c) 1995 NEC Corporation
Copyright (c) 1993 Microsoft Corporation
Module Name:
mixer.c
Abstract:
Mixer code for the Microsoft sound system card.
Kernel mode
Revision History:
--*/
#include "sound.h"
#include <soundcfg.h>
#define absval(x) ((x) > 0 ? (x) : -(x))
/*
** Local functions and data
*/
VOID
SoundWaveinLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SoundWaveoutLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SoundSynthLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
NTSTATUS
HwGetLineFlags(
PMIXER_INFO MixerInfo,
ULONG LineId,
ULONG Length,
PVOID pData
);
NTSTATUS
HwGetControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
);
NTSTATUS
HwSetControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
);
NTSTATUS
HwGetCombinedControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
);
VOID
SoundNotifySynth(
PGLOBAL_DEVICE_INFO pGDI
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,SoundMixerInit)
#pragma alloc_text(PAGE,SoundSaveMixerSettings)
#pragma alloc_text(PAGE,SoundWaveinLineChanged)
#pragma alloc_text(PAGE,SoundWaveoutLineChanged)
#pragma alloc_text(PAGE,SoundSynthLineChanged)
#pragma alloc_text(PAGE,SoundMixerDumpConfiguration)
#pragma alloc_text(PAGE,SoundNotifySynth)
#pragma alloc_text(PAGE,HwGetLineFlags)
#pragma alloc_text(PAGE,HwGetControl)
#pragma alloc_text(PAGE,HwGetCombinedControl)
#pragma alloc_text(PAGE,HwSetControl)
#endif
VOID
SoundSaveMixerSettings(
PGLOBAL_DEVICE_INFO pGDI
)
{
PLOCAL_MIXER_DATA LocalMixerData;
MIXER_CONTROL_DATA_ITEM SavedControlData[MAXSETTABLECONTROLS];
int i;
int SetIndex;
dprintf4(("SoundSaveMixerSettings()"));
LocalMixerData = &pGDI->LocalMixerData;
/*
** Condense the data for storing in the registry
*/
for (i = 0, SetIndex = 0; i < MAXCONTROLS; i++) {
if (pGDI->LocalMixerData.ControlInfo[i].SetIndex != MIXER_SET_INDEX_INVALID) {
ASSERT(SetIndex == pGDI->LocalMixerData.ControlInfo[i].SetIndex);
SavedControlData[SetIndex] = pGDI->LocalMixerData.ControlInfo[i].Data;
SetIndex++;
}
}
/*
** Write the saved data
*/
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
pGDI->RegistryPathName,
SOUND_MIXER_SETTINGS_NAME,
REG_BINARY,
(PVOID)SavedControlData,
sizeof(SavedControlData));
}
VOID SoundWaveinLineChanged( PLOCAL_DEVICE_INFO pLDI,
UCHAR Code )
{
UCHAR Line;
PLOCAL_MIXER_DATA LocalMixerData;
dprintf4(("SoundWaveinLineChanged()"));
LocalMixerData = &((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->LocalMixerData;
// Find which device is in use and inspect the relevant MUX
switch (Code)
{
case SOUND_LINE_NOTIFY_WAVE:
Line = LocalMixerData->ControlInfo[ControlWaveInMux].Data.v[0].u ==
MUXINPUT_MIC ? DestWaveInSourceMic :
DestWaveInSourceAux1;
break;
case SOUND_LINE_NOTIFY_VOICE:
Line = LocalMixerData->ControlInfo[ControlVoiceInMux].Data.v[0].u ==
MUXINPUT_MIC ? DestVoiceInSourceMic :
DestVoiceInSourceAux1;
break;
}
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[Line]);
}
VOID SoundWaveoutLineChanged( PLOCAL_DEVICE_INFO pLDI,
UCHAR Code )
{
PLOCAL_MIXER_DATA LocalMixerData;
dprintf4(("SoundWaveoutLineChanged()"));
LocalMixerData = &((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->LocalMixerData;
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[DestLineoutSourceWaveout]);
}
/*
** NOTE - the initializations etc here depend on the restricted types
** of control supported by this device - if other types are used it must
** be changed
*/
NTSTATUS
SoundMixerInit(
PLOCAL_DEVICE_INFO pLDI,
PMIXER_CONTROL_DATA_ITEM SavedControlData,
BOOLEAN MixerSettingsFound
)
{
int i, SetIndex;
PLOCAL_MIXER_DATA LocalMixerData;
PGLOBAL_DEVICE_INFO pGDI;
PMIXER_INFO MixerInfo;
dprintf4(("SoundMixerInit()"));
pGDI = pLDI->pGlobalInfo;
MixerInfo = &pGDI->MixerInfo;
/*
** Init the generic mixer stuff first so we can use it
*/
SoundInitMixerInfo(&pGDI->MixerInfo,
HwGetLineFlags,
HwGetControl,
HwGetCombinedControl,
HwSetControl);
/*
** Set this device up with its mixer data
*/
pLDI->DeviceType = MIXER_DEVICE;
pLDI->DeviceSpecificData = (PVOID)MixerInfo;
/*
** Make sure everyone can find the mixer device
*/
{
PDEVICE_OBJECT pDO;
for (pDO = pGDI->DeviceObject[WaveInDevice]->DriverObject->DeviceObject;
pDO != NULL;
pDO = pDO->NextDevice) {
((PLOCAL_DEVICE_INFO)pDO->DeviceExtension)->MixerDevice = pLDI;
}
}
LocalMixerData = &pGDI->LocalMixerData;
/*
** Create control info
*/
for (i = 0, SetIndex = 0; i < MAXCONTROLS ; i++) {
/*
** Read limits
*/
if ((MixerControlInit[i].dwControlType & MIXERCONTROL_CT_UNITS_MASK) ==
MIXERCONTROL_CT_UNITS_SIGNED) {
pGDI->LocalMixerData.ControlInfo[i].Signed = TRUE;
pGDI->LocalMixerData.ControlInfo[i].Range.Min.s =
(SHORT)MixerControlInit[i].Bounds.lMinimum;
pGDI->LocalMixerData.ControlInfo[i].Range.Max.s =
(SHORT)MixerControlInit[i].Bounds.lMaximum;
} else {
if ((MixerControlInit[i].dwControlType & MIXERCONTROL_CT_UNITS_MASK) ==
MIXERCONTROL_CT_UNITS_BOOLEAN) {
pGDI->LocalMixerData.ControlInfo[i].Boolean = TRUE;
}
pGDI->LocalMixerData.ControlInfo[i].Range.Min.u =
(USHORT)MixerControlInit[i].Bounds.dwMinimum;
pGDI->LocalMixerData.ControlInfo[i].Range.Max.u =
(USHORT)MixerControlInit[i].Bounds.dwMaximum;
}
/*
** Remember if it's a mux
*/
if (MixerControlInit[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {
pGDI->LocalMixerData.ControlInfo[i].Mux = TRUE;
}
/*
** Only meters are not settable here
*/
if ((MixerControlInit[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) !=
MIXERCONTROL_CT_CLASS_METER)
{
pGDI->LocalMixerData.ControlInfo[i].SetIndex = SetIndex;
SoundInitDataItem(MixerInfo,
&pGDI->LocalMixerData.ControlNotification[SetIndex],
(USHORT)MM_MIXM_CONTROL_CHANGE,
(USHORT)i);
if (MixerSettingsFound) {
/*
** What if it's invalid?
*/
pGDI->LocalMixerData.ControlInfo[i].Data =
SavedControlData[SetIndex];
} else {
/*
** For us it's either Mute, a volume or a Mux.
**
** Muxes are assumed to be set to MUXINPUT_MIC as default
** Only one mute is set
**
** Volumes are set to a fixed value
**
** Nothing is muted
*/
switch (i) {
case ControlLineoutVolume:
case ControlLineoutAux1Volume:
case ControlLineoutWaveoutVolume:
case ControlLineoutMidioutVolume:
case ControlWaveInAux1Volume:
case ControlWaveInMicVolume:
case ControlVoiceInAux1Volume:
case ControlVoiceInMicVolume:
/*
** Half volume
*/
pGDI->LocalMixerData.ControlInfo[i].Data.v[0].u = 32767;
pGDI->LocalMixerData.ControlInfo[i].Data.v[1].u = 32767;
break;
case ControlWaveInMux:
case ControlVoiceInMux:
/*
** Microphone input
*/
pGDI->LocalMixerData.ControlInfo[i].Data.v[0].u = MUXINPUT_MIC;
break;
}
}
SetIndex++;
} else {
pGDI->LocalMixerData.ControlInfo[i].SetIndex = MIXER_SET_INDEX_INVALID;
}
}
ASSERTMSG("MAXSETTABLECONTROLS wrong!", SetIndex == MAXSETTABLECONTROLS);
/*
** Create line info
*/
for (i = 0; i < MAXLINES; i++) {
SoundInitDataItem(MixerInfo,
&pGDI->LocalMixerData.LineNotification[i],
(USHORT)MM_MIXM_LINE_CHANGE,
(USHORT)i);
}
/*
** Set up line notifications and volume control ids for non-mixer devices
*/
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveInDevice]->DeviceExtension,
SoundWaveinLineChanged);
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
SoundWaveoutLineChanged);
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
ControlLineoutWaveoutVolume);
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[LineInDevice]->DeviceExtension,
ControlLineoutAux1Volume);
/*
** Set the volume levels - this only affects the output for this card's
** initial settings (ie wave in not active).
*/
MixSetMasterVolume(pGDI, 0);
return STATUS_SUCCESS;
}
NTSTATUS
SoundMixerDumpConfiguration(
IN PLOCAL_DEVICE_INFO pLDI,
IN OUT PIRP pIrp,
IN PIO_STACK_LOCATION IrpStack
)
{
NTSTATUS Status;
PMIXER_INFO MixerInfo;
PGLOBAL_DEVICE_INFO pGDI;
ULONG Length;
struct {
MIXER_DD_CONFIGURATION_DATA Header;
MIXER_DD_LINE_CONFIGURATION_DATA LineData[MAXLINES];
MIXER_DD_CONTROL_CONFIGURATION_DATA ControlData[MAXCONTROLS];
MIXER_DD_CONTROL_LISTTEXT TextData[NUMBEROFTEXTITEMS];
} *OurConfigData;
pGDI = pLDI->pGlobalInfo;
MixerInfo = &pGDI->MixerInfo;
dprintf4(("SoundMixerDumpConfiguration()"));
/*
** Load and adapt the mixer configuration info
**
** Play safe and allocate the space since the kernel stacks are a limited
** size
*/
OurConfigData = ExAllocatePool(PagedPool, sizeof(*OurConfigData));
if (OurConfigData == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
/*
** Copy the data and initialize the rest
*/
OurConfigData->Header.cbSize = sizeof(*OurConfigData);
ASSERT(sizeof(OurConfigData->LineData) == sizeof(MixerLineInit));
ASSERT(sizeof(OurConfigData->ControlData) == sizeof(MixerControlInit));
ASSERT(sizeof(OurConfigData->TextData) == sizeof(MixerTextInit));
RtlCopyMemory(OurConfigData->LineData, MixerLineInit, sizeof(MixerLineInit));
RtlCopyMemory(OurConfigData->ControlData, MixerControlInit,
sizeof(MixerControlInit));
RtlCopyMemory(OurConfigData->TextData, MixerTextInit, sizeof(MixerTextInit));
OurConfigData->Header.NumberOfLines = MAXLINES;
OurConfigData->Header.NumberOfControls = MAXCONTROLS;
/*
** Create the Device caps
*/
OurConfigData->Header.DeviceCaps.wMid = MID_NEC;
OurConfigData->Header.DeviceCaps.wPid = PID_MIXER;
OurConfigData->Header.DeviceCaps.vDriverVersion = DRIVER_VERSION;
OurConfigData->Header.DeviceCaps.PnameStringId = SR_STR_DRIVER_MIXER;
OurConfigData->Header.DeviceCaps.fdwSupport = 0;
/*
** Compute the number of destinations
*/
{
int i;
for (i = 0; i < MAXLINES; i++) {
if (MixerLineInit[i].cConnections == 0) {
break;
}
}
OurConfigData->Header.DeviceCaps.cDestinations = i;
}
/*
** If this card is something other than a AD1848J, set new levels
*/
if (pGDI->Hw.CODECClass != CODEC_J_CLASS) {
OurConfigData->ControlData[ControlLineoutAux1Volume].Metrics.cSteps = 32;
OurConfigData->ControlData[ControlWaveInAux1Volume].Metrics.cSteps = 32;
OurConfigData->ControlData[ControlVoiceInAux1Volume].Metrics.cSteps = 32;
}
/*
** Set the text data offsets up
*/
{
PMIXER_DD_CONTROL_LISTTEXT pListText;
PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
int i;
for (pListText = &OurConfigData->TextData[NUMBEROFTEXTITEMS - 1],
pControlData = OurConfigData->ControlData,
i = 0;
i < NUMBEROFTEXTITEMS;
pListText--, i++)
{
pControlData[pListText->ControlId].TextDataOffset =
(PBYTE)pListText - (PBYTE)OurConfigData;
}
}
/*
** Note that having no synth means that we just set the synth line to
** disconnected when asked for the line information
*/
/*
** Copy data back to the application - don't copy anything if they
** ask for less than the basic information.
*/
Length =
min(sizeof(*OurConfigData),
IrpStack->Parameters.DeviceIoControl.OutputBufferLength);
if (Length < sizeof(*OurConfigData)) {
Status = STATUS_BUFFER_OVERFLOW;
} else {
Status = STATUS_SUCCESS;
}
pIrp->IoStatus.Information = Length;
RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer,
OurConfigData,
pIrp->IoStatus.Information);
ExFreePool(OurConfigData);
return STATUS_SUCCESS;
}
NTSTATUS
HwGetLineFlags(
PMIXER_INFO MixerInfo,
ULONG LineId,
ULONG Length,
PVOID pData
)
{
PGLOBAL_DEVICE_INFO pGDI;
PULONG fdwLine;
dprintf4(("HwGetLineFlags()")) ;
fdwLine = pData;
if (Length != sizeof(ULONG)) {
return STATUS_BUFFER_TOO_SMALL;
}
pGDI = CONTAINING_RECORD(MixerInfo, GLOBAL_DEVICE_INFO, MixerInfo);
/*
** Get default
*/
*fdwLine = MixerLineInit[LineId].cConnections == 0 ?
MIXERLINE_LINEF_SOURCE : 0;
/*
** The factors that affect this are
** - the mux settings
** - whether we have a synth
** - whether there is an output device playing
*/
switch (LineId) {
/*
** Muxes, line out and aux in -> line out are always available
*/
case DestWaveIn:
case DestVoiceIn:
case DestLineout:
case DestLineoutSourceAux1:
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
break;
/*
** Wave out deemed 'active' when open
*/
case DestLineoutSourceWaveout:
if (pGDI->DeviceInUse == WaveOutDevice) {
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
}
break;
/*
** Midi out deemed 'active' when open
*/
case DestLineoutSourceMidiout:
*fdwLine |= MIXERLINE_LINEF_DISCONNECTED;
break;
/*
** wave in from aux1 active when selected and not low priority
*/
case DestWaveInSourceAux1:
if (pGDI->LocalMixerData.ControlInfo[ControlWaveInMux].Data.v[0].u !=
MUXINPUT_MIC &&
pGDI->DeviceInUse == WaveInDevice &&
(pGDI->WaveInfo.LowPriorityHandle == NULL ||
pGDI->WaveInfo.LowPrioritySaved)) {
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
}
break;
/*
** wave in from mic active when selected and not low priority
*/
case DestWaveInSourceMic:
if (pGDI->LocalMixerData.ControlInfo[ControlWaveInMux].Data.v[0].u ==
MUXINPUT_MIC &&
pGDI->DeviceInUse == WaveInDevice &&
(pGDI->WaveInfo.LowPriorityHandle == NULL ||
pGDI->WaveInfo.LowPrioritySaved)) {
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
}
break;
/*
** voice in from aux active when selected and low priority active
*/
case DestVoiceInSourceAux1:
if (pGDI->LocalMixerData.ControlInfo[ControlVoiceInMux].Data.v[0].u !=
MUXINPUT_MIC &&
pGDI->DeviceInUse == WaveInDevice &&
(pGDI->WaveInfo.LowPriorityHandle != NULL &&
!pGDI->WaveInfo.LowPrioritySaved)) {
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
}
break;
/*
** voice in from mic active when selected and low priority active
*/
case DestVoiceInSourceMic:
if (pGDI->LocalMixerData.ControlInfo[ControlVoiceInMux].Data.v[0].u ==
MUXINPUT_MIC &&
pGDI->DeviceInUse == WaveInDevice &&
(pGDI->WaveInfo.LowPriorityHandle != NULL &&
!pGDI->WaveInfo.LowPrioritySaved)) {
*fdwLine |= MIXERLINE_LINEF_ACTIVE;
}
break;
default:
return STATUS_INVALID_PARAMETER; // Invalid
}
return STATUS_SUCCESS;
}
NTSTATUS
HwGetCombinedControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
)
/*++
Routine Description
This is an INTERNAL ONLY routine so no validation is required.
--*/
{
PULONG Vol;
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
PGLOBAL_DEVICE_INFO pGDI;
dprintf4(("HwGetCombinedControl()"));
pGDI = CONTAINING_RECORD(MixerInfo, GLOBAL_DEVICE_INFO, MixerInfo);
ControlInfo = pGDI->LocalMixerData.ControlInfo;
Vol = ControlData;
/* This is ONLY allowed for midi output */
ASSERTMSG("Invalid control for HwGetCombinedControl",
ControlId == ControlLineoutMidioutVolume &&
DataLength == sizeof(ULONG) * 2);
/* Combine the volume for both left and right */
if (ControlInfo[ControlLineoutMute].Data.v[0].u != 0 ||
ControlInfo[ControlLineoutMidioutMute].Data.v[0].u != 0) {
Vol[0] = 0;
Vol[1] = 0;
} else {
Vol[0] = ((ULONG)ControlInfo[ControlLineoutVolume].Data.v[0].u *
(ULONG)ControlInfo[ControlLineoutMidioutVolume].Data.v[0].u)
>> 16;
Vol[1] = ((ULONG)ControlInfo[ControlLineoutVolume].Data.v[1].u *
(ULONG)ControlInfo[ControlLineoutMidioutVolume].Data.v[1].u)
>> 16;
}
return STATUS_SUCCESS;
}
NTSTATUS
HwGetControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
)
{
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
PGLOBAL_DEVICE_INFO pGDI;
LONG Values[2];
dprintf4(("HwGetControl()"));
/*
** Validate control ID
*/
if (ControlId > MAXCONTROLS) {
dprintf4(("return -1"));
return STATUS_INVALID_PARAMETER;
}
/*
** Establish pointers to our structures
*/
pGDI = CONTAINING_RECORD(MixerInfo, GLOBAL_DEVICE_INFO, MixerInfo);
ControlInfo = &pGDI->LocalMixerData.ControlInfo[ControlId];
/*
** Validate data length and values
*/
switch (DataLength) {
case sizeof(LONG):
break;
case sizeof(LONG) * 2:
break;
default:
dprintf4(("retunr 2"));
return STATUS_BUFFER_TOO_SMALL;
}
/*
** Pull out the data
*/
if (ControlInfo->SetIndex == MIXER_SET_INDEX_INVALID) {
/*
** Must be a peak meter - see if it's valid to query it
*/
PWAVE_INFO WaveInfo;
BOOLEAN ComputePeak;
ComputePeak = FALSE;
/*
** Set defaults
*/
Values[0] = 0;
Values[1] = 0;
WaveInfo = &pGDI->WaveInfo;
switch (ControlId) {
case ControlLineoutWaveoutPeak:
if (pGDI->DeviceInUse == WaveOutDevice) {
ComputePeak = TRUE;
}
break;
case ControlWaveInAux1Peak:
case ControlWaveInMicPeak:
if (pGDI->DeviceInUse != WaveInDevice) {
break;
}
if (WaveInfo->LowPriorityHandle != NULL &&
!WaveInfo->LowPrioritySaved) {
break;
}
if (pGDI->LocalMixerData.ControlInfo[ControlWaveInMux].Data.v[0].u ==
MUXINPUT_MIC) {
if (ControlId == ControlWaveInAux1Peak) {
break;
}
} else {
if (ControlId == ControlWaveInMicPeak) {
break;
}
}
ComputePeak = TRUE;
break;
case ControlVoiceInAux1Peak:
case ControlVoiceInMicPeak:
if (pGDI->DeviceInUse != WaveInDevice) {
break;
}
if (WaveInfo->LowPriorityHandle == NULL ||
WaveInfo->LowPrioritySaved) {
break;
}
if (pGDI->LocalMixerData.ControlInfo[ControlVoiceInMux].Data.v[0].u ==
MUXINPUT_MIC) {
if (ControlId == ControlVoiceInAux1Peak) {
break;
}
} else {
if (ControlId == ControlVoiceInMicPeak) {
break;
}
}
ComputePeak = TRUE;
break;
default:
ASSERTMSG("Invalid control id", FALSE);
break;
}
if (ComputePeak) {
SoundPeakMeter(WaveInfo, Values);
}
/*
** Note that we should round these values to the min/max
** expected in the control but in this case these values
** are always within range
*/
} else {
ASSERTMSG("Set index out of range",
ControlInfo->SetIndex < MAXSETTABLECONTROLS);
if (ControlInfo->Mux) {
Values[ControlInfo->Data.v[0].s] = (LONG)ControlInfo->Range.Max.s;
Values[1 - ControlInfo->Data.v[0].s] = (LONG)ControlInfo->Range.Min.s;
} else {
if (ControlInfo->Signed) {
Values[0] = (LONG)ControlInfo->Data.v[0].s;
Values[1] = (LONG)ControlInfo->Data.v[1].s;
} else {
Values[0] = (LONG)(ULONG)ControlInfo->Data.v[0].u;
Values[1] = (LONG)(ULONG)ControlInfo->Data.v[1].u;
}
}
}
/*
** If only 1 channel was asked for then munge the data accordingly
*/
if (DataLength == sizeof(LONG)) {
switch (MixerControlInit[ControlId].dwControlType &
MIXERCONTROL_CT_UNITS_MASK) {
case MIXERCONTROL_CT_UNITS_BOOLEAN:
Values[0] = Values[0] != 0 || Values[1] != 0;
break ;
case MIXERCONTROL_CT_UNITS_SIGNED:
/*
** Assumes signed values...
*/
if (absval(Values[1]) > absval(Values[0])) {
Values[0] = Values[1];
}
break ;
case MIXERCONTROL_CT_UNITS_UNSIGNED:
case MIXERCONTROL_CT_UNITS_DECIBELS:
case MIXERCONTROL_CT_UNITS_PERCENT:
/*
** Assumes unsigned values...
*/
if ((ULONG)Values[0] < (ULONG)Values[1]) {
Values[0] = Values[1];
}
break ;
}
/*
** Copy the single value back
*/
} else {
((PLONG)ControlData)[1] = Values[1];
}
*(PLONG)ControlData = Values[0];
dprintf4(("retunr 3"));
return STATUS_SUCCESS;
}
VOID
SoundMixerChangedMuxItem(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId,
int Subitem
)
{
int i;
dprintf4(("SoundMixerChangeMuxItem()"));
for (i = 0; i < NUMBEROFTEXTITEMS; i++) {
if (MixerTextInit[i].ControlId == ControlId) {
SoundMixerChangedItem(
&pGDI->MixerInfo,
&pGDI->LocalMixerData.LineNotification[
MixerTextInit[i + Subitem].dwParam1]);
break;
}
}
}
NTSTATUS
HwSetControl(
PMIXER_INFO MixerInfo,
ULONG ControlId,
ULONG DataLength,
PVOID ControlData
)
{
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
int i;
BOOLEAN Changed;
LONG Values[2];
BOOLEAN MixerSetResult;
PGLOBAL_DEVICE_INFO pGDI;
dprintf4(("HwSetControl() Start"));
pGDI = CONTAINING_RECORD(MixerInfo, GLOBAL_DEVICE_INFO, MixerInfo);
/*
** Validate control ID
*/
if (ControlId > MAXCONTROLS) {
return STATUS_INVALID_PARAMETER;
}
/*
** Establish pointers to our structures
*/
ControlInfo = &pGDI->LocalMixerData.ControlInfo[ControlId];
ASSERTMSG("Set index out of range",
ControlInfo->SetIndex < MAXSETTABLECONTROLS ||
ControlInfo->SetIndex == MIXER_SET_INDEX_INVALID);
/*
** Validate data length and values
*/
switch (DataLength) {
case sizeof(LONG):
Values[0] = *(PLONG)ControlData;
Values[1] = Values[0];
break;
case sizeof(LONG) * 2:
Values[0] = *(PLONG)ControlData;
Values[1] = ((PLONG)ControlData)[1];
break;
default:
return STATUS_BUFFER_TOO_SMALL;
}
/*
** Apparently Boolean values can be anything
*/
if (ControlInfo->Boolean) {
Values[0] = (ULONG)!!Values[0];
Values[1] = (ULONG)!!Values[1];
}
/*
** Check the item ranges and assign the values. Note that
** this stuff only works for <= 2 channels/items.
*/
for (i = 0, Changed = FALSE; i < 2; i++) {
if (ControlInfo->Signed) {
if (Values[i] < (LONG)ControlInfo->Range.Min.s ||
Values[i] > (LONG)ControlInfo->Range.Max.s) {
return STATUS_INVALID_PARAMETER;
} else {
if ((SHORT)((PLONG)Values)[i] != ControlInfo->Data.v[i].s) {
Changed = TRUE;
ControlInfo->Data.v[i].s = (SHORT)((PLONG)Values)[i];
}
}
} else {
if ((((PULONG)Values)[i] < (ULONG)ControlInfo->Range.Min.u ||
((PULONG)Values)[i] > (ULONG)ControlInfo->Range.Max.u)) {
return STATUS_INVALID_PARAMETER;
} else {
/*
** Do muxes slightly differently so we don't store a big
** array of n - 1 zeros and 1 one
*/
if (ControlInfo->Mux) {
if (Values[i] != (LONG)ControlInfo->Range.Min.s) {
/*
** 'On' - only turn ONE on
*/
if ((USHORT)i != ControlInfo->Data.v[0].u) {
Changed = TRUE;
/*
** Notify the one turned off and the
** one turned on
*/
SoundMixerChangedMuxItem(
pGDI,
ControlId,
ControlInfo->Data.v[0].u);
ControlInfo->Data.v[0].u = (USHORT)i;
SoundMixerChangedMuxItem(
pGDI,
ControlId,
ControlInfo->Data.v[0].u);
}
/*
** Mux ONLY changes ONE thing
*/
break;
}
} else {
if ((USHORT)((PULONG)Values)[i] != ControlInfo->Data.v[i].u) {
Changed = TRUE;
ControlInfo->Data.v[i].u = (USHORT)((PULONG)Values)[i];
}
}
}
}
}
if (!Changed) {
return STATUS_SUCCESS;
}
/*
** Notify the Win32 Midi driver of changes
*/
//if (ControlId == ControlLineoutMidioutVolume) {
//
// SoundNotifySynth(pGDI);
//}
/*
** Now pass on to the relevant handler which must :
** Set the hardware
** Determine if there is a real change so it can generate notifications
** Generate related changes (eg mux handling)
*/
switch (ControlId) {
case ControlWaveInMux:
case ControlVoiceInMux:
case ControlWaveInAux1Volume:
case ControlWaveInMicVolume:
case ControlVoiceInAux1Volume:
case ControlVoiceInMicVolume:
MixerSetResult = MixSetADCHardware(pGDI, ControlId);
dprintf4(("Call MixSetADCHardware()"));
break;
case ControlLineoutAux1Volume:
case ControlLineoutWaveoutVolume:
MixerSetResult = MixSetVolume(pGDI, ControlId);
dprintf4(("Call MixSetVolume()"));
break;
case ControlLineoutVolume:
MixerSetResult = MixSetMasterVolume(pGDI, ControlId);
dprintf4(("Call MixSetMasterVolume()"));
//SoundNotifySynth(pGDI);
break;
case ControlLineoutMute:
MixerSetResult = MixSetMute(pGDI, ControlId);
dprintf4(("Call MixSetMute()"));
//SoundNotifySynth(pGDI);
break;
case ControlLineoutAux1Mute:
case ControlLineoutWaveoutMute:
MixerSetResult = MixSetMute(pGDI, ControlId);
dprintf4(("Call MixSetMute()"));
break;
case ControlLineoutMidioutVolume:
case ControlLineoutMidioutMute:
//SoundNotifySynth(pGDI);
break;
case ControlLineoutWaveoutPeak:
case ControlWaveInAux1Peak:
case ControlWaveInMicPeak:
case ControlVoiceInAux1Peak:
case ControlVoiceInMicPeak:
MixerSetResult = FALSE;
dprintf4(("MixerSetResult = FALSE"));
break;
}
if (MixerSetResult) {
SoundMixerChangedItem(MixerInfo,
&pGDI->LocalMixerData.ControlNotification[
ControlInfo->SetIndex]);
return STATUS_SUCCESS;
} else {
return STATUS_INVALID_PARAMETER;
}
}