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 / i386 / kernel / irq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-02  |  9.1 KB  |  367 lines

  1. /*
  2.  *    linux/arch/i386/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/ioport.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/timex.h>
  26.  
  27. #include <asm/system.h>
  28. #include <asm/io.h>
  29. #include <asm/irq.h>
  30. #include <asm/bitops.h>
  31.  
  32. #define CR0_NE 32
  33.  
  34. static unsigned char cache_21 = 0xff;
  35. static unsigned char cache_A1 = 0xff;
  36.  
  37. void disable_irq(unsigned int irq_nr)
  38. {
  39.     unsigned long flags;
  40.     unsigned char mask;
  41.  
  42.     mask = 1 << (irq_nr & 7);
  43.     save_flags(flags);
  44.     if (irq_nr < 8) {
  45.         cli();
  46.         cache_21 |= mask;
  47.         outb(cache_21,0x21);
  48.         restore_flags(flags);
  49.         return;
  50.     }
  51.     cli();
  52.     cache_A1 |= mask;
  53.     outb(cache_A1,0xA1);
  54.     restore_flags(flags);
  55. }
  56.  
  57. void enable_irq(unsigned int irq_nr)
  58. {
  59.     unsigned long flags;
  60.     unsigned char mask;
  61.  
  62.     mask = ~(1 << (irq_nr & 7));
  63.     save_flags(flags);
  64.     if (irq_nr < 8) {
  65.         cli();
  66.         cache_21 &= mask;
  67.         outb(cache_21,0x21);
  68.         restore_flags(flags);
  69.         return;
  70.     }
  71.     cli();
  72.     cache_A1 &= mask;
  73.     outb(cache_A1,0xA1);
  74.     restore_flags(flags);
  75. }
  76.  
  77. /*
  78.  * This builds up the IRQ handler stubs using some ugly macros in irq.h
  79.  *
  80.  * These macros create the low-level assembly IRQ routines that do all
  81.  * the operations that are needed to keep the AT interrupt-controller
  82.  * happy. They are also written to be fast - and to disable interrupts
  83.  * as little as humanly possible.
  84.  *
  85.  * NOTE! These macros expand to three different handlers for each line: one
  86.  * complete handler that does all the fancy stuff (including signal handling),
  87.  * and one fast handler that is meant for simple IRQ's that want to be
  88.  * atomic. The specific handler is chosen depending on the SA_INTERRUPT
  89.  * flag when installing a handler. Finally, one "bad interrupt" handler, that
  90.  * is used when no handler is present.
  91.  */
  92. BUILD_IRQ(FIRST,0,0x01)
  93. BUILD_IRQ(FIRST,1,0x02)
  94. BUILD_IRQ(FIRST,2,0x04)
  95. BUILD_IRQ(FIRST,3,0x08)
  96. BUILD_IRQ(FIRST,4,0x10)
  97. BUILD_IRQ(FIRST,5,0x20)
  98. BUILD_IRQ(FIRST,6,0x40)
  99. BUILD_IRQ(FIRST,7,0x80)
  100. BUILD_IRQ(SECOND,8,0x01)
  101. BUILD_IRQ(SECOND,9,0x02)
  102. BUILD_IRQ(SECOND,10,0x04)
  103. BUILD_IRQ(SECOND,11,0x08)
  104. BUILD_IRQ(SECOND,12,0x10)
  105. BUILD_IRQ(SECOND,13,0x20)
  106. BUILD_IRQ(SECOND,14,0x40)
  107. BUILD_IRQ(SECOND,15,0x80)
  108.  
  109. /*
  110.  * Pointers to the low-level handlers: first the general ones, then the
  111.  * fast ones, then the bad ones.
  112.  */
  113. static void (*interrupt[16])(void) = {
  114.     IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
  115.     IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
  116.     IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
  117.     IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
  118. };
  119.  
  120. static void (*fast_interrupt[16])(void) = {
  121.     fast_IRQ0_interrupt, fast_IRQ1_interrupt,
  122.     fast_IRQ2_interrupt, fast_IRQ3_interrupt,
  123.     fast_IRQ4_interrupt, fast_IRQ5_interrupt,
  124.     fast_IRQ6_interrupt, fast_IRQ7_interrupt,
  125.     fast_IRQ8_interrupt, fast_IRQ9_interrupt,
  126.     fast_IRQ10_interrupt, fast_IRQ11_interrupt,
  127.     fast_IRQ12_interrupt, fast_IRQ13_interrupt,
  128.     fast_IRQ14_interrupt, fast_IRQ15_interrupt
  129. };
  130.  
  131. static void (*bad_interrupt[16])(void) = {
  132.     bad_IRQ0_interrupt, bad_IRQ1_interrupt,
  133.     bad_IRQ2_interrupt, bad_IRQ3_interrupt,
  134.     bad_IRQ4_interrupt, bad_IRQ5_interrupt,
  135.     bad_IRQ6_interrupt, bad_IRQ7_interrupt,
  136.     bad_IRQ8_interrupt, bad_IRQ9_interrupt,
  137.     bad_IRQ10_interrupt, bad_IRQ11_interrupt,
  138.     bad_IRQ12_interrupt, bad_IRQ13_interrupt,
  139.     bad_IRQ14_interrupt, bad_IRQ15_interrupt
  140. };
  141.  
  142. /*
  143.  * Initial irq handlers.
  144.  */
  145. struct irqaction {
  146.     void (*handler)(int, struct pt_regs *);
  147.     unsigned long flags;
  148.     unsigned long mask;
  149.     const char *name;
  150. };
  151.  
  152. static struct irqaction irq_action[16] = {
  153.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  154.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  155.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  156.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  157.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  158.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  159.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  160.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
  161. };
  162.  
  163. int get_irq_list(char *buf)
  164. {
  165.     int i, len = 0;
  166.     struct irqaction * action = irq_action;
  167.  
  168.     for (i = 0 ; i < 16 ; i++, action++) {
  169.         if (!action->handler)
  170.             continue;
  171.         len += sprintf(buf+len, "%2d: %8d %c %s\n",
  172.             i, kstat.interrupts[i],
  173.             (action->flags & SA_INTERRUPT) ? '+' : ' ',
  174.             action->name);
  175.     }
  176.     return len;
  177. }
  178.  
  179. /*
  180.  * do_IRQ handles IRQ's that have been installed without the
  181.  * SA_INTERRUPT flag: it uses the full signal-handling return
  182.  * and runs with other interrupts enabled. All relatively slow
  183.  * IRQ's should use this format: notably the keyboard/timer
  184.  * routines.
  185.  */
  186. asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
  187. {
  188.     struct irqaction * action = irq + irq_action;
  189.  
  190.     kstat.interrupts[irq]++;
  191.     action->handler(irq, regs);
  192. }
  193.  
  194. /*
  195.  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
  196.  * stuff - the handler is also running with interrupts disabled unless
  197.  * it explicitly enables them later.
  198.  */
  199. asmlinkage void do_fast_IRQ(int irq)
  200. {
  201.     struct irqaction * action = irq + irq_action;
  202.  
  203.     kstat.interrupts[irq]++;
  204.     action->handler(irq, NULL);
  205. }
  206.  
  207. #define SA_PROBE SA_ONESHOT
  208.  
  209. int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
  210.     unsigned long irqflags, const char * devname)
  211. {
  212.     struct irqaction * action;
  213.     unsigned long flags;
  214.  
  215.     if (irq > 15)
  216.         return -EINVAL;
  217.     action = irq + irq_action;
  218.     if (action->handler)
  219.         return -EBUSY;
  220.     if (!handler)
  221.         return -EINVAL;
  222.     save_flags(flags);
  223.     cli();
  224.     action->handler = handler;
  225.     action->flags = irqflags;
  226.     action->mask = 0;
  227.     action->name = devname;
  228.     if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
  229.         if (action->flags & SA_INTERRUPT)
  230.             set_intr_gate(0x20+irq,fast_interrupt[irq]);
  231.         else
  232.             set_intr_gate(0x20+irq,interrupt[irq]);
  233.     }
  234.     if (irq < 8) {
  235.         cache_21 &= ~(1<<irq);
  236.         outb(cache_21,0x21);
  237.     } else {
  238.         cache_21 &= ~(1<<2);
  239.         cache_A1 &= ~(1<<(irq-8));
  240.         outb(cache_21,0x21);
  241.         outb(cache_A1,0xA1);
  242.     }
  243.     restore_flags(flags);
  244.     return 0;
  245. }
  246.         
  247. void free_irq(unsigned int irq)
  248. {
  249.     struct irqaction * action = irq + irq_action;
  250.     unsigned long flags;
  251.  
  252.     if (irq > 15) {
  253.         printk("Trying to free IRQ%d\n",irq);
  254.         return;
  255.     }
  256.     if (!action->handler) {
  257.         printk("Trying to free free IRQ%d\n",irq);
  258.         return;
  259.     }
  260.     save_flags(flags);
  261.     cli();
  262.     if (irq < 8) {
  263.         cache_21 |= 1 << irq;
  264.         outb(cache_21,0x21);
  265.     } else {
  266.         cache_A1 |= 1 << (irq-8);
  267.         outb(cache_A1,0xA1);
  268.     }
  269.     set_intr_gate(0x20+irq,bad_interrupt[irq]);
  270.     action->handler = NULL;
  271.     action->flags = 0;
  272.     action->mask = 0;
  273.     action->name = NULL;
  274.     restore_flags(flags);
  275. }
  276.  
  277. /*
  278.  * Note that on a 486, we don't want to do a SIGFPE on a irq13
  279.  * as the irq is unreliable, and exception 16 works correctly
  280.  * (ie as explained in the intel literature). On a 386, you
  281.  * can't use exception 16 due to bad IBM design, so we have to
  282.  * rely on the less exact irq13.
  283.  *
  284.  * Careful.. Not only is IRQ13 unreliable, but it is also
  285.  * leads to races. IBM designers who came up with it should
  286.  * be shot.
  287.  */
  288. static void math_error_irq(int cpl, struct pt_regs *regs)
  289. {
  290.     outb(0,0xF0);
  291.     if (ignore_irq13 || !hard_math)
  292.         return;
  293.     math_error();
  294. }
  295.  
  296. static void no_action(int cpl, struct pt_regs * regs) { }
  297.  
  298. unsigned int probe_irq_on (void)
  299. {
  300.     unsigned int i, irqs = 0, irqmask;
  301.     unsigned long delay;
  302.  
  303.     /* first, snaffle up any unassigned irqs */
  304.     for (i = 15; i > 0; i--) {
  305.         if (!request_irq(i, no_action, SA_PROBE, "probe")) {
  306.             enable_irq(i);
  307.             irqs |= (1 << i);
  308.         }
  309.     }
  310.  
  311.     /* wait for spurious interrupts to mask themselves out again */
  312.     for (delay = jiffies + 2; delay > jiffies; );    /* min 10ms delay */
  313.  
  314.     /* now filter out any obviously spurious interrupts */
  315.     irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
  316.     for (i = 15; i > 0; i--) {
  317.         if (irqs & (1 << i) & irqmask) {
  318.             irqs ^= (1 << i);
  319.             free_irq(i);
  320.         }
  321.     }
  322. #ifdef DEBUG
  323.     printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
  324. #endif
  325.     return irqs;
  326. }
  327.  
  328. int probe_irq_off (unsigned int irqs)
  329. {
  330.     unsigned int i, irqmask;
  331.  
  332.     irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
  333.     for (i = 15; i > 0; i--) {
  334.         if (irqs & (1 << i)) {
  335.             free_irq(i);
  336.         }
  337.     }
  338. #ifdef DEBUG
  339.     printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
  340. #endif
  341.     irqs &= irqmask;
  342.     if (!irqs)
  343.         return 0;
  344.     i = ffz(~irqs);
  345.     if (irqs != (irqs & (1 << i)))
  346.         i = -i;
  347.     return i;
  348. }
  349.  
  350. void init_IRQ(void)
  351. {
  352.     int i;
  353.  
  354.     /* set the clock to 100 Hz */
  355.     outb_p(0x34,0x43);        /* binary, mode 2, LSB/MSB, ch 0 */
  356.     outb_p(LATCH & 0xff , 0x40);    /* LSB */
  357.     outb(LATCH >> 8 , 0x40);    /* MSB */
  358.     for (i = 0; i < 16 ; i++)
  359.         set_intr_gate(0x20+i,bad_interrupt[i]);
  360.     if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
  361.         printk("Unable to get IRQ2 for cascade\n");
  362.     if (request_irq(13,math_error_irq, 0, "math error"))
  363.         printk("Unable to get IRQ13 for math-error handler\n");
  364.     request_region(0x20,0x20,"pic1");
  365.     request_region(0xa0,0x20,"pic2");
  366.