📄 sa150xintrctl.c
字号:
int key; int bit; UINT32 val; sa150xIntrCtlDetails *p; if (level < 0 || level >= SA150X_INT_NUM_LEVELS) return ERROR; bit = 1 << (level % 32); p = &sa150xIntrCtl[level / 32]; key = intIFLock (); /* disable IRQ and FIQ */ /* configure destination - note: must not retry write (locks up) */ SA150X_INT_REG_READ (SA150X_INT_DESTINATION (p->base), val); val &= ~bit; /* clear bit for this interrupt */#ifdef SA150X_INT_HANDLE_1501_DESTINATION if (features & SA150X_INT_DESTINATION_FIQ) val |= bit & (bit ^ p->destModifier); else val |= bit & (0 ^ p->destModifier);#else if (features & SA150X_INT_DESTINATION_FIQ) val |= bit;#endif SA150X_INT_REG_WRITE (SA150X_INT_DESTINATION (p->base), val); /* configure polarity */ SA150X_INT_REG_READ (SA150X_INT_POLARITY (p->base), val); if (features & SA150X_INT_POLARITY_POSITIVE) val &= ~bit; else val |= bit;#ifdef SA150X_INT_RETRY_WRITES SA150X_INT_REG_WRITE_RETRY (SA150X_INT_POLARITY (p->base), val);#else SA150X_INT_REG_WRITE (SA150X_INT_POLARITY (p->base), val);#endif intIFUnlock (key); /* restore IRQ and FIQ */ /* clear any pending interrupt */ SA150X_INT_REG_WRITE (SA150X_INT_CLEAR (p->base), bit); /* * if level interrupt, and source register (which takes account of * polarity) indicates that interrupt is still active, set request */ if (features & SA150X_INT_TYPE_LEVEL) { SA150X_INT_REG_READ (SA150X_INT_SOURCE (p->base), val); if (val & bit) SA150X_INT_REG_WRITE (SA150X_INT_SET (p->base), bit); } return OK; }/********************************************************************************* sa150xIntLvlVecChk - 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 sa150xIntLvlVecChk ( int* pLevel, /* ptr to receive old interrupt level */ int* pVector /* ptr to receive current interrupt vector */ ) { int newLevel; sa150xIntrCtlDetails *p; UINT32 isr, bit; UINT32 *priPtr; int ctl; int bitNum;#ifdef SA150X_INT_RETRY_READS int ok;#define TRIES 2#endif /* initialise vars to stop compiler warnings */ p = 0; bit = 0; SA150X_INT_DEBUG(0x00, 0);#ifdef SA150X_INT_CACHE_IRQ_REQUEST /* mark all cached requests as invalid */ for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl) sa150xIntrCtl[ctl].requestsValid = FALSE;#endif if (priPtr = sa150xIntLvlPriMap, priPtr == 0) bitNum = -1; else { /* service interrupts according to priority specified in map */ while (bitNum = *priPtr++, bitNum != -1) { /* * bitNum = interrupt bit from priority map - convert it to * a bit position in a specific controller * Note: UINT32 cast of bitNum is an optimisation(!) */ ctl = (UINT32)bitNum / 32; bit = 1 << ((UINT32)bitNum % 32); p = &sa150xIntrCtl[ctl];#ifdef SA150X_INT_CACHE_IRQ_REQUEST if (p->requestsValid) { isr = p->irqRequests; SA150X_INT_DEBUG(0x81, ctl); } else {#endif /* read pending interrupt register for this controller */ SA150X_INT_DEBUG(0x80, ctl); SA150X_INT_REQ_REG_READ (SA150X_INT_IRQ_REQUEST (p->base), isr, ~p->enabledIrqs, TRIES, ok);#ifdef SA150X_INT_RETRY_READS if (ok)#endif#ifdef SA150X_INT_CACHE_IRQ_REQUEST { p->requestsValid = TRUE; p->irqRequests = isr; }#ifdef SA150X_INT_RETRY_READS else { isr = 0; SA150X_INT_DEBUG(0x83, bitNum); }#endif }#endif /* SA150X_INT_CACHE_IRQ_REQUEST */ if (isr & bit) { SA150X_INT_DEBUG(0x82, bitNum); break; } } } /* * If priority scan didn't find anything, look for any bit set in any * controller, starting with the lowest-numbered bit */ if (bitNum == -1) for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl) { p = &sa150xIntrCtl[ctl];#ifdef SA150X_INT_CACHE_IRQ_REQUEST if (p->requestsValid) { isr = p->irqRequests; SA150X_INT_DEBUG(0x91, ctl); } else {#endif /* read pending interrupt register for this controller */ SA150X_INT_DEBUG(0x90, ctl); SA150X_INT_REQ_REG_READ (SA150X_INT_IRQ_REQUEST (p->base), isr, ~p->enabledIrqs, TRIES, ok);#ifdef SA150X_INT_RETRY_READS if (ok)#endif#ifdef SA150X_INT_CACHE_IRQ_REQUEST { p->requestsValid = TRUE; p->irqRequests = isr; }#ifdef SA150X_INT_RETRY_READS else { isr = 0; SA150X_INT_DEBUG(0x93, ctl); }#endif }#endif /* SA150X_INT_CACHE_IRQ_REQUEST */ /* find lowest bit set */ bitNum = ffsLsb (isr) - 1; /* ffsLsb returns 1..n, not 0..n-1 */ if (bitNum != -1) { bit = 1 << bitNum; bitNum += ctl * 32; SA150X_INT_DEBUG(0x92, bitNum); break; } } /* If no interrupt is pending, return ERROR */ if (bitNum == -1) { SA150X_INT_DEBUG(0xEE, 0xEE); return ERROR; } /* * bitNum is the bit that is interrupting (0..SA150X_INT_NUM_LEVELS-1) * ctl is the controller number (0..SA150X_INT_NUM_CONTROLLERS-1) * bit is the bit within that controller * p-> sa150xIntrCtl structure for this controller * * clear the interrupt */ SA150X_INT_REG_WRITE (SA150X_INT_CLEAR (p->base), bit); /* map the interrupting device to an interrupt level number */ newLevel = sa150xIntLvlMap[bitNum]; /* change to new interrupt level, returning previous level to caller */ *pLevel = sa150xIntLvlChg (newLevel); /* fetch, or compute the interrupt vector number */ SA150X_INT_LVL_VEC_MAP (bitNum, *pVector); SA150X_INT_DEBUG(0xEE, 0x00); return OK; }/********************************************************************************* sa150xIntLvlVecAck - acknowledge the current interrupt** Acknowledge the current interrupt cycle. The level and vector values are* those generated during the sa150xIntLvlVecChk() routine for this interrupt* cycle. The basic action is to return the interrupt level to its previous* setting. Note that the SA150X interrupt controller does not need an* acknowledge cycle and that the interrupt has already been cleared in* sa150xIntLvlVecChk().** RETURNS: OK or ERROR if a hardware fault is detected.* ARGSUSED*/STATUS sa150xIntLvlVecAck ( int level, /* old interrupt level to be restored */ int vector /* current interrupt vector, if needed */ ) { SA150X_INT_DEBUG(0xFF, vector); /* restore the previous interrupt level */ sa150xIntLvlChg (level); return OK; }/********************************************************************************* sa150xIntLvlChg - change the interrupt level value** This routine implements the overall interrupt setting. All levels* up to and including the specified level are disabled. All levels above* the specified level will be enabled, but only if they were specifically* enabled by the sa150xIntLvlEnable() routine.** The specific priority level SA150X_INT_NUM_LEVELS is valid and represents* all levels enabled.** RETURNS: Previous interrupt level.*/int sa150xIntLvlChg ( int level /* new interrupt level */ ) { int oldLevel; int i, m; sa150xIntrCtlDetails *p; int key; oldLevel = sa150xIntLvlCurrent; if (level >= 0 && level <= SA150X_INT_NUM_LEVELS) { /* change current interrupt level */ sa150xIntLvlCurrent = level; } /* Activate the enabled interrupts */ m = sa150xIntLvlCurrent * SA150X_INT_NUM_CONTROLLERS; for (i = 0; i < SA150X_INT_NUM_CONTROLLERS; ++i) { p = &sa150xIntrCtl[i]; key = intIFLock (); /* disable IRQ and FIQ */#ifdef SA150X_INT_RETRY_WRITES SA150X_INT_REG_WRITE_RETRY (SA150X_INT_ENABLE (p->base), (sa150xIntLvlMask[m + i] & p->enabledIrqs) | p->enabledFiqs);#else SA150X_INT_REG_WRITE (SA150X_INT_ENABLE (p->base), (sa150xIntLvlMask[m + i] & p->enabledIrqs) | p->enabledFiqs);#endif intIFUnlock (key); } return oldLevel; }/********************************************************************************* sa150xIntLvlEnable - 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* sa150xIntLvlPriMap). 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 sa150xIntLvlEnable ( int level /* level to be enabled */ ) { int key; if (level < 0 || level >= SA150X_INT_NUM_LEVELS) return ERROR; /* set bit in enable mask */ key = intIFLock (); /* disable IRQ and FIQ */ sa150xIntrCtl[level / 32].enabledIrqs |= (1 << (level % 32)); intIFUnlock (key); sa150xIntLvlChg (-1); /* reset current mask */ return OK; }/********************************************************************************* sa150xIntLvlDisable - 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* sa150xIntLvlPriMap).** RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.*/STATUS sa150xIntLvlDisable ( int level /* level to be disabled */ ) { int key; if (level < 0 || level >= SA150X_INT_NUM_LEVELS) return ERROR; /* clear bit in enable mask */ key = intIFLock (); /* disable IRQ and FIQ */ sa150xIntrCtl[level / 32].enabledIrqs &= ~(1 << (level % 32)); intIFUnlock (key); sa150xIntLvlChg (-1); /* reset current mask */ return OK; }/********************************************************************************* sa150xIntFiqEnable - enable a single FIQ interrupt** Enable a specific FIQ interrupt. Unlike an enable IRQ interrupt, an* enabled FIQ interrupt will be always be allowed to interrupt,* irrespective of the overall interrupt level.** RETURNS: OK or ERROR if the specified level cannot be enabled.*/STATUS sa150xIntFiqEnable ( int level /* level to be enabled */ ) { int key; if (level < 0 || level >= SA150X_INT_NUM_LEVELS) return ERROR; /* set bit in enable mask */ key = intIFLock (); /* disable IRQ and FIQ */ sa150xIntrCtl[level / 32].enabledFiqs |= (1 << (level % 32)); intIFUnlock (key); sa150xIntLvlChg (-1); /* reset current mask */ return OK; }/********************************************************************************* sa150xIntFiqDisable - disable a single FIQ interrupt** Disable a specific FIQ interrupt. The disabled level is prevented* from generating an interrupt.** RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.*/STATUS sa150xIntFiqDisable ( int level /* level to be disabled */ ) { int key; if (level < 0 || level >= SA150X_INT_NUM_LEVELS) return ERROR; /* clear bit in enable mask */ key = intIFLock (); /* disable IRQ and FIQ */ sa150xIntrCtl[level / 32].enabledFiqs &= ~(1 << (level % 32)); intIFUnlock (key); sa150xIntLvlChg (-1); /* reset current mask */ return OK; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -