📄 int.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.01.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* * @(#)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) & 0x1f; if ( old == 0x1f ) 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 < IV_GPA(0) ) { /* IRQ */ intvec -= IV_IRQ(0); reg = INTTYPEL - ((intvec >> 5) * 4); msk = 1 << (intvec & 31); set = ( (mode & IM_FIQ) != 0 )? msk: 0; _DI(imask); out_w(reg, (in_w(reg) & ~msk) | set); _EI(imask); } else { /* GPIO */ intvec -= IV_GPA(0); reg = ICR1_A + ((intvec >> 5) * 0x100); reg += (intvec & 0x10) >> (4 - 2); set = (intvec & 15) * 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 < IV_GPA(0) ) { /* IRQ */ intvec -= IV_IRQ(0); reg = NIPRIORITY0 - ((intvec >> 3) * 4); num = (intvec & 7) * 4; _DI(imask); out_w(reg, (in_w(reg) & ~(15 << num)) | (level << num)); out_w(INTENNUM, intvec); _EI(imask); } else if ( intvec < IV_FPGA1(0) ) { /* GPIO */ intvec -= IV_GPA(0); reg = IMR_A + ((intvec >> 5) * 0x100); num = intvec & 31; _DI(imask); out_w(reg, in_w(reg) | (1 << num)); _EI(imask); } else { /* FPGA */ intvec -= IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_MASK1: IRQ_MASK2; num = intvec & 7; _DI(imask); out_b(reg, in_b(reg) | (1 << 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 < IV_GPA(0) ) { /* IRQ */ intvec -= IV_IRQ(0); out_w(INTDISNUM, intvec); } else if ( intvec < IV_FPGA1(0) ) { /* GPIO */ intvec -= IV_GPA(0); reg = IMR_A + ((intvec >> 5) * 0x100); num = intvec & 31; _DI(imask); out_w(reg, in_w(reg) & ~(1 << num)); _EI(imask); } else { /* FPGA */ intvec -= IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_MASK1: IRQ_MASK2; num = intvec & 7; _DI(imask); out_b(reg, in_b(reg) & ~(1 << 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 >= IV_FPGA1(0) ) { /* FPGA */ intvec -= IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_STR1: IRQ_STR2; out_b(reg, ~(1 << (intvec & 7))); intvec = IV_GPA(7); } /* GPIO */ intvec -= IV_GPA(0); reg = ISR_A + ((intvec >> 5) * 0x100); out_w(reg, 1 << (intvec & 31));}/* * 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 < IV_FPGA1(0) ) { if ( intvec < IV_GPA(0) ) { /* IRQ */ intvec -= IV_IRQ(0); reg = NIPNDL - ((intvec >> 5) * 4); } else { /* GPIO */ intvec -= IV_GPA(0); reg = ISR_A + ((intvec >> 5) * 0x100); } return (in_w(reg) >> (intvec & 31)) & 1; } else { /* FPGA */ intvec -= IV_FPGA1(0); reg = ( intvec < 8 )? IRQ_STR1: IRQ_STR2; return (in_b(reg) >> (intvec & 7)) & 1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -