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

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