i8259.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.i8259.c 1.11 12/19/01 09:45:54 trini
  3.  */
  4. #include <linux/stddef.h>
  5. #include <linux/init.h>
  6. #include <linux/irq.h>
  7. #include <linux/ioport.h>
  8. #include <linux/sched.h>
  9. #include <linux/signal.h>
  10. #include <asm/io.h>
  11. #include "i8259.h"
  12. static volatile char *pci_intack; /* RO, gives us the irq vector */
  13. unsigned char cached_8259[2] = { 0xff, 0xff };
  14. #define cached_A1 (cached_8259[0])
  15. #define cached_21 (cached_8259[1])
  16. static spinlock_t i8259_lock = SPIN_LOCK_UNLOCKED;
  17. int i8259_pic_irq_offset;
  18. /* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
  19.  * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
  20.  */
  21. int i8259_irq(void)
  22. {
  23. int irq;
  24. spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
  25. irq = *pci_intack & 0xff;
  26. if (irq==7) {
  27. /*
  28.  * This may be a spurious interrupt.
  29.  *
  30.  * Read the interrupt status register (ISR). If the most
  31.  * significant bit is not set then there is no valid
  32.  * interrupt.
  33.  */
  34. if(~inb(0x20)&0x80) {
  35. irq = -1;
  36. }
  37. }
  38. spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
  39. return irq;
  40. }
  41. /* Poke the 8259's directly using poll commands. */
  42. int i8259_poll(void)
  43. {
  44. int irq;
  45. spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
  46. /*
  47.  * Perform an interrupt acknowledge cycle on controller 1
  48.  */
  49. outb(0x0C, 0x20); /* prepare for poll */
  50. irq = inb(0x20) & 7;
  51. if (irq == 2) {
  52. /*
  53.  * Interrupt is cascaded so perform interrupt
  54.  * acknowledge on controller 2
  55.  */
  56. outb(0x0C, 0xA0); /* prepare for poll */
  57. irq = (inb(0xA0) & 7) + 8;
  58. } else if (irq==7) {
  59. /*
  60.  * This may be a spurious interrupt
  61.  *
  62.  * Read the interrupt status register. If the most
  63.  * significant bit is not set then there is no valid
  64.  * interrupt
  65.  */
  66. outb(0x0b, 0x20);
  67. if(~inb(0x20)&0x80) {
  68. spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
  69. return -1;
  70. }
  71. }
  72. spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
  73. return irq;
  74. }
  75. static void i8259_mask_and_ack_irq(unsigned int irq_nr)
  76. {
  77. unsigned long flags;
  78. spin_lock_irqsave(&i8259_lock, flags);
  79. if ( irq_nr >= i8259_pic_irq_offset )
  80. irq_nr -= i8259_pic_irq_offset;
  81. if (irq_nr > 7) {
  82. cached_A1 |= 1 << (irq_nr-8);
  83. inb(0xA1); /* DUMMY */
  84. outb(cached_A1,0xA1);
  85. outb(0x20,0xA0); /* Non-specific EOI */
  86. outb(0x20,0x20); /* Non-specific EOI to cascade */
  87. } else {
  88. cached_21 |= 1 << irq_nr;
  89. inb(0x21); /* DUMMY */
  90. outb(cached_21,0x21);
  91. outb(0x20,0x20); /* Non-specific EOI */
  92. }
  93. spin_unlock_irqrestore(&i8259_lock, flags);
  94. }
  95. static void i8259_set_irq_mask(int irq_nr)
  96. {
  97. outb(cached_A1,0xA1);
  98. outb(cached_21,0x21);
  99. }
  100.  
  101. static void i8259_mask_irq(unsigned int irq_nr)
  102. {
  103. unsigned long flags;
  104. spin_lock_irqsave(&i8259_lock, flags);
  105. if ( irq_nr >= i8259_pic_irq_offset )
  106. irq_nr -= i8259_pic_irq_offset;
  107. if ( irq_nr < 8 )
  108. cached_21 |= 1 << irq_nr;
  109. else
  110. cached_A1 |= 1 << (irq_nr-8);
  111. i8259_set_irq_mask(irq_nr);
  112. spin_unlock_irqrestore(&i8259_lock, flags);
  113. }
  114. static void i8259_unmask_irq(unsigned int irq_nr)
  115. {
  116. unsigned long flags;
  117. spin_lock_irqsave(&i8259_lock, flags);
  118. if ( irq_nr >= i8259_pic_irq_offset )
  119. irq_nr -= i8259_pic_irq_offset;
  120. if ( irq_nr < 8 )
  121. cached_21 &= ~(1 << irq_nr);
  122. else
  123. cached_A1 &= ~(1 << (irq_nr-8));
  124. i8259_set_irq_mask(irq_nr);
  125. spin_unlock_irqrestore(&i8259_lock, flags);
  126. }
  127. static void i8259_end_irq(unsigned int irq)
  128. {
  129. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  130. i8259_unmask_irq(irq);
  131. }
  132. struct hw_interrupt_type i8259_pic = {
  133. " i8259    ",
  134. NULL,
  135. NULL,
  136. i8259_unmask_irq,
  137. i8259_mask_irq,
  138. i8259_mask_and_ack_irq,
  139. i8259_end_irq,
  140. NULL
  141. };
  142. static struct resource pic1_iores = {
  143. "8259 (master)", 0x20, 0x21, IORESOURCE_BUSY
  144. };
  145. static struct resource pic2_iores = {
  146. "8259 (slave)", 0xa0, 0xa1, IORESOURCE_BUSY
  147. };
  148. static struct resource pic_edgectrl_iores = {
  149. "8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
  150. };
  151. void __init i8259_init(long intack_addr)
  152. {
  153. unsigned long flags;
  154. spin_lock_irqsave(&i8259_lock, flags);
  155. /* init master interrupt controller */
  156. outb(0x11, 0x20); /* Start init sequence */
  157. outb(0x00, 0x21); /* Vector base */
  158. outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
  159. outb(0x01, 0x21); /* Select 8086 mode */
  160. /* init slave interrupt controller */
  161. outb(0x11, 0xA0); /* Start init sequence */
  162. outb(0x08, 0xA1); /* Vector base */
  163. outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
  164. outb(0x01, 0xA1); /* Select 8086 mode */
  165. /* always read ISR */
  166. outb(0x0B, 0x20);
  167. outb(0x0B, 0xA0);
  168. /* Mask all interrupts */
  169. outb(cached_A1, 0xA1);
  170. outb(cached_21, 0x21);
  171. spin_unlock_irqrestore(&i8259_lock, flags);
  172. /* reserve our resources */
  173. request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
  174. "82c59 secondary cascade", NULL );
  175. request_resource(&ioport_resource, &pic1_iores);
  176. request_resource(&ioport_resource, &pic2_iores);
  177. request_resource(&ioport_resource, &pic_edgectrl_iores);
  178. if (intack_addr)
  179. pci_intack = ioremap(intack_addr, 1);
  180. }