i8259.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. /*
  8. * 8259 interrupt controllers
  9. */
  10. enum
  11. {
  12. Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */
  13. Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */
  14. Int1ctl= 0xA0, /* control port */
  15. Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */
  16. Icw1= 0x10, /* select bit in ctl register */
  17. Ocw2= 0x00,
  18. Ocw3= 0x08,
  19. EOI= 0x20, /* non-specific end of interrupt */
  20. Elcr1= 0x4D0, /* Edge/Level Triggered Register */
  21. Elcr2= 0x4D1,
  22. };
  23. static int int0mask; /* interrupts enabled for first 8259 */
  24. static int int1mask; /* interrupts enabled for second 8259 */
  25. int elcr; /* mask of level-triggered interrupts */
  26. void
  27. i8259init(void)
  28. {
  29. int /*elcr1, */ x;
  30. ioalloc(Int0ctl, 2, 0, "i8259.0");
  31. ioalloc(Int1ctl, 2, 0, "i8259.1");
  32. int0mask = 0xFF;
  33. int1mask = 0xFF;
  34. /*
  35. * Set up the first 8259 interrupt processor.
  36. * Make 8259 interrupts start at CPU vector Int0vec.
  37. * Set the 8259 as master with edge triggered
  38. * input with fully nested interrupts.
  39. */
  40. outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
  41. ICW4 will be sent */
  42. outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */
  43. outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */
  44. outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */
  45. /*
  46. * Set up the second 8259 interrupt processor.
  47. * Make 8259 interrupts start at CPU vector VectorPIC+8.
  48. * Set the 8259 as slave with edge triggered
  49. * input with fully nested interrupts.
  50. */
  51. outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
  52. ICW4 will be sent */
  53. outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */
  54. outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */
  55. outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */
  56. outb(Int1aux, int1mask);
  57. /*
  58. * pass #2 8259 interrupts to #1
  59. */
  60. int0mask &= ~0x04;
  61. outb(Int0aux, int0mask);
  62. /*
  63. * Set Ocw3 to return the ISR when ctl read.
  64. * After initialisation status read is set to IRR.
  65. * Read IRR first to possibly deassert an outstanding
  66. * interrupt.
  67. */
  68. x = inb(Int0ctl); USED(x);
  69. outb(Int0ctl, Ocw3|0x03);
  70. x = inb(Int1ctl); USED(x);
  71. outb(Int1ctl, Ocw3|0x03);
  72. /*
  73. * Check for Edge/Level register.
  74. * This check may not work for all chipsets.
  75. */
  76. /* elcr1 = inb(Elcr1);
  77. outb(Elcr1, 0);
  78. if(inb(Elcr1) == 0){
  79. outb(Elcr1, 0x20);
  80. if(inb(Elcr1) == 0x20)
  81. elcr = (inb(Elcr2)<<8)|elcr1;
  82. }
  83. outb(Elcr1, elcr1);
  84. if(elcr)
  85. iprint("ELCR: %4.4uX\n", elcr);
  86. /**/
  87. }
  88. int
  89. i8259isr(int v)
  90. {
  91. int isr;
  92. /*
  93. * tell the 8259 that we're done with the
  94. * highest level interrupt (interrupts are still
  95. * off at this point)
  96. */
  97. isr = 0;
  98. if(v >= VectorPIC && v <= MaxVectorPIC){
  99. isr = inb(Int0ctl);
  100. outb(Int0ctl, EOI);
  101. if(v >= VectorPIC+8){
  102. isr |= inb(Int1ctl)<<8;
  103. outb(Int1ctl, EOI);
  104. }
  105. }
  106. return isr & (1<<(v-VectorPIC));
  107. }
  108. int
  109. i8259enable(int v, int, Vctl* vctl)
  110. {
  111. if(v > MaxIrqPIC){
  112. print("i8259enable: vector %d out of range\n", v);
  113. return -1;
  114. }
  115. /*
  116. * enable corresponding interrupt in 8259
  117. */
  118. if(v < 8){
  119. int0mask &= ~(1<<v);
  120. outb(Int0aux, int0mask);
  121. }
  122. else{
  123. int1mask &= ~(1<<(v-8));
  124. outb(Int1aux, int1mask);
  125. }
  126. if(elcr & (1<<v))
  127. vctl->eoi = i8259isr;
  128. else
  129. vctl->isr = i8259isr;
  130. vctl->isintr = 1;
  131. return v;
  132. }