home *** CD-ROM | disk | FTP | other *** search
- /*
- * ints.c -- 680x0 Linux general interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- */
-
- #include <asm/system.h>
-
- #include <linux/types.h>
- #include <linux/config.h>
- #include <linux/interrupt.h>
- #include <linux/sched.h>
-
- /*
- * ++roman: The number of possible interrupts is 7 only if there are no
- * non-autovec ints. But e.g. the Atari uses a lot of them. So I defined
- * a constant NUM_INT_SOURCES in interrupt.h that gives the total number of
- * possible interrputs. A constant FIRST_NONAUTO_VEC is defined also.
- */
-
- /* list is accessed 0-6 for IRQs 1-7 */
- static isr_node_t *isr_list[NUM_INT_SOURCES];
-
- /* The number of spurious interrupts */
- volatile unsigned long num_spurious;
-
- volatile unsigned long intr_count = 0;
- unsigned long bh_active = 0;
- unsigned long bh_mask = 0xFFFFFFFF;
- struct bh_struct bh_base[32];
-
- /*
- * void init_INTS(void)
- *
- * Parameters: None
- *
- * Returns: Nothing
- *
- * This function should be called during kernel startup to initialize
- * the IRQ handling routines.
- */
-
- void init_INTS(void)
- {
- int i;
-
- /* initialize the ISR list pointers */
- for (i = 0; i < NUM_INT_SOURCES; i++)
- isr_list[i] = NULL;
-
- num_spurious = 0;
-
- /* intialize the bottom half routines. */
- for (i = 0; i < 32; i++) {
- bh_base[i].routine = NULL;
- bh_base[i].data = NULL;
- }
- bh_active = 0;
- intr_count = 0;
-
- mach_init_INTS ();
-
- /* enable CPU interrupts */
- sti();
- }
-
- /*
- * do_bottom_half() runs at normal kernel priority: all interrupts
- * enabled. do_bottom_half() is atomic with respect to itself: a
- * bottom_half handler need not be re-entrant.
- */
- asmlinkage void do_bottom_half(void)
- {
- unsigned long active;
- unsigned long mask, left;
- struct bh_struct *bh;
-
- bh = bh_base;
- active = bh_active & bh_mask;
-
- for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
- if (mask & active) {
- void (*fn)(void *);
- bh_active &= ~mask;
- fn = bh->routine;
- if (!fn)
- goto bad_bh;
- fn(bh->data);
- }
- }
- return;
- bad_bh:
- printk ("irq.c:bad bottom half entry\n");
- }
-
- void insert_isr (isr_node_t **listp, isr_node_t *node)
- {
- unsigned long spl;
- isr_node_t *cur, *last = NULL;
-
- save_flags(spl);
- cli();
-
- cur = *listp;
-
- if (!cur || cur->pri > node->pri) {
- if (cur)
- node->next = cur;
- *listp = node;
- restore_flags (spl);
- return;
- }
-
- while (cur->next && cur->pri <= node->pri)
- {
- last = cur;
- cur = cur->next;
- }
-
- if (!cur->next) {
- cur->next = node;
- } else {
- node->next = cur;
- last->next = node;
- }
-
- restore_flags(spl);
- }
-
- isr_node_t *new_isr_node(void)
- {
- isr_node_t *np;
-
- static isr_node_t nodes[32];
- static int curnode = 0;
-
- np = &nodes[curnode++];
- if (curnode >= sizeof(nodes)/sizeof(nodes[0]))
- panic ("new_isr_node: out of nodes");
-
- return np;
- }
-
- int add_isr (unsigned long source, isrfunc isr, int pri, void *data)
- {
- isr_node_t *p;
-
- if (source & IRQ_MACHSPEC)
- {
- return mach_add_isr (source, isr, pri, data);
- }
-
- if (source < IRQ1 || source > NUM_INT_SOURCES)
- panic ("add_isr: Incorrect IRQ source");
-
- p = new_isr_node();
- p->isr = isr;
- p->pri = pri;
- p->data = data;
- p->next = NULL;
-
- insert_isr (&isr_list[source-1], p);
-
- return 1;
- }
-
- void call_isr_list(isr_node_t *p, struct intframe *fp)
- {
- while (p) {
- p->isr (fp, p->data);
- p = p->next;
- }
- }
-
- #define DEBUG_LOST_INT_DECR
-
- asmlinkage void process_int(int level, struct intframe *fp)
- {
- #ifdef DEBUG_LOST_INT_DECR
- int cnt = intr_count;
- static int last_spur = 0;
- #endif
-
- #if NUM_INT_SOURCES > 7
- /* Possibility for non-autovec ints! */
- if (level < 8)
- /* autovector int */
- call_isr_list (isr_list[level-1], fp);
- else
- /* non-autovec */
- call_isr_list (isr_list[level-FIRST_NONAUTO_VEC+24+7], fp);
- #else
- call_isr_list (isr_list[level-1], fp);
- #endif
-
- #ifdef DEBUG_LOST_INT_DECR
- if (cnt != intr_count) {
- printk( "intr_count=%d != old_cnt=%d; resetted\n", (int)intr_count, cnt );
- intr_count = cnt;
- }
- if (num_spurious != last_spur) {
- printk( "num_spurious is now %lu\n", num_spurious );
- last_spur = num_spurious;
- }
- #endif
- }
-
-