📄 at91intrctl.c
字号:
* interrupt. It should be called after initialisation of the driver and
* must be called before enabling the level.
*
* The return value ERROR indicates that the parameters were invalid.
*
* RETURNS: OK or ERROR if parameters invalid.
*/
STATUS at91IntLvlConfigure
(
int level, /* level to configure */
int features /* edge/level/positive/negative */
)
{
int bits;
if (level < 0 ||
level >= AT91_INT_NUM_LEVELS)
return ERROR;
/*
* Configure polarity:
*
* Bits to be written to configuration register are:
* 00 = level, active low
* 01 = edge, negative edge
* 10 = level, active high
* 11 = edge, positive edge
*/
bits = features << 5; /* set priority zero */
AT91_INT_REG_WRITE ((AT91_INT_CSR_MODE + (level * 4)), bits);
/* put level number into the source vector reg to read back on interrupt*/
AT91_INT_REG_WRITE ((AT91_INT_CSR_SVEC + (level * 4)), level);
return OK;
}
/*******************************************************************************
*
* at91IntLvlVecChk - check for and return any pending interrupts
*
* This routine interrogates the hardware to determine the highest priority
* interrupt pending. It returns the vector associated with that interrupt, and
* also the interrupt priority level prior to the interrupt (not the
* level of the interrupt). The current interrupt priority level is then
* raised to the level of the current interrupt so that only higher priority
* interrupts will be accepted until this interrupt is finished.
*
* This routine must be called with CPU interrupts disabled.
*
* The return value ERROR indicates that no pending interrupt was found and
* that the level and vector values were not returned.
*
* RETURNS: OK or ERROR if no interrupt is pending.
*/
STATUS at91IntLvlVecChk
(
int* pLevel, /* ptr to receive old interrupt level */
int* pVector /* ptr to receive current interrupt vector */
)
{
int newLevel;
#ifdef AT91_INT_SOFT_PRIORITY_MAP
UINT32 *priPtr;
int bitNum;
UINT32 ipr;
UINT32 imr;
UINT32 dummy;
#endif
#ifdef AT91_INT_SOFT_PRIORITY_MAP
/*
* Read pending interrupt register before reading vector register,
* which we must do anyway, as early as possible.
*/
AT91_INT_REG_READ (AT91_INT_CSR_PEND, ipr);
AT91_INT_REG_READ (AT91_INT_CSR_VECT, dummy);
#ifdef AT91_INT_USE_PROTECT_MODE
AT91_INT_REG_WRITE (AT91_INT_CSR_VECT, dummy);
#endif /* AT91_INT_USE_PROTECT_MODE */
/* read enabled interrupts and mask pending interrupts with that */
AT91_INT_REG_READ (AT91_INT_CSR_IMR, imr);
ipr &= imr;
/* If no interrupt is pending, return ERROR */
if (ipr == 0)
#else /* AT91_INT_SOFT_PRIORITY_MAP */
AT91_INT_REG_READ (AT91_INT_CSR_VECT, newLevel);
#ifdef AT91_INT_USE_PROTECT_MODE
AT91_INT_REG_WRITE (AT91_INT_CSR_VECT, newLevel);
#endif /* AT91_INT_USE_PROTECT_MODE */
/* If no interrupt is pending, return ERROR */
if (newLevel == 0)
#endif /* AT91_INT_SOFT_PRIORITY_MAP */
{
/*
* If there is no interrupt pending, then the architecture code
* will not call the intLvlVecAck routine, leading to an
* imbalance in the interrupt controller hardware stack. So, we
* need to issue the End Of Interrupt command here. Depending
* upon how we have been called by the architecture code, this
* may or may not indicate that there has been a spurious
* interrupt.
*/
AT91_INT_REG_WRITE (AT91_INT_CSR_EOIC, 0); /* issue End-of-Int cmd */
return ERROR;
}
#ifdef AT91_INT_SOFT_PRIORITY_MAP
if (priPtr = at91IntLvlPriMap, priPtr == 0)
bitNum = -1;
else
{
/* service interrupts according to priority specifed in map */
while (bitNum = *priPtr++, bitNum != -1)
{
/* bitNum = interrupt bit from priority map */
if (ipr & (1 << bitNum))
{
break;
}
}
}
/*
* if priority scan didn't find anything, look for any bit set,
* starting with the lowest-numbered bit
*/
if (bitNum == -1)
bitNum = ffsLsb (ipr) - 1; /* ffsLsb returns numbers from 1, not 0 */
/* if no interrupt is pending, return ERROR */
if (bitNum == -1)
return ERROR;
/* map the interrupting device to an interrupt level number */
newLevel = at91IntLvlMap[bitNum];
#else /* ifdef AT91_INT_SOFT_PRIORITY_MAP */
if (newLevel > AT91_INT_NUM_LEVELS)
return ERROR;
/* map the interrupting device to an interrupt level number */
AT91_INT_PEND_LVL_MAP (newLevel, newLevel);
#endif /* ifdef AT91_INT_SOFT_PRIORITY_MAP */
/* change to new interrupt level, returning previous level to caller */
*pLevel = at91IntLvlChg (newLevel);
/* fetch, or compute the interrupt vector number */
#ifdef AT91_INT_SOFT_PRIORITY_MAP
AT91_INT_LVL_VEC_MAP (bitNum, *pVector);
#else
AT91_INT_LVL_VEC_MAP (newLevel, *pVector);
#endif
return OK;
}
/*******************************************************************************
*
* at91IntLvlVecAck - acknowledge the current interrupt
*
* Acknowledge the current interrupt cycle. The level and vector values are
* those generated during the at91IntLvlVecChk() routine for this interrupt
* cycle. The basic action is to reset the current interrupt and return
* the interrupt level to its previous setting.
*
* RETURNS: OK or ERROR if a hardware fault is detected.
* ARGSUSED
*/
STATUS at91IntLvlVecAck
(
int level, /* old interrupt level to be restored */
int vector /* current interrupt vector, if needed */
)
{
/* acknowledge end of interrupt cycle */
AT91_INT_REG_WRITE (AT91_INT_CSR_EOIC, 0); /* Write of any value will do */
/* restore the previous interrupt level */
at91IntLvlChg (level);
return OK;
}
/*******************************************************************************
*
* at91IntLvlChg - change the interrupt level value
*
* This routine implements the overall interrupt setting. All levels
* up to and including the specifed level are disabled. All levels above
* the specified level will be enabled, but only if they were specifically
* enabled by the at91IntLvlEnable() routine.
*
* The specific priority level AT91_INT_NUM_LEVELS is valid and represents
* all levels enabled.
*
* RETURNS: Previous interrupt level.
*/
int at91IntLvlChg
(
int level /* new interrupt level */
)
{
int oldLevel;
oldLevel = at91IntLvlCurrent;
if (level >= 0 &&
level <= AT91_INT_NUM_LEVELS)
{
/* change current interrupt level */
at91IntLvlCurrent = level;
}
/* Switch off all interrupts */
AT91_INT_REG_WRITE (AT91_INT_CSR_DIS, -1);
/* Activate the enabled interrupts */
AT91_INT_REG_WRITE (AT91_INT_CSR_ENB,
(at91IntLvlMask[at91IntLvlCurrent] & at91IntLvlEnabled));
return oldLevel;
}
/*******************************************************************************
*
* at91IntLvlEnable - enable a single interrupt level
*
* Enable a specific interrupt level. The enabled level will be allowed
* to generate an interrupt when the overall interrupt level is set to
* enable interrupts of this priority (as configured by at91IntLvlPriMap,
* if appropriate). When not enabled, the interrupt is blocked
* regardless of the overall interrupt level setting.
*
* The interrupt level must have been configured by a call to
* at91IntLvlConfigure() before it is enabled by a call to this routine.
*
* RETURNS: OK or ERROR if the specified level cannot be enabled.
*/
STATUS at91IntLvlEnable
(
int level /* level to be enabled */
)
{
int key;
if (level < 0 ||
level >= AT91_INT_NUM_LEVELS)
return ERROR;
/* set bit in enable mask */
key = intLock ();
at91IntLvlEnabled |= (1 << level);
intUnlock (key);
at91IntLvlChg (-1); /* reset current mask */
return OK;
}
/*******************************************************************************
*
* at91IntLvlDisable - disable a single interrupt level
*
* Disable a specific interrupt level. The disabled level is prevented
* from generating an interrupt even if the overall interrupt level is
* set to enable interrupts of this priority (as configured by
* at91IntLvlPriMap, if appropriate).
*
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
*/
STATUS at91IntLvlDisable
(
int level /* level to be disabled */
)
{
int key;
if (level < 0 ||
level >= AT91_INT_NUM_LEVELS)
return ERROR;
/* clear bit in enable mask */
key = intLock ();
at91IntLvlEnabled &= ~(1 << level);
intUnlock (key);
at91IntLvlChg (-1); /* reset current mask */
return OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -