📄 common.cpp
字号:
// No mask? Could happen when you try to prg. left channel of a
// mono volume.
//
if (!wMask)
return STATUS_SUCCESS;
//
// Check to see if we are only writing specific bits. If so, we want
// to leave some bits in the register alone.
//
if (wMask != 0xffff)
{
//
// Read the current register contents.
//
ntStatus = ReadCodecRegister (reg, &TempData);
if (!NT_SUCCESS (ntStatus))
{
DOUT (DBG_ERROR, ("WriteCodecRegiser read for mask failed"));
return ntStatus;
}
//
// Do the masking.
//
TempData &= ~wMask;
TempData |= (wMask & wData);
}
else
{
TempData = wData;
}
//
// Grab the codec access semiphore.
//
ntStatus = AcquireCodecSemiphore ();
if (!NT_SUCCESS (ntStatus))
{
DOUT (DBG_ERROR, ("WriteCodecRegister failed for register %s",
reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" : "REG_INVALID"));
return ntStatus;
}
//
// Write the data.
//
WRITE_PORT_USHORT (m_pCodecBase + reg, TempData);
//
// Update cache.
//
m_stAC97Registers[reg].wCache = TempData;
DOUT (DBG_REGS, ("AC97WRITE: %s -> 0x%04x",
reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
"REG_INVALID", TempData));
return STATUS_SUCCESS;
}
/*****************************************************************************
* CAdapterCommon::PrimaryCodecReady
*****************************************************************************
* Checks whether the primary codec is present and ready. This may take
* awhile if we are bringing it up from a cold reset so give it a second
* before giving up.
*/
NTSTATUS CAdapterCommon::PrimaryCodecReady (void)
{
PAGED_CODE ();
DOUT (DBG_PRINT, ("[CAdapterCommon::PrimaryCodecReady]"));
//
// Enable the AC link and raise the reset line.
//
DWORD dwRegValue = ReadBMControlRegister32 (GLOB_CNT);
// If someone enabled GPI Interrupt Enable, then he hopefully handles that
// too.
dwRegValue = (dwRegValue | GLOB_CNT_COLD) & ~(GLOB_CNT_ACLOFF | GLOB_CNT_PRIE);
WriteBMControlRegister (GLOB_CNT, dwRegValue);
//
// Wait for the Codec to be ready.
//
ULONG WaitCycles = 200;
LARGE_INTEGER WaitTime = RtlConvertLongToLargeInteger (-50000); // wait 5000us (5ms) relative
do
{
if (READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA)) &
GLOB_STA_PCR)
{
return STATUS_SUCCESS;
}
KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
} while (WaitCycles--);
DOUT (DBG_ERROR, ("PrimaryCodecReady timed out!"));
return STATUS_IO_TIMEOUT;
}
/*****************************************************************************
* CAdapterCommon::PowerUpCodec
*****************************************************************************
* Sets the Codec to the highest power state and waits until the Codec reports
* that the power state is reached.
*/
NTSTATUS CAdapterCommon::PowerUpCodec (void)
{
PAGED_CODE ();
WORD wCodecReg;
NTSTATUS ntStatus;
DOUT (DBG_PRINT, ("[CAdapterCommon::PowerUpCodec]"));
//
// Power up the Codec.
//
WriteCodecRegister (AC97REG_POWERDOWN, 0x00, -1);
//
// Wait for the Codec to be powered up.
//
ULONG WaitCycles = 200;
LARGE_INTEGER WaitTime = RtlConvertLongToLargeInteger (-50000); // wait 5000us (5ms) relative
do
{
//
// Read the power management register.
//
ntStatus = ReadCodecRegister (AC97REG_POWERDOWN, &wCodecReg);
if (!NT_SUCCESS (ntStatus))
{
wCodecReg = 0; // Will cause an error.
break;
}
//
// Check the power state. Should be ready.
//
if ((wCodecReg & 0x0f) == 0x0f)
break;
//
// Let's wait a little, 5ms and then try again.
//
KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
} while (WaitCycles--);
// Check if we timed out.
if ((wCodecReg & 0x0f) != 0x0f)
{
DOUT (DBG_ERROR, ("PowerUpCodec timed out. CoDec not powered up."));
ntStatus = STATUS_DEVICE_NOT_READY;
}
return ntStatus;
}
/*****************************************************************************
* CAdapterCommon::ProgramSampleRate
*****************************************************************************
* Programs the sample rate. If the rate cannot be programmed, the routine
* restores the register and returns STATUS_UNSUCCESSFUL.
* We don't handle double rate sample rates here, because the Intel ICH con-
* troller cannot serve CoDecs with double rate or surround sound. If you want
* to modify this driver for another AC97 controller, then you might want to
* change this function too.
*/
STDMETHODIMP_(NTSTATUS) CAdapterCommon::ProgramSampleRate
(
IN AC97Register Register,
IN DWORD dwSampleRate
)
{
PAGED_CODE ();
WORD wOldRateReg, wCodecReg;
NTSTATUS ntStatus;
DOUT (DBG_PRINT, ("[CAdapterCommon::ProgramSampleRate]"));
//
// Check if we support variable sample rate.
//
switch(Register)
{
case AC97REG_MIC_SAMPLERATE:
//
// Variable sample rate supported?
//
if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
{
// Range supported?
if (dwSampleRate > 48000ul)
{
// Not possible.
DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
return STATUS_NOT_SUPPORTED;
}
}
else
{
// Only 48000KHz possible.
if (dwSampleRate != 48000ul)
{
DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
break;
case AC97REG_FRONT_SAMPLERATE:
case AC97REG_SURROUND_SAMPLERATE:
case AC97REG_LFE_SAMPLERATE:
case AC97REG_RECORD_SAMPLERATE:
//
// Variable sample rate supported?
//
if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
{
//
// Check range supported
//
if (dwSampleRate > 48000ul)
{
DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
return STATUS_NOT_SUPPORTED;
}
}
else
{
// Only 48KHz possible.
if (dwSampleRate != 48000ul)
{
DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
return STATUS_NOT_SUPPORTED;
}
return STATUS_SUCCESS;
}
break;
default:
DOUT (DBG_ERROR, ("Invalid sample rate register!"));
return STATUS_UNSUCCESSFUL;
}
//
// Save the old sample rate register.
//
ntStatus = ReadCodecRegister (Register, &wOldRateReg);
if (!NT_SUCCESS (ntStatus))
return ntStatus;
//
// program the rate.
//
ntStatus = WriteCodecRegister (Register, (WORD)dwSampleRate, -1);
if (!NT_SUCCESS (ntStatus))
{
DOUT (DBG_ERROR, ("Cannot program sample rate."));
return ntStatus;
}
//
// Read it back.
//
ntStatus = ReadCodecRegister (Register, &wCodecReg);
if (!NT_SUCCESS (ntStatus))
{
DOUT (DBG_ERROR, ("Cannot read sample rate."));
return ntStatus;
}
//
// Validate.
//
if (wCodecReg != dwSampleRate)
{
//
// restore sample rate and ctrl register.
//
WriteCodecRegister (Register, wOldRateReg, -1);
DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
return STATUS_NOT_SUPPORTED;
}
DOUT (DBG_VSR, ("Samplerate changed to %d.", dwSampleRate));
return STATUS_SUCCESS;
}
/*****************************************************************************
* CAdapterCommon::PowerChangeState
*****************************************************************************
* Change power state for the device. We handle the codec, PowerChangeNotify
* in the wave miniport handles the DMA registers.
*/
STDMETHODIMP_(void) CAdapterCommon::PowerChangeState
(
IN POWER_STATE NewState
)
{
PAGED_CODE ();
NTSTATUS ntStatus = STATUS_SUCCESS;
DOUT (DBG_PRINT, ("[CAdapterCommon::PowerChangeNotify]"));
//
// Check to see if this is the current power state.
//
if (NewState.DeviceState == m_PowerState)
{
DOUT (DBG_POWER, ("New device state equals old state."));
return;
}
//
// Check the new device state.
//
if ((NewState.DeviceState < PowerDeviceD0) ||
(NewState.DeviceState > PowerDeviceD3))
{
DOUT (DBG_ERROR, ("Unknown device state: D%d.",
(ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
return;
}
DOUT (DBG_POWER, ("Changing state to D%d.", (ULONG)NewState.DeviceState -
(ULONG)PowerDeviceD0));
//
// Switch on new state.
//
switch (NewState.DeviceState)
{
case PowerDeviceD0:
//
// If we are coming from D2 or D3 we have to restore the registers cause
// there might have been a power loss.
//
if ((m_PowerState == PowerDeviceD3) || (m_PowerState == PowerDeviceD2))
{
//
// Reset AD3 to indicate that we are now awake.
// Because the system has only one power irp at a time, we are sure
// that the modem driver doesn't get called while we are restoring
// power.
//
WriteBMControlRegister (GLOB_STA,
ReadBMControlRegister32 (GLOB_STA) & ~GLOB_STA_AD3);
//
// Restore codec registers.
//
ntStatus = RestoreCodecRegisters ();
}
else // We are coming from power state D1
{
ntStatus = PowerUpCodec ();
}
// Print error code.
if (!NT_SUCCESS (ntStatus))
{
DOUT (DBG_ERROR, ("PowerChangeState failed to restore the codec."));
}
break;
case PowerDeviceD1:
//
// This sleep state is the lowest latency sleep state with respect
// to the latency time required to return to D0. If the
// driver is not being used an inactivity timer in portcls will
// place the driver in this state after a timeout period
// controllable via the registry.
//
// Let's power down the DAC/ADC's and analog mixer.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -