irq.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * irq.c
  3. *
  4. * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <irq.h>
  20. #include <heap.h>
  21. #include <lock.h>
  22. #include <cpu.h>
  23. static list_entry_t irq_handlers[MAX_IRQ_COUNT];
  24. static dword_t irq_alloc_bitmap = 0xFFFFF3FF;
  25. static byte_t primary_pic_mask = 0xFF, secondary_pic_mask = 0xFF;
  26. static void irq_handler(registers_t *regs, byte_t int_num)
  27. {
  28. irq_handler_t *handler;
  29. byte_t irq_num = int_num - IRQ_INT_BASE;
  30. if (irq_num == 7)
  31. {
  32. cpu_write_port_byte(PRIMARY_PIC_CMD, 0x0B);
  33. byte_t isr = cpu_read_port_byte(PRIMARY_PIC_CMD);
  34. if (!(isr & 0x80)) return;
  35. }
  36. if (irq_num == 15)
  37. {
  38. cpu_write_port_byte(SECONDARY_PIC_CMD, 0x0B);
  39. byte_t isr = cpu_read_port_byte(SECONDARY_PIC_CMD);
  40. if (!(isr & 0x80))
  41. {
  42. cpu_write_port_byte(PRIMARY_PIC_CMD, 0x20);
  43. return;
  44. }
  45. }
  46. list_entry_t *ptr;
  47. for (ptr = irq_handlers[irq_num].next; ptr != &irq_handlers[irq_num]; ptr = ptr->next)
  48. {
  49. handler = CONTAINER_OF(ptr, irq_handler_t, list);
  50. cpu_enable_interrupts();
  51. handler->procedure(regs, irq_num);
  52. cpu_disable_interrupts();
  53. }
  54. if (irq_num >= 8) cpu_write_port_byte(SECONDARY_PIC_CMD, 0x20);
  55. cpu_write_port_byte(PRIMARY_PIC_CMD, 0x20);
  56. }
  57. dword_t register_irq_handler(byte_t irq_num, irq_handler_proc_t handler_proc, bool_t exclusive)
  58. {
  59. dword_t ret = ERR_SUCCESS;
  60. critical_t critical;
  61. if (irq_num >= MAX_IRQ_COUNT) return ERR_INVALID;
  62. irq_handler_t *handler = (irq_handler_t*)malloc(sizeof(irq_handler_t));
  63. if (handler == NULL) return ERR_NOMEMORY;
  64. handler->procedure = handler_proc;
  65. handler->exclusive = exclusive;
  66. enter_critical(&critical);
  67. if (irq_handlers[irq_num].next == &irq_handlers[irq_num])
  68. {
  69. if (irq_num >= 0 && irq_num < 8)
  70. {
  71. primary_pic_mask &= ~(1 << irq_num);
  72. cpu_write_port_byte(PRIMARY_PIC_DATA, primary_pic_mask);
  73. }
  74. else
  75. {
  76. secondary_pic_mask &= ~(1 << (irq_num - 8));
  77. cpu_write_port_byte(SECONDARY_PIC_DATA, secondary_pic_mask);
  78. }
  79. }
  80. else if (exclusive || CONTAINER_OF(irq_handlers[irq_num].next, irq_handler_t, list)->exclusive)
  81. {
  82. ret = ERR_EXISTS;
  83. }
  84. if (ret == ERR_SUCCESS) list_append(&irq_handlers[irq_num], &handler->list);
  85. leave_critical(&critical);
  86. return ret;
  87. }
  88. dword_t unregister_irq_handler(byte_t irq_num, irq_handler_proc_t handler_proc)
  89. {
  90. bool_t found = FALSE;
  91. critical_t critical;
  92. if (irq_num >= MAX_IRQ_COUNT) return ERR_INVALID;
  93. enter_critical(&critical);
  94. list_entry_t *ptr;
  95. for (ptr = irq_handlers[irq_num].next; ptr != &irq_handlers[irq_num]; ptr = ptr->next)
  96. {
  97. irq_handler_t *handler = CONTAINER_OF(ptr, irq_handler_t, list);
  98. if (handler->procedure == handler_proc)
  99. {
  100. list_remove(&handler->list);
  101. free(handler);
  102. found = TRUE;
  103. break;
  104. }
  105. }
  106. leave_critical(&critical);
  107. return found ? ERR_SUCCESS : ERR_NOTFOUND;
  108. }
  109. byte_t alloc_irq()
  110. {
  111. byte_t i;
  112. for (i = 0; i < MAX_IRQ_COUNT; i++) if (!test_bit(&irq_alloc_bitmap, i))
  113. {
  114. set_bit(&irq_alloc_bitmap, i);
  115. return i;
  116. }
  117. return 0xFF;
  118. }
  119. void free_irq(byte_t number)
  120. {
  121. clear_bit(&irq_alloc_bitmap, number);
  122. }
  123. void irq_init()
  124. {
  125. byte_t i;
  126. primary_pic_mask &= ~(1 << PRIMARY_PIC_CASCADE_IRQ);
  127. cpu_write_port_byte(PRIMARY_PIC_CMD, 0x11);
  128. cpu_write_port_byte(SECONDARY_PIC_CMD, 0x11);
  129. cpu_write_port_byte(PRIMARY_PIC_DATA, PRIMARY_IRQ_INT);
  130. cpu_write_port_byte(SECONDARY_PIC_DATA, SECONDARY_IRQ_INT);
  131. cpu_write_port_byte(PRIMARY_PIC_DATA, 1 << PRIMARY_PIC_CASCADE_IRQ);
  132. cpu_write_port_byte(SECONDARY_PIC_DATA, 1 << SECONDARY_PIC_CASCADE_IRQ);
  133. cpu_write_port_byte(PRIMARY_PIC_DATA, PIC_8086_MODE);
  134. cpu_write_port_byte(SECONDARY_PIC_DATA, PIC_8086_MODE);
  135. cpu_write_port_byte(PRIMARY_PIC_DATA, primary_pic_mask);
  136. cpu_write_port_byte(SECONDARY_PIC_DATA, secondary_pic_mask);
  137. for (i = 0; i < MAX_IRQ_COUNT; i++)
  138. {
  139. list_init(&irq_handlers[i]);
  140. set_int_handler(IRQ_INT_BASE + i, irq_handler, FALSE, FALSE);
  141. }
  142. }