home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / mips / kernel / irq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-31  |  6.7 KB  |  304 lines

  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)
  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)
  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)
  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)
  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)
  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 *),
  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)
  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) { }
  230.  
  231. unsigned int probe_irq_on (void)
  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)
  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)
  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. }
  304.