📄 int.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004-2006 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.02.02 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/9. * *---------------------------------------------------------------------- *//* * @(#)int.c (libtk/MC9328) * * Interrupt controller operation * * Operation functions of interrupt controller support IRQ, GPIO, FPGA * interrupts. Some functions treat part of those interrupts. * FIQ interrupt is specified by IRQ interrupt vector which means the * same factor. If invalid vector is specified, operation is not * guaranteed. */#include <basic.h>#include <tk/syslib.h>#include <tk/sysdef.h>/* * Interrupt disable/enable */Inline UW _disint( void ){ UW imask; Asm(" mrs %0, cpsr \n" " orr ip, %0, %1 \n" " msr cpsr_c, ip " : "=r"(imask) : "i"(PSR_DI) : "ip" ); return imask;}Inline void _enaint( UW imask ){ Asm("msr cpsr_c, %0":: "r"(imask));}#define _DI(imask) ( imask = _disint() )#define _EI(imask) ( _enaint(imask) )/* * Set interrupt enable level * Disable IRQ interrupts which level is less then or equal to specified * 'level'. 'level' must be '-1'-'15'. * If '-1' is specified, all level IRQ interrupts are enable. * If '15' is specified, all level IRQ interrupts are disable. * 'level' is set to the NIMASK register of interrupt controller. * Initial value is '-1'. * This function returns the interrupt enable level before being changed. */EXPORT INT SetIntLevel( INT level ){ INT old; old = in_w(NIMASK) & 0x0000001f; if ( old == 0x0000001f ) { old = -1; } out_w(NIMASK, level); return old;}/* * Set interrupt mode * Set accept mode to 'mode' regarding interrupt specified by 'intvec'. * If 'mode' is not correct value, operation is not guaranteed. * * For IRQ, mode := (IM_IRQ || IM_FIQ) * Set the INTTYPE register of interrupt controller. * Initial value is IM_IRQ. * * For GPIO, mode := (IM_LEVEL || IM_EDGE) | (IM_HI || IM_LOW) * Set the ICR register of GPIO controller. * * For FPGA interrupt, cannot set interrupt mode. */EXPORT void SetIntMode( INTVEC intvec, UINT mode ){ UW msk, set; INT reg; UW imask; if ( intvec < (INTVEC)IV_GPA(0) ) { /* IRQ */ intvec -= (INTVEC)IV_IRQ(0); reg = INTTYPEL - ((INT)(intvec >> 5) * 4); msk = 1 << (intvec & 0x0000001fU); set = ( (mode & IM_FIQ) != 0 )? msk: 0; _DI(imask); out_w(reg, (in_w(reg) & ~msk) | set); _EI(imask); } else { /* GPIO */ intvec -= (INTVEC)IV_GPA(0); reg = ICR1_A + ((INT)(intvec >> 5) * 0x100); reg += (INT)(intvec & 0x00000010U) >> (4 - 2); set = (intvec & 0x0000000fU) * 2; msk = 3 << set; set = (mode & 3) << set; _DI(imask); out_w(reg, (in_w(reg) & ~msk) | set); _EI(imask); }}/* * Enable interrupt * Enable interrupt specified by 'intvec'. * * For IRQ, level := '0'-'15'. * level=0 means lowest priority level, level=15 means highest. * If 'level' is outside this range, operation is not guaranteed. * Set the NIPRIORITY register with the value 'level' and set * interrupt enable to the INTENABLE register. * For FIQ, 'level' has no mean. * * For GPIO, 'level' is ignored. * Set the IMR register of GPIO controller to interrupt enable. * * For FPGA, 'level' is ignored. * Set the IRQ_MASK register to interrupt enable. */EXPORT void EnableInt( INTVEC intvec, INT level ){ INT reg, num; UW imask; if ( intvec < (INTVEC)IV_GPA(0) ) { /* IRQ */ intvec -= (INTVEC)IV_IRQ(0); reg = NIPRIORITY0 - ((INT)(intvec >> 3) * 4); num = (INT)(intvec & 0x00000007U) * 4; _DI(imask); out_w(reg, (in_w(reg) & ~(0x0000000fU << num)) | (UW)(level << num)); out_w(INTENNUM, intvec); _EI(imask); } else if ( intvec < (INTVEC)IV_FPGA1(0) ) { /* GPIO */ intvec -= (INTVEC)IV_GPA(0); reg = IMR_A + ((INT)(intvec >> 5) * 0x100); num = (INT)(intvec & 0x0000001fU); _DI(imask); out_w(reg, in_w(reg) | (0x00000001U << num)); _EI(imask); } else { /* FPGA */ intvec -= (INTVEC)IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_MASK1: IRQ_MASK2; num = (INT)(intvec & 0x00000007U); _DI(imask); out_b(reg, in_b(reg) | (0x01U << num)); _EI(imask); }}/* * Disable interrupt * Disable interrupt specified by 'intvec'. * * For IRQ, set the INTENABLE register to interrupt disable state. * * For GPIO, set the IMR register to interrupt disable. * * For FPGA, set the IRQ_MASK register to interrupt disable. */EXPORT void DisableInt( INTVEC intvec ){ INT reg, num; UW imask; if ( intvec < (INTVEC)IV_GPA(0) ) { /* IRQ */ intvec -= (INTVEC)IV_IRQ(0); out_w(INTDISNUM, intvec); } else if ( intvec < (INTVEC)IV_FPGA1(0) ) { /* GPIO */ intvec -= (INTVEC)IV_GPA(0); reg = IMR_A + ((INT)(intvec >> 5) * 0x100); num = (INT)(intvec & 0x0000001fU); _DI(imask); out_w(reg, in_w(reg) & ~(0x00000001U << num)); _EI(imask); } else { /* FPGA */ intvec -= (INTVEC)IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_MASK1: IRQ_MASK2; num = (INT)(intvec & 0x00000007U); _DI(imask); out_b(reg, in_b(reg) & ~(0x00000001U << num)); _EI(imask); }}/* * Clear interrupt request * Clear interrupt request specified by 'intvec'. * This function is valid for GPIO and FPGA interrupts. * For FPGA interrupt, clear 'GPIO Port A pin 7' which connected to FPGA. */EXPORT void ClearInt( INTVEC intvec ){ INT reg; if ( intvec >= (INTVEC)IV_FPGA1(0) ) { /* FPGA */ intvec -= (INTVEC)IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_STR1: IRQ_STR2; out_b(reg, ~(0x01U << (intvec & 0x00000007U))); intvec = (INTVEC)IV_GPA(7); } /* GPIO */ intvec -= (INTVEC)IV_GPA(0); reg = ISR_A + ((INT)(intvec >> 5) * 0x100); out_w(reg, 1 << (intvec & 0x0000001fU));}/* * Check interrupt request * Check interrupt request specified by 'intvec'. * If interrupt request occurs, returns TRUE (nonzero). */EXPORT BOOL CheckInt( INTVEC intvec ){ INT reg; if ( intvec < (INTVEC)IV_FPGA1(0) ) { if ( intvec < (INTVEC)IV_GPA(0) ) { /* IRQ */ intvec -= (INTVEC)IV_IRQ(0); reg = NIPNDL - ((INT)(intvec >> 5) * 4); } else { /* GPIO */ intvec -= (INTVEC)IV_GPA(0); reg = ISR_A + ((INT)(intvec >> 5) * 0x100); } return (BOOL)((in_w(reg) >> (intvec & 0x0000001fU)) & 0x00000001U); } else { /* FPGA */ intvec -= (INTVEC)IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_STR1: IRQ_STR2; return (BOOL)((in_b(reg) >> (intvec & 0x00000007U)) & 0x00000001U); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -