📄 ictrl.c
字号:
/* ictrl.c * * This routine installs and handles external interrupt vectors for * PowerPC 403 CPU built-in external interrupt controller * * Author: Thomas Doerfler <td@imd.m.isar.de> * * COPYRIGHT (c) 1998 by IMD, Puchheim, Germany * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file * for any purpose is hereby granted without fee, provided that * the above copyright notice and this notice appears in all * copies, and that the name of IMD not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * IMD makes no representations about the suitability * of this software for any purpose. * * Modifications for PPC405GP by Dennis Ehlin * */#include "ictrl.h"#include <rtems.h>#include <rtems/libio.h>#include <stdlib.h> /* for atexit() *//* * ISR vector table to dispatch external interrupts */ rtems_isr_entry ictrl_vector_table[PPC_IRQ_EXT_MAX];/* * * some utilities to access the EXI* registers * *//* * clear bits in EXISR that have a bit set in mask */#if defined(ppc405)RTEMS_INLINE_ROUTINE void clr_exisr(unsigned32 mask) { asm volatile ("mtdcr 0xC0,%0"::"r" (mask));/*EXISR*/} /* * get value of EXISR */RTEMS_INLINE_ROUTINE unsigned32 get_exisr(void) { unsigned32 val; asm volatile ("mfdcr %0,0xC0":"=r" (val));/*EXISR*/ return val; } /* * get value of EXIER */RTEMS_INLINE_ROUTINE unsigned32 get_exier(void) { unsigned32 val; asm volatile ("mfdcr %0,0xC2":"=r" (val));/*EXIER*/ return val; } /* * set value of EXIER */RTEMS_INLINE_ROUTINE void set_exier(unsigned32 val) { asm volatile ("mtdcr 0xC2,%0"::"r" (val));/*EXIER*/} #else /* not ppc405 */RTEMS_INLINE_ROUTINE void clr_exisr(unsigned32 mask) { asm volatile ("mtdcr 0x40,%0"::"r" (mask));/*EXISR*/} /* * get value of EXISR */RTEMS_INLINE_ROUTINE unsigned32 get_exisr(void) { unsigned32 val; asm volatile ("mfdcr %0,0x40":"=r" (val));/*EXISR*/ return val; } /* * get value of EXIER */RTEMS_INLINE_ROUTINE unsigned32 get_exier(void) { unsigned32 val; asm volatile ("mfdcr %0,0x42":"=r" (val));/*EXIER*/ return val; } /* * set value of EXIER */RTEMS_INLINE_ROUTINE void set_exier(unsigned32 val) { asm volatile ("mtdcr 0x42,%0"::"r" (val));/*EXIER*/} #endif /* ppc405 *//* * enable an external interrupt, make this interrupt consistent */RTEMS_INLINE_ROUTINE void enable_ext_irq( unsigned32 mask){ unsigned32 isrlvl; _CPU_ISR_Disable(isrlvl); set_exier(get_exier() | ((mask)&PPC_EXI_MASK)); _CPU_ISR_Enable(isrlvl);}/* * disable an external interrupt, make this interrupt consistent */RTEMS_INLINE_ROUTINE void disable_ext_irq( unsigned32 mask){ unsigned32 isrlvl; _CPU_ISR_Disable(isrlvl); set_exier(get_exier() & ~(mask) & PPC_EXI_MASK); _CPU_ISR_Enable(isrlvl);}/* * * this function is called, when a external interrupt is present and * enabled but there is no handler installed. It will clear * the corresponding enable bits and call the spurious handler * present in the CPU Configuration Table, if any. * */void ictrl_spurious_handler(unsigned32 spurious_mask, CPU_Interrupt_frame *cpu_frame){ int v; for (v=0; v < PPC_IRQ_EXT_MAX; v++) { if (VEC_TO_EXMSK(v) & spurious_mask) { clr_exisr(VEC_TO_EXMSK(v)); disable_ext_irq(VEC_TO_EXMSK(v));#if 0 printf("spurious external interrupt: %d at pc 0x%x; disabling\n", vector, cpu_frame->Interrupt.pcoqfront);#endif if (rtems_cpu_configuration_get_spurious_handler()) { rtems_cpu_configuration_get_spurious_handler()(v + PPC_IRQ_EXT_BASE,cpu_frame); } } }}/* * ISR Handler: this is called from the primary exception dispatcher */ voidictrl_isr(rtems_vector_number vector,CPU_Interrupt_frame *cpu_frame){ unsigned32 istat, mask, global_vec; int exvec; rtems_isr_entry handler; istat = get_exisr() & get_exier() & PPC_EXI_MASK; /* FIXME: this may be speeded up using cntlzw instruction */ for (exvec = 0;exvec < PPC_IRQ_EXT_MAX;exvec++) { mask = VEC_TO_EXMSK(exvec); if (0 != (istat & mask)) { /*clr_exisr(mask); too early to ack*/ handler = ictrl_vector_table[exvec]; if (handler) { istat &= ~mask; global_vec = exvec + PPC_IRQ_EXT_BASE; (handler)(global_vec); } clr_exisr(mask);/* now we can ack*/ } } if (istat != 0) { /* anything left? then we have a spurious interrupt */ ictrl_spurious_handler(istat,cpu_frame); }}/* * * the following functions form the user interface * *//* * * install a user vector for one of the external interrupt sources * */ rtems_status_codeictrl_set_vector(rtems_isr_entry new_handler, unsigned32 vector, rtems_isr_entry *old_handler){ /* * We put the actual user ISR address in 'ictrl_vector_table'. This will * be used by the _ictrl_isr so the user gets control. */ /* check for valid vector range */ if ((vector >= PPC_IRQ_EXT_BASE) && (vector < PPC_IRQ_EXT_BASE + PPC_IRQ_EXT_MAX)) { /* return old handler entry */ *old_handler = ictrl_vector_table[vector - PPC_IRQ_EXT_BASE]; if (new_handler != NULL) { /* store handler function... */ ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = new_handler; /* then enable it in EXIER register */ enable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE)); } else { /* new_handler == NULL */ /* then disable it in EXIER register */ disable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE)); ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = NULL; } return RTEMS_SUCCESSFUL; } else { return RTEMS_INVALID_NUMBER; }}/* * Called via atexit() * deactivate the interrupt controller */voidictrl_exit(void){ /* mark them all unused */ disable_ext_irq(~0); clr_exisr(~0); }/* * activate the interrupt controller */rtems_status_code ictrl_init(void){ proc_ptr dummy; /* mark them all unused */ disable_ext_irq(~0); clr_exisr(~0); /* install the external interrupt handler */ _CPU_ISR_install_vector(PPC_IRQ_EXTERNAL, ictrl_isr, &dummy); atexit(ictrl_exit); return RTEMS_SUCCESSFUL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -