~kernel/irq.cr
.cr
Crystal
(text/x-crystal)
lib KernelShim
  fun outb(port : UInt16, value : UInt8) : Void
end

module IRQ
  IRQ_COUNT = 16
  HANDLERS = StaticArray(Proc(UInt8, Void)?, IRQ_COUNT).new()
  
  def self.init
    self.register_keyboard
    puts "IRQ initialized!\n"
  end
  
  private def self.register_keyboard
    # todo: handle keyboard events
    register(1, # IRQ 1 = keyboard
    ->(scan_code : UInt8) {
      if scan_code == 0x1C
        puts "Enter\n"
      end
      # do smth
      puts "keyboard event\n"
    })
  end

  def self.register(irq : Int32, handler : Proc(UInt8, Void)) : Proc(UInt8, Void)?
    return nil if irq < 0 || irq >= IRQ_COUNT
    prev = HANDLERS[irq]
    HANDLERS[irq] = handler
    prev
  end

  def self.dispatcher(irq : UInt32)
    i = irq.to_u8
    h = HANDLERS[i]
    h.call(i) if h
  end
end

fun irq_dispatcher_c(irq : UInt32)
  puts "irq_dispatcher_c\n"
  IRQ.dispatcher(irq)
end

fun pic_send_eoi(irq : UInt32)
  puts "pic_send_eoi\n"
  if irq >= 8
    KernelShim.outb(0xA0_u16, 0x20_u8)
  end
  KernelShim.outb(0x20_u16, 0x20_u8)
end