📄 ambaintrctl.c
字号:
/* * set index in level map: to disable this interrupt and all * lower-priority ones, select the level one less than this */ ambaIntLvlMap[i] = level - 1; } } /* do the rest of the levels */ i = 0; /* lowest-numbered interrupt bit */ for ( ; level <= AMBA_INT_NUM_LEVELS; ++level) { /* copy previous level's mask to this one's */ ambaIntLvlMask[level] = ambaIntLvlMask[level - 1]; /* try to find a bit that has not yet been set */ for ( ; ; ++i) { bit = 1 << i; if ((ambaIntLvlMask[level] & bit) == 0) { /* this bit not set so put it in the mask */ ambaIntLvlMask[level] |= bit; /* * set index in level map: to disable this interrupt and all * lower-priority ones, select the level one less than this */ ambaIntLvlMap[i] = level - 1; break; } } }#endif /* install the driver routines in the architecture hooks */ sysIntLvlVecChkRtn = ambaIntLvlVecChk; sysIntLvlVecAckRtn = ambaIntLvlVecAck; sysIntLvlChgRtn = ambaIntLvlChg; sysIntLvlEnableRtn = ambaIntLvlEnable; sysIntLvlDisableRtn = ambaIntLvlDisable; ambaIntLvlEnabled = 0; /* all sources disabled */ ambaIntLvlChg (AMBA_INT_ALL_ENABLED); /* enable all levels */ return OK; }/********************************************************************************* ambaIntLvlVecChk - 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 ambaIntLvlVecChk ( int* pLevel, /* ptr to receive old interrupt level */ int* pVector /* ptr to receive current interrupt vector */ ) { int newLevel; UINT32 isr;#ifdef AMBA_INT_PRIORITY_MAP UINT32 *priPtr; int bitNum;#endif /* Read pending interrupt register and mask undefined bits */ AMBA_INT_REG_READ (AMBA_INT_CSR_PEND, isr);#ifdef AMBA_INT_CSR_MASK isr &= AMBA_INT_CSR_MASK;#endif /* If no interrupt is pending, return ERROR */ if (isr == 0) return ERROR;#ifdef AMBA_INT_PRIORITY_MAP priPtr = (UINT32 *)ambaIntLvlPriMap; if (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 (isr & (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 (isr) - 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 = ambaIntLvlMap[bitNum];#else /* find first bit set in ISR, starting from lowest-numbered bit */ if (newLevel = ffsLsb (isr), newLevel == 0) return ERROR; --newLevel; /* ffsLsb returns numbers from 1, not 0 */ /* map the interrupting device to an interrupt level number */ AMBA_INT_PEND_LVL_MAP (newLevel, newLevel);#endif /* ifdef AMBA_INT_PRIORITY_MAP */ /* change to new interrupt level, returning previous level to caller */ *pLevel = ambaIntLvlChg (newLevel); /* fetch, or compute the interrupt vector number */#ifdef AMBA_INT_PRIORITY_MAP AMBA_INT_LVL_VEC_MAP (bitNum, *pVector);#else AMBA_INT_LVL_VEC_MAP (newLevel, *pVector);#endif return OK; }/********************************************************************************* ambaIntLvlVecAck - acknowledge the current interrupt** Acknowledge the current interrupt cycle. The level and vector values are* those generated during the ambaIntLvlVecChk() routine for this interrupt* cycle. The basic action is to reset the current interrupt and return* the interrupt level to its previous setting. Note that the AMBA interrupt* controller does not need an acknowledge cycle.** RETURNS: OK or ERROR if a hardware fault is detected.* ARGSUSED*/STATUS ambaIntLvlVecAck ( int level, /* old interrupt level to be restored */ int vector /* current interrupt vector, if needed */ ) { /* restore the previous interrupt level */ ambaIntLvlChg (level); return OK; }/********************************************************************************* ambaIntLvlChg - 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 ambaIntLvlEnable() routine.** The specific priority level AMBA_INT_NUM_LEVELS is valid and represents* all levels enabled.** RETURNS: Previous interrupt level.*/int ambaIntLvlChg ( int level /* new interrupt level */ ) { int oldLevel; oldLevel = ambaIntLvlCurrent; if (level >= 0 && level <= AMBA_INT_NUM_LEVELS) { /* change current interrupt level */ ambaIntLvlCurrent = level; } /* Switch off all interrupts */ AMBA_INT_REG_WRITE (AMBA_INT_CSR_DIS, -1); /* Activate the enabled interrupts */ AMBA_INT_REG_WRITE (AMBA_INT_CSR_ENB, (ambaIntLvlMask[ambaIntLvlCurrent] & ambaIntLvlEnabled)); return oldLevel; }/********************************************************************************* ambaIntLvlEnable - 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 ambaIntLvlPriMap,* if appropriate). Without being enabled, the interrupt is blocked* regardless of the overall interrupt level setting.** RETURNS: OK or ERROR if the specified level cannot be enabled.*/STATUS ambaIntLvlEnable ( int level /* level to be enabled */ ) { int key; if (level < 0 || level >= AMBA_INT_NUM_LEVELS) return ERROR; /* set bit in enable mask */ key = intLock (); ambaIntLvlEnabled |= (1 << level); intUnlock (key); ambaIntLvlChg (-1); /* reset current mask */ return OK; }/********************************************************************************* ambaIntLvlDisable - 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* ambaIntLvlPriMap, if appropriate).** RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.*/STATUS ambaIntLvlDisable ( int level /* level to be disabled */ ) { int key; if (level < 0 || level >= AMBA_INT_NUM_LEVELS) return ERROR; /* clear bit in enable mask */ key = intLock (); ambaIntLvlEnabled &= ~(1 << level); intUnlock (key); ambaIntLvlChg (-1); /* reset current mask */ return OK; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -