📄 xsac97ctrl.c
字号:
if (status != ERR_NONE)
{
PrintfUartDef("!!!!Error Cold reset AC97\r\n");
status = ERR_T_SW_INTERNAL;
}
else
PrintfUartDef("AC97 Cold reset OK ....\r\n");
// Note: this system has only one codec. For systems with a primary and
// secondary device, the identity of a device that did not properly
// reset could be ascertained at this point.
}
//must delay, to let controller settle
Util_DelayMs(500);
if (status)
{
if ((ERR_T_NOBITSET != status) && (ERR_T_TIMEOUT != status))
{
// Other errors indicate a bad parameter, failure to clear any
// existing handler by the interrupt controller driver, or
// violation of the assumption that the AC'97 is unused by a
// debugger. All are essentially software errors.
// The error log, as filled in by the subroutines, should leave a
// trace of exactly what the problem was.
status = ERR_T_SW_INTERNAL;
}
// LOGERROR (XsAc97CtrlContext.loggedError, ERR_L_XSAC97CTRL,
// ERR_S_XSAC97CTRL_HWSETUP, status, 0, 0, 0)
}
return (status);
} // End XsAc97CtrlHWSetup ()
/*
*******************************************************************************
*
* FUNCTION: XsAc97CtrlGetStatus
*
* DESCRIPTION: Reports the value of the specified status indicator, as
* obtained from the ACUNIT's GSR register. Clears the
* status indicator, if possible, after reading it.
*
* Should not be used for status types that are currently in
* use as interrupt triggers.
*
* INPUT PARAMETERS: XsAc97CtrlStatusIdT statusId: ID of status indicator to get
*
* RETURNS: Status indicator masked and normalized to bit 0.
* Invalid ID: 0 (There is no direct reporting of invalid ID error).
*
* GLOBAL EFFECTS: 1) Because the status indicator is cleared, it will not be
* available to trigger an interrupt.
* 2) If the specified status ID is invalid, an error is
* logged in the error log and the context structure.
*
* ASSUMPTIONS: We don't have to double-check the hardware by making sure
* that a clearable status actually cleared.
*
* CALLS:
*
* CALLED BY:
*
* PROTOTYPE: UINT32 XsAc97CtrlGetStatus (XsAc97CtrlStatusIdT);
*
*******************************************************************************
*/
UINT32 XsAc97CtrlGetStatus (XsAc97CtrlStatusIdT statusId)
{
UINT32 statusIndication = 0; // Assume bad ID
UINT32 rangeCheckResult;
XsAc97CtrlStatusEntryT* statusTableEntryP;
rangeCheckResult = XsAc97CtrlRangeCheckStatusId (statusId);
if (rangeCheckResult)
{
// LOGERROR ( XsAc97CtrlContext.loggedError,
// ERR_L_XSAC97CTRL,
// ERR_S_XSAC97CTRL_GET_STATUS,
// rangeCheckResult, 0, 0, 0)
}
else
{
statusTableEntryP = XsAc97CtrlStatusTable + statusId;
// Get the indication, normalize it, then isolate it.
statusIndication = XsAc97CtrlRegsP->GSR;
statusIndication >>= statusTableEntryP->reportBitShiftGsr;
statusIndication &= statusTableEntryP->reportBitMaskGsr;
// Clear the indication if it exists and can be cleared.
// Don't use the clearing subroutine, there's so much extra overhead.
// Don't clear without finding it, to avoid race condition.
// NULL clear register means it can't be cleared.
if (statusIndication && statusTableEntryP->clearRegisterP)
{
// Write a shifted "1" to clear the status. Don't "OR" it in.
*statusTableEntryP->clearRegisterP =
1u << statusTableEntryP->clearBitShift;
}
} // else (rangeCheckResult)
return (statusIndication);
} // XsAc97CtrlGetStatus()
/*
*******************************************************************************
*
* FUNCTION: XsAc97CtrlWriteCodecReg
*
* DESCRIPTION: Write a value to a specific mixer register in a specific
* AC'97 codec or modem, using the AC Link.
*
* INPUT PARAMETERS:
*
* RETURNS:
* Success: 0 (ERR_NONE)
* Failure: ERR_T_NOT_AVAIL: AC Link was not available within the
* timeout interval.
* ERR_T_ILLPARAM: One of the ID parameters was illegal.
* Which one is recorded in the first parameter of
* the logged error. Software error.
*
* GLOBAL EFFECTS: Disables interrupts briefly, possibly sub-microsecond.
* Theoretical maximum is about 130 - 200 uSec.
* On termination, AC Link remains locked until the codec I/0
* cycle initiated by the local write completes. That
* should take from 21 to 42 uSec. Next codec I/O will not
* be able to start during that time.
*
* ASSUMPTIONS:
*
* CALLS:
*
* CALLED BY:
*
* PROTOTYPE: UINT32 XsAc97CtrlWriteCodecReg (XsAc97CtrlCodecModemIdT,
* AC97MixerRegisterIdT,
* UINT32);
*
*******************************************************************************
*
* DESIGN:
*
* 1. Disable interrupts, saving pre-existing state.
* 2. Read the CAR until it is verified that no Codec I/O accesses are
* currently in progress. This also claims the next codec I/O transaction
* for this operation.
* 3. Clear any status and error indications that can result from a Codec
* write operation (CDONE).
* 4. Write the specified data to the processor memory location that is mapped
* to the target Codec's target register.
* 5. Restore previous interrupt state.
*
* Note that this operation does not wait for the transmission to complete.
* Any remaining wait is done in the beginning of the next access.
*
*******************************************************************************
*/
UINT32 XsAc97CtrlWriteCodecReg (XsAc97CtrlCodecModemIdT ac97DeviceId,
AC97MixerRegisterIdT targetRegister,
UINT32 newValue)
{
UINT32 status ;
INT badParamNum = 0 ; // Which param had error. Assume no errors.
BOOL gotLink;
UINT32 irqIntState;
INT timeRemaining;
VUINT32* mixerRegsAccessP;
VUINT finishedStatus;
status = Ac97CheckRegId (targetRegister);
if (status)
{
badParamNum = 2;
}
else // register ID OK, set register access pointer to codec access base
{
switch (ac97DeviceId)
{
case XS_AC97CTRL_CM_ID_PRI_CODEC:
mixerRegsAccessP = &XsAc97CtrlRegsP->
XsAC97CtrlMixerRegsPrimaryAud[0];
break;
default:
status = ERR_T_ILLPARAM;
badParamNum = 1;
break;
}
} // else (register ID OK)
if (!status)
{
// Point to specified register within area mapped to target codec regs
mixerRegsAccessP += (targetRegister / XS_AC97CTRL_MIXER_REGS_PER_WORD);
irqIntState = XsIcDisableInterruptsIrq();
// Lock the ACLINK
timeRemaining = XS_AC97CTRL_CAIP_TIMEOUT_1USECS;
do
{
gotLink = XsAc97CtrlLockAcLink();
if (!gotLink) // 1 usec is a long time. Skip delay if possible.
{
DM_WaitUs(1);
}
}
// Wait while time remaining and ACLINK not available
while ( timeRemaining-- && !gotLink );
if (!gotLink) // Didn't get the ACLINK
{
status = ERR_T_NOT_AVAIL;
}
else // We got the link. Perform the write operation and don't wait.
{
// First, clear old write status indications.
// Ignore return code; if the ID is invalid, it won't compile.
(void) XsAc97CtrlClearStatus (XS_AC97CTRL_STAT_CDONE);
*mixerRegsAccessP = newValue; // Now the write!
// Wait until write cycle is complete. There should be a way
// to do this speculatively at the beginning of the procedure.
// Need to discover it. Too inefficient to always wait.
// Use more forgiving read timeout
timeRemaining = XS_AC97CTRL_READ_TIMEOUT_1USECS;
do
{
DM_WaitUs(1);
finishedStatus =
XsAc97CtrlGetStatus (XS_AC97CTRL_STAT_CDONE);
}
// Wait while time remaining and command I/O still incomplete
// CDONE bit is high when done.
while ( (timeRemaining--) && !finishedStatus);
} // Got AC link
XsIcRestoreInterruptsIrq (irqIntState);
} // if (!status): No problem with params. Sent command if link available.
if (status)
{
// LOGERROR (XsAc97CtrlContext.loggedError, ERR_L_XSAC97CTRL,
// ERR_S_XSAC97CTRL_CODEC_WRITE, status, badParamNum, 0, targetRegister)
}
return(status);
} // XsAc97CtrlCodecWrite()
/*
*******************************************************************************
*
* FUNCTION: XsAc97CtrlReadCodecReg
*
* DESCRIPTION: Read the value of a specific mixer register in a specified
* AC'97 codec or modem, using the AC Link.
*
* INPUT PARAMETERS:
* XsAc97CtrlCodecModemIdT ac97DeviceId: ID of modem or codec to read.
* AC97MixerRegisterIdT targetRegister: ID of register on codec.
* UINT32* mixerRegValueP: Address of variable in which to
* put the value from the codec reg.
*
* OUTPUT: UINT32* mixerRegValueP: Receives the value reported for the
* specified mixer register in the specified
* codec. Valid only if return code is zero.
*
* RETURNS:
* Success: 0 (ERR_NONE); value in *mixerRegValueP is valid.
* Failure: ERR_T_NOT_AVAIL: AC Link was not available within the
* initial timeout interval.
* ERR_T_ILLPARAM: One of the ID parameters was illegal.
* Which one is recorded in the first parameter of
* the logged error. Software error.
* ERR_T_TIMEOUT: A timeout occurred after initial
* acquisition of the AC Link. The point in the
* routine where the timeout occurred is recorded
* in the second parameter of the logged error.
*
* GLOBAL EFFECTS: Disables interrupts for at least 42 uSec. Theoretical
* maximum is about 250 uSec.
* On termination, AC Link remains locked until the codec I/0
* cycle initiated by the second local read completes. That
* could take from 42 to 84+ uSec. Next codec I/O will not
* be able to start during that time.
* Errors recorded in context structure and system error log.
*
* ASSUMPTIONS:
*
* CALLS:
*
* CALLED BY:
*
* PROTOTYPE: UINT32 XsAc97CtrlReadCodecReg (XsAc97CtrlCodecModemIdT,
* AC97MixerRegisterIdT,
* UINT32*);
*
*******************************************************************************
*
* DESIGN:
*
* 1. Disable interrupts, saving pre-existing state.
* 2. Read the CAR until it is verified that no codec I/O accesses are
* currently in progress. This also claims the next codec I/O transaction
* for this operation.
* 3. Clear any status and error indications that can result from a codec read
* operation (SDONE, Read Completion Status).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -