x86: Add APIs to 8259 PIC driver

This commit implements pic_eoi(int irq) and a helper macro PIC_INT(irq).
This first checks which PICs should be 'acked' given an IRQ number, while
the macro returns the actual system interrupt number for the IRQ according
to the offset used on the PIC initialization.
This commit is contained in:
Jesus Sanchez-Palencia 2015-07-02 18:24:20 -03:00
parent 826ff7cb29
commit afd9b5b0b7
4 changed files with 38 additions and 14 deletions

View file

@ -30,6 +30,8 @@
#include "drivers/pic.h"
#define PIC_ACK 0x20
void
pic_unmask_irq(unsigned int num)
{
@ -46,3 +48,13 @@ pic_unmask_irq(unsigned int num)
bitmap = inb(port);
outb(port, bitmap & ~BIT(num));
}
/*---------------------------------------------------------------------------*/
void
pic_eoi(unsigned int irq)
{
if(irq >= 8) {
outb(PIC2_CMD_PORT, PIC_ACK);
}
outb(PIC1_CMD_PORT, PIC_ACK);
}

View file

@ -37,6 +37,14 @@
#define PIC1_DATA_PORT 0x21
#define PIC2_CMD_PORT 0xA0
#define PIC2_DATA_PORT 0xA1
#define PIC1_OFFSET 0x20
#define PIC2_OFFSET PIC1_OFFSET + 8
/*
* Returns the actual interrupt number of a given IRQ,
* no matter which PIC it is part of.
*/
#define PIC_INT(a) (a + PIC1_OFFSET)
void pic_unmask_irq(unsigned int num);
@ -52,8 +60,8 @@ pic_init(void)
outb(PIC2_CMD_PORT, 0x11);
/* ICW2: Remap IRQs by setting an IDT Offset for each PIC. */
outb(PIC1_DATA_PORT, 0x20);
outb(PIC2_DATA_PORT, 0x28);
outb(PIC1_DATA_PORT, PIC1_OFFSET);
outb(PIC2_DATA_PORT, PIC2_OFFSET);
/* ICW3: Setup Slave to Master's IRQ2. */
outb(PIC1_DATA_PORT, 0x04);
@ -69,4 +77,10 @@ pic_init(void)
outb(PIC2_DATA_PORT, 0xff);
}
/*
* This function sends an end-of-interrupt (EOI) to the correct PIC according
* to the IRQ line number.
*/
void pic_eoi(unsigned int irq);
#endif /* PIC_H */

View file

@ -39,6 +39,8 @@
#define PIT_CONTROL_PORT 0x43
#define PIT_COUNTER0_PORT 0x40
#define PIT_CLOCK_FREQUENCY 1193182
#define PIT_IRQ 0
#define PIT_INT PIC_INT(PIT_IRQ)
static pit_int_callback interrupt_cb;
@ -47,15 +49,13 @@ pit_int_handler(void)
{
interrupt_cb();
/* FIXME: Add a pic_send_eoi() API or similar and call it here. */
outb(0x20, 0x20); /* master PIC */
pic_eoi(PIT_IRQ);
}
/*---------------------------------------------------------------------------*/
void
pit_init(uint32_t ticks_rate, pit_int_callback cb)
{
/* FIXME: Call some PIC API to get the current offset and then add to its default IRQ number (0). */
SET_INTERRUPT_HANDLER(32, 0, pit_int_handler);
SET_INTERRUPT_HANDLER(PIT_INT, 0, pit_int_handler);
interrupt_cb = cb;
@ -76,5 +76,5 @@ pit_init(uint32_t ticks_rate, pit_int_callback cb)
outb(PIT_COUNTER0_PORT, divisor & 0xFF); /* Write least significant bytes first. */
outb(PIT_COUNTER0_PORT, (divisor >> 8) & 0xFF);
pic_unmask_irq(0);
pic_unmask_irq(PIT_IRQ);
}

View file

@ -35,6 +35,8 @@
#define RTC_INDEX_REGISTER 0x70
#define RTC_TARGET_REGISTER 0x71
#define RTC_IRQ 8
#define RTC_INT PIC_INT(RTC_IRQ)
static void (*user_callback)(void);
@ -51,8 +53,7 @@ rtc_handler()
inb(RTC_TARGET_REGISTER);
/* Issue the End of Interrupt to PIC */
outb(0xA0, 0x20);
outb(0x20, 0x20);
pic_eoi(RTC_IRQ);
}
/*---------------------------------------------------------------------------*/
/* Initialize the Real Time Clock.
@ -69,10 +70,7 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void))
user_callback = callback;
/* FIXME: Once we have a proper API to ask PIC what is the IRQ offset, we
* should consider using it here.
*/
SET_INTERRUPT_HANDLER(40, 0, rtc_handler);
SET_INTERRUPT_HANDLER(RTC_INT, 0, rtc_handler);
/* Select interrupt period to 7.8125 ms */
outb(RTC_INDEX_REGISTER, 0x0A);
@ -88,5 +86,5 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void))
outb(RTC_INDEX_REGISTER, 0x0B);
outb(RTC_TARGET_REGISTER, reg_b | BIT(6));
pic_unmask_irq(8);
pic_unmask_irq(RTC_IRQ);
}