⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xsac97ctrl.c

📁 优龙YLP270开发板 光盘自带的BIOS和实验例程源码 强烈推荐
💻 C
📖 第 1 页 / 共 5 页
字号:

    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.  Wait with a timeout until the CDONE indicator is set.  This means that
*       the command has been sent.
*  6.  Restore previous interrupt state.
*
*  Note: It should theoretically be possible to write a driver so that this
*    operation does not wait for the transmission to complete.  Any remaining
*    wait would be done in the beginning of the next access.  That
*    optimization has not yet been successfully implemented.
*
*******************************************************************************
*/

ErrorT XsAc97CtrlWriteCodecReg   (XsAc97CtrlCodecModemIdT  ac97DeviceId,
                                 AC97MixerRegisterIdT     targetRegister,
                                 UINT32                   newValue)
{
    ErrorT    retVal;
    INT       badParamNum  = 0 ; // Which param had error.  Assume no errors.
    BOOL      gotLink;
    UINT32    irqIntState;
    INT       timeRemaining;
    VUINT32*  mixerRegsAccessP;
    VUINT     finishedStatus;

    retVal = Ac97CheckRegId (targetRegister);
    if (retVal)
    {
        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:
                retVal      = ERR_T_ILLPARAM;
                badParamNum = 1;
                break;
        }
    } // else (register ID OK)

    if (!retVal)
    {
        // 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
        {
            retVal = 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 (!retVal): No problem with params.  Sent command if link available.

    if (retVal)
    {
        LOGERROR (XsAc97CtrlContext.loggedError, ERR_L_XSAC97CTRL,
            ERR_S_XSAC97CTRL_CODEC_WRITE, retVal, badParamNum, 0, targetRegister)
    }

    return(retVal);

} // 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).
*  4.  Perform the first (dummy) read from the processor memory location that is
*      mapped to the target Codec's target register.  Discard the resulting data
*  5.  Continuously check the AC '97 Controller's Global Status Register until
*      the SDONE bit is set.  Use software timeout logic.
*  6.  If the Read Completion Status bit is set or the software timeout has
*      occurred, there is a timeout.
*      a)  Declare an error status
*      b)  Skip to step 8 in this procedure.
*  7.  If there was no timeout, the read operation was successful.
*      a)  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.  It leaves an indication for the
*          next SW read or write I/O operation.  This will prevent ambiguity.
*          (We shouldn't actually have to loop here because the SDONE bit
*          indicator ought to be set at the same time as the CAR indicator
*          clears.  But we loop anyway, just in case.)
*      b)  Perform the second read to obtain the register contents reported by
*          the codec.
*      c)  Report the data obtained from the codec.
*      d)  Wait with a timeout until the SDONE indicator is set.
*          This means that the I/O cycle triggered by the second read has
*          completed.
*  8.  Restore previous interrupt state.
*  9.  Report success or error status.
*
*  Note: It should theoretically be possible to write a driver so that that
*   this operation does not wait for the second read operation to complete.
*   Any remaining wait would be done in the beginning of the next access.
*   That optimization has not yet been successfully implemented.
*
*  Note also that there is a possible optimization in this processor for reads
*   of a modem's GPIO bits that are reported to the controller in time slot 12.
*   It would be to skip the timeout logic and the second read cycle because the
*   local values are constantly updated from the values reported in TS 12.
*
*  Once the link is acquired, perform the double read under interrupt
*   protection.  This is necessary to make it an atomic operation.  Even
*   if link acquisition continued for @@@
*
*******************************************************************************
*/

ErrorT XsAc97CtrlReadCodecReg (XsAc97CtrlCodecModemIdT  ac97DeviceId,
                               AC97MixerRegisterIdT     targetRegister,
                               UINT32*                  mixerRegValueP)
{
    ErrorT    retVal ;
    INT       badParamNum  = 0; // Which param had error.  Assume no errors.
    INT       timeoutLoc   = 0; // What point had a timeout.  Assume no errors.
    BOOL      gotLink;
    VUINT32   readFinishedStatus;
    UINT32    irqIntState;
    UINT32    rcsErrTmp;
    INT       minorIterations;
    INT       retries   =   0;
    XsAc97CtrlStatsT* codeStatsP;
    VUINT32*  mixerRegsAccessP;

    retVal = Ac97CheckRegId (targetRegister);

    if (retVal)
    {
        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];
                codeStatsP = &XsAc97CtrlContext.statistics[ac97DeviceId];
                break;
            default:
                retVal      = ERR_T_ILLPARAM;
                badParamNum = 1;
                break;
        }
        // Point to specified register within area mapped to target codec regs
        mixerRegsAccessP += (targetRegister / XS_AC97CTRL_MIXER_REGS_PER_WORD);

    } // else (register ID OK)

    if (!retVal)
    {
        // Some statistics.  Only valid invocations are interesting.
        irqIntState = XsIcDisableInterruptsIrq();
        codeStatsP->readCodecNumInvocations++;
        XsIcRestoreInterruptsIrq (irqIntState);

        do
        {
            retVal = ERR_NONE;      // Clear for possible retry
            // Protect entire operation for simplicity.  Very small extra
            //  execution time penalty.
            irqIntState = XsIcDisableInterruptsIrq();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -