1*433d6423SLionel Sambuc /* This file contains routines for initializing the 8259 interrupt controller:
2*433d6423SLionel Sambuc * put_irq_handler: register an interrupt handler
3*433d6423SLionel Sambuc * rm_irq_handler: deregister an interrupt handler
4*433d6423SLionel Sambuc * intr_handle: handle a hardware interrupt
5*433d6423SLionel Sambuc * intr_init: initialize the interrupt controller(s)
6*433d6423SLionel Sambuc */
7*433d6423SLionel Sambuc
8*433d6423SLionel Sambuc #include "kernel/kernel.h"
9*433d6423SLionel Sambuc #include "arch_proto.h"
10*433d6423SLionel Sambuc #include "hw_intr.h"
11*433d6423SLionel Sambuc #include <machine/cpu.h>
12*433d6423SLionel Sambuc
13*433d6423SLionel Sambuc #define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */
14*433d6423SLionel Sambuc #define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */
15*433d6423SLionel Sambuc #define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */
16*433d6423SLionel Sambuc #define ICW4_AT_SLAVE 0x01 /* not SFNM, not buffered, normal EOI, 8086 */
17*433d6423SLionel Sambuc #define ICW4_AT_MASTER 0x05 /* not SFNM, not buffered, normal EOI, 8086 */
18*433d6423SLionel Sambuc #define ICW4_PC_SLAVE 0x09 /* not SFNM, buffered, normal EOI, 8086 */
19*433d6423SLionel Sambuc #define ICW4_PC_MASTER 0x0D /* not SFNM, buffered, normal EOI, 8086 */
20*433d6423SLionel Sambuc #define ICW4_AT_AEOI_SLAVE 0x03 /* not SFNM, not buffered, auto EOI, 8086 */
21*433d6423SLionel Sambuc #define ICW4_AT_AEOI_MASTER 0x07 /* not SFNM, not buffered, auto EOI, 8086 */
22*433d6423SLionel Sambuc #define ICW4_PC_AEOI_SLAVE 0x0B /* not SFNM, buffered, auto EOI, 8086 */
23*433d6423SLionel Sambuc #define ICW4_PC_AEOI_MASTER 0x0F /* not SFNM, buffered, auto EOI, 8086 */
24*433d6423SLionel Sambuc
25*433d6423SLionel Sambuc /*===========================================================================*
26*433d6423SLionel Sambuc * intr_init *
27*433d6423SLionel Sambuc *===========================================================================*/
intr_init(const int auto_eoi)28*433d6423SLionel Sambuc int intr_init(const int auto_eoi)
29*433d6423SLionel Sambuc {
30*433d6423SLionel Sambuc /* Initialize the 8259s, finishing with all interrupts disabled. */
31*433d6423SLionel Sambuc outb( INT_CTL, ICW1_AT);
32*433d6423SLionel Sambuc outb( INT_CTLMASK, IRQ0_VECTOR);
33*433d6423SLionel Sambuc /* ICW2 for master */
34*433d6423SLionel Sambuc outb( INT_CTLMASK, (1 << CASCADE_IRQ));
35*433d6423SLionel Sambuc /* ICW3 tells slaves */
36*433d6423SLionel Sambuc if (auto_eoi)
37*433d6423SLionel Sambuc outb( INT_CTLMASK, ICW4_AT_AEOI_MASTER);
38*433d6423SLionel Sambuc else
39*433d6423SLionel Sambuc outb( INT_CTLMASK, ICW4_AT_MASTER);
40*433d6423SLionel Sambuc outb( INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
41*433d6423SLionel Sambuc outb( INT2_CTL, ICW1_AT);
42*433d6423SLionel Sambuc outb( INT2_CTLMASK, IRQ8_VECTOR);
43*433d6423SLionel Sambuc /* ICW2 for slave */
44*433d6423SLionel Sambuc outb( INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */
45*433d6423SLionel Sambuc if (auto_eoi)
46*433d6423SLionel Sambuc outb( INT2_CTLMASK, ICW4_AT_AEOI_SLAVE);
47*433d6423SLionel Sambuc else
48*433d6423SLionel Sambuc outb( INT2_CTLMASK, ICW4_AT_SLAVE);
49*433d6423SLionel Sambuc outb( INT2_CTLMASK, ~0); /* IRQ 8-15 mask */
50*433d6423SLionel Sambuc
51*433d6423SLionel Sambuc return OK;
52*433d6423SLionel Sambuc }
53*433d6423SLionel Sambuc
irq_8259_unmask(const int irq)54*433d6423SLionel Sambuc void irq_8259_unmask(const int irq)
55*433d6423SLionel Sambuc {
56*433d6423SLionel Sambuc const unsigned ctl_mask = irq < 8 ? INT_CTLMASK : INT2_CTLMASK;
57*433d6423SLionel Sambuc outb(ctl_mask, inb(ctl_mask) & ~(1 << (irq & 0x7)));
58*433d6423SLionel Sambuc }
59*433d6423SLionel Sambuc
irq_8259_mask(const int irq)60*433d6423SLionel Sambuc void irq_8259_mask(const int irq)
61*433d6423SLionel Sambuc {
62*433d6423SLionel Sambuc const unsigned ctl_mask = irq < 8 ? INT_CTLMASK : INT2_CTLMASK;
63*433d6423SLionel Sambuc outb(ctl_mask, inb(ctl_mask) | (1 << (irq & 0x7)));
64*433d6423SLionel Sambuc }
65*433d6423SLionel Sambuc
66*433d6423SLionel Sambuc /* Disable 8259 - write 0xFF in OCW1 master and slave. */
i8259_disable(void)67*433d6423SLionel Sambuc void i8259_disable(void)
68*433d6423SLionel Sambuc {
69*433d6423SLionel Sambuc outb(INT2_CTLMASK, 0xFF);
70*433d6423SLionel Sambuc outb(INT_CTLMASK, 0xFF);
71*433d6423SLionel Sambuc inb(INT_CTLMASK);
72*433d6423SLionel Sambuc }
73*433d6423SLionel Sambuc
irq_8259_eoi(int irq)74*433d6423SLionel Sambuc void irq_8259_eoi(int irq)
75*433d6423SLionel Sambuc {
76*433d6423SLionel Sambuc if (irq < 8)
77*433d6423SLionel Sambuc eoi_8259_master();
78*433d6423SLionel Sambuc else
79*433d6423SLionel Sambuc eoi_8259_slave();
80*433d6423SLionel Sambuc }
81