📄 ac97.c
字号:
/**************** Audio support utilities ******************/
void Ac97SwRestoreDefaultsAudio (Ac97ContextT* ctxP)
// Only restores the audio "current values" writeable record to the
// default settings.
// To place them into hardware, Ac97HwReconfigAudio() must be used.
{
INT i;
for (i = 0; i < AC97_NUM_MIXER_REGS; i++ )
{
if ( AC97_MR_USAGE_AUDIO ==
(*ctxP->mixerRegsDfltValsUsageP)[i].mixerRegUsage)
{
ctxP->mixerRegsCurrVals[i] =
(*ctxP->mixerRegsDfltValsUsageP)[i].mixerRegDefaultVal;
}
}
} // Ac97SwRestoreDefaultsAudio ()
UINT32 Ac97HwReconfigAudio (Ac97ContextT* ctxP)
{
// Does not permit a change in the resources used (controller comms, codec)
// Does not change most recently set values of writeable regs
// Enable all supported audio codec subsystems
// Verify readiness of all supported audio codec subsystems
// Write out all values in "current" Audio registers record to the codec
// Set audio state variable flag fields. @@@ What are these?
// Stop at first error.
UINT32 status;
UINT32 desiredSetting;
UINT32 checkedSetting;
INT i = 0;
// First, make sure that all audio subsystems are enabled and ready.
status = Ac97PowerOnAudioSubsystems (ctxP);
// Now, write all audio settings to the codec and check them.
// Try all mixer registers
for (i = 0; (i < AC97_NUM_MIXER_REGS) && !status ; i++ )
{
// Touch only if standard audio writeable registers
if ( AC97_MR_USAGE_AUDIO ==
(*ctxP->mixerRegsDfltValsUsageP)[i].mixerRegUsage)
{
// Write existing intended settings as found in SW record.
desiredSetting = ctxP->mixerRegsCurrVals[i];
status = XsAc97CtrlWriteCodecReg
(ctxP->audioIdForController,
i * 2, // mixer regs step by 2
desiredSetting);
// Now check that the value was accepted
if (!status)
{
status = XsAc97CtrlReadCodecReg
(ctxP->audioIdForController,
i * 2, // mixer regs step by 2
&checkedSetting);
}
if (!status && (checkedSetting != desiredSetting))
{
// Failed compare means that at least one bit didn't set or clr
status = ERR_T_NOBITSET;
}
} // if AC97_MR_USAGE_AUDIO usage
} // for all mixer registers
if (!status)
{
ctxP->audioCodecReady = TRUE;
ctxP->audioCodecInitialized = TRUE;
}
else
{
ctxP->audioCodecReady = FALSE;
ctxP->audioCodecInitialized = FALSE;
// First param is ID # of problem register. Becomes -2 if the failure
// was during the subsystem power on subroutine.
LOGERROR (ctxP->loggedError, ERR_L_AC97,
ERR_S_AC97_HWRCNFG_AUD, status, (i-1)*2, 0, 0)
}
return (status);
} // Ac97HwReconfigAudio ()
// Runs the power-on state machine from PR1..4 previously being set
// Also makes sure that all extended audio subsystems are enabled and ready.
// Assumes that basic communication with the codec is established.
UINT32 Ac97PowerOnAudioSubsystems (Ac97ContextT* ctxP)
{
// Not supporting power modes for initial release, so only make sure that
// all subsystems supported by the target codec are ready. State machine
// implementation will be needed when power modes are supported.
UINT32 status;
UINT32 ac97MrPowerdownCtrlStatTmp;
INT msTimeout = AC97_AUD_RDY_FROM_COLD_TOUT_MS;
INT errLoc = 1; // Default is error from subroutine
// DEBUG
INT commErrs = 0;
// Return timeout error if subsystem readiness fails after n msec.
// Get Powerdown status. For this preliminary implementation, all
// subsystems should be enabled and ready.
status = XsAc97CtrlReadCodecReg ( ctxP->audioIdForController,
AC97_MR_POWERDOWN_CTRL_STAT,
&ac97MrPowerdownCtrlStatTmp);
// DEBUG @@@
// Count comm errors rather than stopping for them.
// Keep trying until all subsystems ready; stop on comm error or timeout
while ( /* @@@ !status
&& */(ac97MrPowerdownCtrlStatTmp
!= ctxP->mixerRegsSpecialMasksP->mr0x26EaAudioReadyVal)
&& msTimeout)
{
//@@@ DEBUG
DM_WaitMs (10);
msTimeout--;
status = XsAc97CtrlReadCodecReg ( ctxP->audioIdForController,
AC97_MR_POWERDOWN_CTRL_STAT,
&ac97MrPowerdownCtrlStatTmp);
// DEBUG @@@
if (status)
{
commErrs++;
}
}
// DEBUG @@@
// LOGERROR (ctxP->loggedError, ERR_L_AC97,
// ERR_S_AC97_PWR_ON_AUD_SUB, 0, 0, msTimeout, commErrs)
if (!status && !msTimeout)
{
// No comm errors, but we timed out waiting for the subsystems
// There are lots of timeouts possible while powering up. The
// identification of which type is made by tracing the error log
// and, in this case, if the first parameter is 2 instead of 1.
status = ERR_T_TIMEOUT;
errLoc = 2; // Timeout waiting for readiness
}
if (status)
{
LOGERROR (ctxP->loggedError, ERR_L_AC97,
ERR_S_AC97_PWR_ON_AUD_SUB, status, errLoc, 0, 0)
}
return (status);
} // Ac97PowerOnAudioSubsystems ()
UINT32 Ac97ShutdownAudioSubsystems (Ac97ContextT* ctxP)
{
// Shut down audio subsystems, but leave the AC link and other global
// systems running.
// Max shut down of audio systems without going into warm or cold reset.
// Shut down AC97 audio services provided by controller and main
// processor GPIOs. This includes unregistering AC97 and GPIO interrupts,
// returning descriptors and other allocated memory, setting the context
// flags to reflect the state, returning GPIO channels, etc.
// Does not change local record of codec settings, nor does it change
// settings in the mixer registers other than to shut down the targeted
// audio subsystems.
// Not supporting power modes for initial release, so stub actual power
// controls.
// @@@Stub: still need to release buffers and clean up GPIO
return (ERR_NONE);
} // Ac97ShutdownAudioSubsystems ()
/**************** Modem support utilities: stubs only ******************/
void Ac97SwRestoreDefaultsModem (Ac97ContextT* ctxP)
// Only restores the modem "current values" record to the default settings.
// To place them into hardware, Ac97HwReconfigModem() must be used.
{
// @@@Stub
} // Ac97SwRestoreDefaultsModem()
UINT32 Ac97HwReconfigModem (Ac97ContextT* ctxP) // Not implemented; stub only
{
// Does not permit a change in the resources used (controller comms, codec)
// Does not change most recently set values of
// Verify codec readiness (not initial setup, can't assume this)
// Enable all modem codec subsystems
// Verify modem codec subsystem readiness
// Set modem state variable flag fields.
// Return timeout error if subsystem readiness fails after n msec.
// @@@Stub
return (ERR_NONE);
} // Ac97HwReconfigModem()
UINT32 Ac97ShutdownModemSubsystems (Ac97ContextT* ctxP) // Not implemented; stub only
{
// Shut down modem subsystems, but leave the AC link and other global
// systems running.
// Shut down AC97 modem services provided by controller and main
// processor GPIOs. This includes unregistering AC97 and GPIO interrupts,
// returning descriptors and other allocated memory, setting the context
// flags to reflect the state, returning GPIO channels, etc.
// Does not change local record of codec settings, nor does it change
// settings in the mixer registers other than to shut down the targeted
// modem subsystems.
// @@@Stub
return (ERR_NONE);
} // Ac97ShutdownModemSubsystems()
/**************** General AC97 codec support utilities ******************/
// Note: The compiler seems to truncate the parameter to a byte because
// of the enum type. This limits the effectiveness of range-checking.
// @@@ Consider changing the parameter to an int.
/*
UINT32 Ac97CheckRegId (AC97MixerRegisterIdT registerIdToCheck)
{
UINT32 status = ERR_NONE;
// Register must be in range and also even. No odd registers supported
// by the spec.
if ( (registerIdToCheck < 0 ) ||
(registerIdToCheck > AC97_MR_MAX)||
(registerIdToCheck & 1) )
{
status = ERR_T_ILLPARAM;
}
return (status);
} // Ac97CheckRegId ()
*/
/*
*******************************************************************************
*******************************************************************************
Mixer Register Access functions
*******************************************************************************
*******************************************************************************
*/
UINT32 Ac97GetVendorIDandRev (Ac97ContextT* ctxP,
PCHAR vendorIdStringP,
PINT vendorRevNumberP)
{
// Provides the vendor string and rev number info found in
// mixer regs 0x7C + 0x7E
// Some codecs provide duplicate or additional information elsewhere, but
// this is the information from the standard location
UINT32 status;
UINT32 tmpMr7C;
UINT32 tmpMr7E;
// Get contents of Vendor ID 1 Mixer Register. Use Audio Codec
// selector for convenience.
status = XsAc97CtrlReadCodecReg (ctxP->audioIdForController,
AC97_MR_VENDOR_ID1,
&tmpMr7C);
// Now get info from Vendor ID 2 reg. Don't differentiate error locations
// if problem.
if (!status)
{
status = XsAc97CtrlReadCodecReg (ctxP->audioIdForController,
AC97_MR_VENDOR_ID2,
&tmpMr7E);
}
if (status)
{
LOGERROR (ctxP->loggedError, ERR_L_AC97,
ERR_S_AC97_GET_MR_VENDOR_ID, status, 0, 0, 0)
}
else
{
*vendorIdStringP++ = (CHAR) (tmpMr7C >> 8) & 0xFF; // first char of ID
*vendorIdStringP++ = (CHAR) tmpMr7C & 0xFF;
*vendorIdStringP++ = (CHAR) (tmpMr7E >> 8) & 0xFF;
*vendorIdStringP = (CHAR) '\0';
*vendorRevNumberP = (INT) tmpMr7E & 0xFF;
}
return (status);
} // Ac97GetVendorIDandRev ()
UINT32 Ac97GetAnyMixerRegister (Ac97ContextT* ctxP,
AC97MixerRegisterIdT targetReg,
PUINT16 curRegValueP)
{
UINT32 status ;
UINT32 regValTmp;
// Assume that there is no real difference between audio and modem
// interface mappings in AC97 controller. Just use the audio Id.
// If there's really a difference, this function becomes more complex.
status = XsAc97CtrlReadCodecReg (ctxP->audioIdForController,
targetReg,
®ValTmp);
if (status)
{
LOGERROR (ctxP->loggedError, ERR_L_AC97,
ERR_S_AC97_GET_ANY_MIX_REG, status, targetReg, 0, 0)
}
else
{
// Really only 16 bits in a mixer register, although the HW interface
// returns 32 with upper 16 undefined.
*curRegValueP = (UINT16) (regValTmp & 0xFFFF);
// Record actual value from mixer register.
// Divide by two for index because only even registers are used,
// and structures assume that.
ctxP->mixerRegsCurrVals[targetReg/2] = *curRegValueP;
}
return (status);
} // Ac97GetAnyMixerRegister ()
// This is a low-level routine. No read-validation of write. Such error
// checking is left to the calling routine.
// Universal access: "back door": Use with extreme caution!
/*
UINT32 Ac97SetAnyMixerRegister (Ac97ContextT* ctxP,
AC97MixerRegisterIdT targetReg,
UINT16 newValue)
{
UINT32 status ;
// Assume that there is no real difference between audio and modem
// interface mappings in AC97 controller. Just use the audio Id.
// If there's really a difference, this function becomes more complex.
status = XsAc97CtrlWriteCodecReg (ctxP->audioIdForController,
targetReg,
newValue);
if (status)
{
LOGERROR (ctxP->loggedError, ERR_L_AC97,
ERR_S_AC97_SET_ANY_MIX_REG, status, targetReg, 0, 0)
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Err in Ac97SetAnyMixerRegister: %08x, reg %02X",status,targetReg);
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -