root/arch/mips/kernel/irq.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. disable_irq
  2. enable_irq
  3. get_irq_list
  4. do_IRQ
  5. do_fast_IRQ
  6. request_irq
  7. free_irq
  8. no_action
  9. probe_irq_on
  10. probe_irq_off
  11. init_IRQ

   1 /*
   2  *      linux/arch/mips/kernel/irq.c
   3  *
   4  *      Copyright (C) 1992 Linus Torvalds
   5  *
   6  * This file contains the code used by various IRQ handling routines:
   7  * asking for different IRQ's should be done through these routines
   8  * instead of just grabbing them. Thus setups with different IRQ numbers
   9  * shouldn't result in any weird surprises, and installing new handlers
  10  * should be easier.
  11  */
  12 
  13 /*
  14  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  15  * Naturally it's not a 1:1 relation, but there are similarities.
  16  */
  17 
  18 #include <linux/ptrace.h>
  19 #include <linux/errno.h>
  20 #include <linux/kernel_stat.h>
  21 #include <linux/signal.h>
  22 #include <linux/sched.h>
  23 #include <linux/interrupt.h>
  24 #include <linux/timex.h>
  25 
  26 #include <asm/system.h>
  27 #include <asm/io.h>
  28 #include <asm/irq.h>
  29 #include <asm/bitops.h>
  30 
  31 unsigned char cache_21 = 0xff;
  32 unsigned char cache_A1 = 0xff;
  33 
  34 unsigned long spurious_count = 0;
  35 
  36 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         unsigned long flags;
  39         unsigned char mask;
  40 
  41         mask = 1 << (irq_nr & 7);
  42         save_flags(flags);
  43         if (irq_nr < 8) {
  44                 cli();
  45                 cache_21 |= mask;
  46                 outb(cache_21,0x21);
  47                 restore_flags(flags);
  48                 return;
  49         }
  50         cli();
  51         cache_A1 |= mask;
  52         outb(cache_A1,0xA1);
  53         restore_flags(flags);
  54 }
  55 
  56 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         unsigned long flags;
  59         unsigned char mask;
  60 
  61         mask = ~(1 << (irq_nr & 7));
  62         save_flags(flags);
  63         if (irq_nr < 8) {
  64                 cli();
  65                 cache_21 &= mask;
  66                 outb(cache_21,0x21);
  67                 restore_flags(flags);
  68                 return;
  69         }
  70         cli();
  71         cache_A1 &= mask;
  72         outb(cache_A1,0xA1);
  73         restore_flags(flags);
  74 }
  75 
  76 /*
  77  * Pointers to the low-level handlers: first the general ones, then the
  78  * fast ones, then the bad ones.
  79  */
  80 extern void interrupt(void);
  81 extern void fast_interrupt(void);
  82 extern void bad_interrupt(void);
  83 
  84 /*
  85  * Initial irq handlers.
  86  */
  87 struct irqaction {
  88         void (*handler)(int, struct pt_regs *);
  89         unsigned long flags;
  90         unsigned long mask;
  91         const char *name;
  92 };
  93 
  94 static struct irqaction irq_action[16] = {
  95         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  96         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  97         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  98         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  99         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 100         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 101         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 102         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
 103 };
 104 
 105 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107         int i, len = 0;
 108         struct irqaction * action = irq_action;
 109 
 110         for (i = 0 ; i < 16 ; i++, action++) {
 111                 if (!action->handler)
 112                         continue;
 113                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
 114                         i, kstat.interrupts[i],
 115                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 116                         action->name);
 117         }
 118         return len;
 119 }
 120 
 121 /*
 122  * do_IRQ handles IRQ's that have been installed without the
 123  * SA_INTERRUPT flag: it uses the full signal-handling return
 124  * and runs with other interrupts enabled. All relatively slow
 125  * IRQ's should use this format: notably the keyboard/timer
 126  * routines.
 127  */
 128 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         struct irqaction * action = irq + irq_action;
 131 
 132         kstat.interrupts[irq]++;
 133         action->handler(irq, regs);
 134 }
 135 
 136 /*
 137  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 138  * stuff - the handler is also running with interrupts disabled unless
 139  * it explicitly enables them later.
 140  */
 141 asmlinkage void do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         struct irqaction * action = irq + irq_action;
 144 
 145         kstat.interrupts[irq]++;
 146         action->handler(irq, NULL);
 147 }
 148 
 149 #define SA_PROBE SA_ONESHOT
 150 
 151 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 152         unsigned long irqflags, const char * devname)
 153 {
 154         struct irqaction * action;
 155         unsigned long flags;
 156 
 157         if (irq > 15)
 158                 return -EINVAL;
 159         action = irq + irq_action;
 160         if (action->handler)
 161                 return -EBUSY;
 162         if (!handler)
 163                 return -EINVAL;
 164         save_flags(flags);
 165         cli();
 166         action->handler = handler;
 167         action->flags = irqflags;
 168         action->mask = 0;
 169         action->name = devname;
 170         if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
 171                 /*
 172                  * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
 173                  */
 174                 if (action->flags & SA_INTERRUPT)
 175                         set_intr_gate(irq,fast_interrupt);
 176                 else
 177                         set_intr_gate(irq,interrupt);
 178         }
 179         if (irq < 8) {
 180                 cache_21 &= ~(1<<irq);
 181                 outb(cache_21,0x21);
 182         } else {
 183                 cache_21 &= ~(1<<2);
 184                 cache_A1 &= ~(1<<(irq-8));
 185                 outb(cache_21,0x21);
 186                 outb(cache_A1,0xA1);
 187         }
 188         restore_flags(flags);
 189         return 0;
 190 }
 191 
 192 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         struct irqaction * action = irq + irq_action;
 195         unsigned long flags;
 196 
 197         if (irq > 15) {
 198                 printk("Trying to free IRQ%d\n",irq);
 199                 return;
 200         }
 201         if (!action->handler) {
 202                 printk("Trying to free free IRQ%d\n",irq);
 203                 return;
 204         }
 205         save_flags(flags);
 206         cli();
 207         if (irq < 8) {
 208                 cache_21 |= 1 << irq;
 209                 outb(cache_21,0x21);
 210         } else {
 211                 cache_A1 |= 1 << (irq-8);
 212                 outb(cache_A1,0xA1);
 213         }
 214         set_intr_gate(irq,bad_interrupt);
 215         action->handler = NULL;
 216         action->flags = 0;
 217         action->mask = 0;
 218         action->name = NULL;
 219         restore_flags(flags);
 220 }
 221 
 222 static void no_action(int cpl, struct pt_regs * regs) { }
     /* [previous][next][first][last][top][bottom][index][help] */
 223 
 224 unsigned int probe_irq_on (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         unsigned int i, irqs = 0, irqmask;
 227         unsigned long delay;
 228 
 229         /* first, snaffle up any unassigned irqs */
 230         for (i = 15; i > 0; i--) {
 231                 if (!request_irq(i, no_action, SA_PROBE, "probe")) {
 232                         enable_irq(i);
 233                         irqs |= (1 << i);
 234                 }
 235         }
 236 
 237         /* wait for spurious interrupts to mask themselves out again */
 238         for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
 239 
 240         /* now filter out any obviously spurious interrupts */
 241         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 242         for (i = 15; i > 0; i--) {
 243                 if (irqs & (1 << i) & irqmask) {
 244                         irqs ^= (1 << i);
 245                         free_irq(i);
 246                 }
 247         }
 248 #ifdef DEBUG
 249         printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 250 #endif
 251         return irqs;
 252 }
 253 
 254 int probe_irq_off (unsigned int irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 {
 256         unsigned int i, irqmask;
 257 
 258         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 259         for (i = 15; i > 0; i--) {
 260                 if (irqs & (1 << i)) {
 261                         free_irq(i);
 262                 }
 263         }
 264 #ifdef DEBUG
 265         printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 266 #endif
 267         irqs &= irqmask;
 268         if (!irqs)
 269                 return 0;
 270         i = ffz(~irqs);
 271         if (irqs != (irqs & (1 << i)))
 272                 i = -i;
 273         return i;
 274 }
 275 
 276 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 277 {
 278         int i;
 279 
 280         /* set the clock to 100 Hz */
 281         outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
 282         outb_p(LATCH & 0xff , 0x40);    /* LSB */
 283         outb(LATCH >> 8 , 0x40);        /* MSB */
 284         for (i = 0; i < 16 ; i++)
 285                 set_intr_gate(i, bad_interrupt);
 286         if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
 287                 printk("Unable to get IRQ2 for cascade\n");
 288 
 289         /* initialize the bottom half routines. */
 290         for (i = 0; i < 32; i++) {
 291                 bh_base[i].routine = NULL;
 292                 bh_base[i].data = NULL;
 293         }
 294         bh_active = 0;
 295         intr_count = 0;
 296 }

/* [previous][next][first][last][top][bottom][index][help] */