i8259.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Code to handle x86 style IRQs plus some generic interrupt stuff.
  7.  *
  8.  * Copyright (C) 1992 Linus Torvalds
  9.  * Copyright (C) 1994 - 2000 Ralf Baechle
  10.  */
  11. #include <linux/delay.h>
  12. #include <linux/init.h>
  13. #include <linux/ioport.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/kernel.h>
  16. #include <linux/spinlock.h>
  17. #include <asm/io.h>
  18. void enable_8259A_irq(unsigned int irq);
  19. void disable_8259A_irq(unsigned int irq);
  20. /*
  21.  * This is the 'legacy' 8259A Programmable Interrupt Controller,
  22.  * present in the majority of PC/AT boxes.
  23.  * plus some generic x86 specific things if generic specifics makes
  24.  * any sense at all.
  25.  * this file should become arch/i386/kernel/irq.c when the old irq.c
  26.  * moves to arch independent land
  27.  */
  28. static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
  29. static void end_8259A_irq (unsigned int irq)
  30. {
  31. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  32. enable_8259A_irq(irq);
  33. }
  34. #define shutdown_8259A_irq disable_8259A_irq
  35. void mask_and_ack_8259A(unsigned int);
  36. static unsigned int startup_8259A_irq(unsigned int irq)
  37. {
  38. enable_8259A_irq(irq);
  39. return 0; /* never anything pending */
  40. }
  41. static struct hw_interrupt_type i8259A_irq_type = {
  42. "XT-PIC",
  43. startup_8259A_irq,
  44. shutdown_8259A_irq,
  45. enable_8259A_irq,
  46. disable_8259A_irq,
  47. mask_and_ack_8259A,
  48. end_8259A_irq,
  49. NULL
  50. };
  51. /*
  52.  * 8259A PIC functions to handle ISA devices:
  53.  */
  54. /*
  55.  * This contains the irq mask for both 8259A irq controllers,
  56.  */
  57. static unsigned int cached_irq_mask = 0xffff;
  58. #define cached_21 (cached_irq_mask)
  59. #define cached_A1 (cached_irq_mask >> 8)
  60. void disable_8259A_irq(unsigned int irq)
  61. {
  62. unsigned int mask = 1 << irq;
  63. unsigned long flags;
  64. spin_lock_irqsave(&i8259A_lock, flags);
  65. cached_irq_mask |= mask;
  66. if (irq & 8)
  67. outb(cached_A1,0xA1);
  68. else
  69. outb(cached_21,0x21);
  70. spin_unlock_irqrestore(&i8259A_lock, flags);
  71. }
  72. void enable_8259A_irq(unsigned int irq)
  73. {
  74. unsigned int mask = ~(1 << irq);
  75. unsigned long flags;
  76. spin_lock_irqsave(&i8259A_lock, flags);
  77. cached_irq_mask &= mask;
  78. if (irq & 8)
  79. outb(cached_A1,0xA1);
  80. else
  81. outb(cached_21,0x21);
  82. spin_unlock_irqrestore(&i8259A_lock, flags);
  83. }
  84. int i8259A_irq_pending(unsigned int irq)
  85. {
  86. unsigned int mask = 1 << irq;
  87. unsigned long flags;
  88. int ret;
  89. spin_lock_irqsave(&i8259A_lock, flags);
  90. if (irq < 8)
  91. ret = inb(0x20) & mask;
  92. else
  93. ret = inb(0xA0) & (mask >> 8);
  94. spin_unlock_irqrestore(&i8259A_lock, flags);
  95. return ret;
  96. }
  97. void make_8259A_irq(unsigned int irq)
  98. {
  99. disable_irq_nosync(irq);
  100. irq_desc[irq].handler = &i8259A_irq_type;
  101. enable_irq(irq);
  102. }
  103. /*
  104.  * This function assumes to be called rarely. Switching between
  105.  * 8259A registers is slow.
  106.  * This has to be protected by the irq controller spinlock
  107.  * before being called.
  108.  */
  109. static inline int i8259A_irq_real(unsigned int irq)
  110. {
  111. int value;
  112. int irqmask = 1 << irq;
  113. if (irq < 8) {
  114. outb(0x0B,0x20); /* ISR register */
  115. value = inb(0x20) & irqmask;
  116. outb(0x0A,0x20); /* back to the IRR register */
  117. return value;
  118. }
  119. outb(0x0B,0xA0); /* ISR register */
  120. value = inb(0xA0) & (irqmask >> 8);
  121. outb(0x0A,0xA0); /* back to the IRR register */
  122. return value;
  123. }
  124. /*
  125.  * Careful! The 8259A is a fragile beast, it pretty
  126.  * much _has_ to be done exactly like this (mask it
  127.  * first, _then_ send the EOI, and the order of EOI
  128.  * to the two 8259s is important!
  129.  */
  130. void mask_and_ack_8259A(unsigned int irq)
  131. {
  132. unsigned int irqmask = 1 << irq;
  133. unsigned long flags;
  134. spin_lock_irqsave(&i8259A_lock, flags);
  135. /*
  136.  * Lightweight spurious IRQ detection. We do not want to overdo
  137.  * spurious IRQ handling - it's usually a sign of hardware problems, so
  138.  * we only do the checks we can do without slowing down good hardware
  139.  * nnecesserily.
  140.  *
  141.  * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting
  142.  * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A.
  143.  * Thus we can check spurious 8259A IRQs without doing the quite slow
  144.  * i8259A_irq_real() call for every IRQ.  This does not cover 100% of
  145.  * spurious interrupts, but should be enough to warn the user that
  146.  * there is something bad going on ...
  147.  */
  148. if (cached_irq_mask & irqmask)
  149. goto spurious_8259A_irq;
  150. cached_irq_mask |= irqmask;
  151. handle_real_irq:
  152. if (irq & 8) {
  153. inb(0xA1); /* DUMMY - (do we need this?) */
  154. outb(cached_A1,0xA1);
  155. outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
  156. outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
  157. } else {
  158. inb(0x21); /* DUMMY - (do we need this?) */
  159. outb(cached_21,0x21);
  160. outb(0x60+irq,0x20); /* 'Specific EOI' to master */
  161. }
  162. spin_unlock_irqrestore(&i8259A_lock, flags);
  163. return;
  164. spurious_8259A_irq:
  165. /*
  166.  * this is the slow path - should happen rarely.
  167.  */
  168. if (i8259A_irq_real(irq))
  169. /*
  170.  * oops, the IRQ _is_ in service according to the
  171.  * 8259A - not spurious, go handle it.
  172.  */
  173. goto handle_real_irq;
  174. {
  175. static int spurious_irq_mask = 0;
  176. /*
  177.  * At this point we can be sure the IRQ is spurious,
  178.  * lets ACK and report it. [once per IRQ]
  179.  */
  180. if (!(spurious_irq_mask & irqmask)) {
  181. printk("spurious 8259A interrupt: IRQ%d.n", irq);
  182. spurious_irq_mask |= irqmask;
  183. }
  184. atomic_inc(&irq_err_count);
  185. /*
  186.  * Theoretically we do not have to handle this IRQ,
  187.  * but in Linux this does not cause problems and is
  188.  * simpler for us.
  189.  */
  190. goto handle_real_irq;
  191. }
  192. }
  193. void __init init_8259A(int auto_eoi)
  194. {
  195. unsigned long flags;
  196. spin_lock_irqsave(&i8259A_lock, flags);
  197. outb(0xff, 0x21); /* mask all of 8259A-1 */
  198. outb(0xff, 0xA1); /* mask all of 8259A-2 */
  199. /*
  200.  * outb_p - this has to work on a wide range of PC hardware.
  201.  */
  202. outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */
  203. outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */
  204. outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */
  205. if (auto_eoi)
  206. outb_p(0x03, 0x21); /* master does Auto EOI */
  207. else
  208. outb_p(0x01, 0x21); /* master expects normal EOI */
  209. outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */
  210. outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */
  211. outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */
  212. outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode
  213.     is to be investigated) */
  214. if (auto_eoi)
  215. /*
  216.  * in AEOI mode we just have to mask the interrupt
  217.  * when acking.
  218.  */
  219. i8259A_irq_type.ack = disable_8259A_irq;
  220. else
  221. i8259A_irq_type.ack = mask_and_ack_8259A;
  222. udelay(100); /* wait for 8259A to initialize */
  223. outb(cached_21, 0x21); /* restore master IRQ mask */
  224. outb(cached_A1, 0xA1); /* restore slave IRQ mask */
  225. spin_unlock_irqrestore(&i8259A_lock, flags);
  226. }
  227. asmlinkage void i8259_do_irq(int irq, struct pt_regs regs)
  228. {
  229. panic("i8259_do_irq: I want to be implemented");
  230. }
  231. /*
  232.  * IRQ2 is cascade interrupt to second interrupt controller
  233.  */
  234. static struct irqaction irq2 = {
  235. no_action, 0, 0, "cascade", NULL, NULL
  236. };
  237. static struct resource pic1_io_resource = {
  238. "pic1", 0x20, 0x3f, IORESOURCE_BUSY
  239. };
  240. static struct resource pic2_io_resource = {
  241. "pic2", 0xa0, 0xbf, IORESOURCE_BUSY
  242. };
  243. /*
  244.  * On systems with i8259-style interrupt controllers we assume for
  245.  * driver compatibility reasons interrupts 0 - 15 to be the i8295
  246.  * interrupts even if the hardware uses a different interrupt numbering.
  247.  */
  248. void __init init_i8259_irqs (void)
  249. {
  250. int i;
  251. request_resource(&ioport_resource, &pic1_io_resource);
  252. request_resource(&ioport_resource, &pic2_io_resource);
  253. init_8259A(0);
  254. for (i = 0; i < 16; i++) {
  255. irq_desc[i].status = IRQ_DISABLED;
  256. irq_desc[i].action = 0;
  257. irq_desc[i].depth = 1;
  258. irq_desc[i].handler = &i8259A_irq_type;
  259. }
  260. setup_irq(2, &irq2);
  261. }