2 Copyright © 2011-2018, The AROS Development Team. All rights reserved.
5 Desc: Intel 8259A "Legacy" PIC driver.
8 #include <proto/exec.h>
10 #define __KERNEL_NOLIBBASE__
11 #include <proto/kernel.h>
16 #include "kernel_base.h"
17 #include "kernel_intern.h"
18 #include "kernel_debug.h"
19 #include "kernel_interrupts.h"
24 struct i8259a_Instance
32 struct i8259a_Instance irq_ic
[0];
35 icid_t
i8259a_Register(struct KernelBase
*KernelBase
)
37 DINT(bug("[Kernel:i8259a] %s()\n", __func__
));
39 /* if we have been disabled, fail to register */
40 if (i8259a_IntrController
.ic_Flags
& ICF_DISABLED
)
43 i8259a_IntrController
.ic_Flags
|= ICF_ACKENABLE
;
45 return (icid_t
)i8259a_IntrController
.ic_Node
.ln_Type
;
48 BOOL
i8259a_DisableIRQ(APTR icPrivate
, icid_t icInstance
, icid_t intNum
)
50 struct i8259a_Private
*xtpicPriv
= (struct i8259a_Private
*)icPrivate
;
51 struct i8259a_Instance
*xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[icInstance
];
53 DINT(bug("[Kernel:i8259a] %s(0x%p, %d, %d)\n", __func__
, icPrivate
, icInstance
, intNum
));
59 /* IRQ2 must never be disabled. Doing so breaks communication between two 8259s */
62 xtPic
->irq_mask
|= 1 << intNum
;
65 outb((xtPic
->irq_mask
>> 8) & 0xff, SLAVE8259_MASKREG
);
67 outb(xtPic
->irq_mask
& 0xff, MASTER8259_MASKREG
);
72 BOOL
i8259a_EnableIRQ(APTR icPrivate
, icid_t icInstance
, icid_t intNum
) // uint16_t *irqmask)
74 struct i8259a_Private
*xtpicPriv
= (struct i8259a_Private
*)icPrivate
;
75 struct i8259a_Instance
*xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[icInstance
];
77 DINT(bug("[Kernel:i8259a] %s(0x%p, %d, %d)\n", __func__
, icPrivate
, icInstance
, intNum
));
83 /* IRQ2 is always enabled anyway, and it's not a "real" IRQ, so it's probably
84 * appropriate to report failure */
87 xtPic
->irq_mask
&= ~(1 << intNum
);
90 outb((xtPic
->irq_mask
>> 8) & 0xff, SLAVE8259_MASKREG
);
92 outb(xtPic
->irq_mask
& 0xff, MASTER8259_MASKREG
);
98 * Careful! The 8259A is a fragile beast, it pretty much _has_ to be done exactly like this (mask it
99 * first, _then_ send the EOI, and the order of EOI to the two 8259s is important!
101 BOOL
i8259a_AckIntr(APTR icPrivate
, icid_t icInstance
, icid_t intNum
) // uint16_t *irqmask)
103 struct i8259a_Private
*xtpicPriv
= (struct i8259a_Private
*)icPrivate
;
104 struct i8259a_Instance
*xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[icInstance
];
106 DINT(bug("[Kernel:i8259a] %s(0x%p, %d, %d)\n", __func__
, icPrivate
, icInstance
, intNum
));
109 xtPic
->irq_mask
|= 1 << intNum
;
113 outb((xtPic
->irq_mask
>> 8) & 0xff, SLAVE8259_MASKREG
);
114 outb(0x62, MASTER8259_CMDREG
);
115 outb(0x20, SLAVE8259_CMDREG
);
119 outb(xtPic
->irq_mask
& 0xff, MASTER8259_MASKREG
);
120 outb(0x20, MASTER8259_CMDREG
);
127 BOOL
i8259a_Init(struct KernelBase
*KernelBase
, icid_t instanceCount
)
129 struct i8259a_Private
*xtpicPriv
;
130 struct i8259a_Instance
*xtPic
;
133 DINT(bug("[Kernel:i8259a] %s(%d)\n", __func__
, instanceCount
));
136 if (i8259a_IntrController
.ic_Flags
& ICF_DISABLED
)
139 xtpicPriv
= (struct i8259a_Private
*)
140 AllocMem(sizeof(struct i8259a_Private
)
141 + sizeof(struct i8259a_Instance
) * instanceCount
, MEMF_ANY
);
143 if ((i8259a_IntrController
.ic_Private
= xtpicPriv
) != NULL
)
146 * After initialization everything is disabled except cascade interrupt (IRQ 2).
147 * Be careful and don't miss this! Without IRQ2 enabled slave 8259 (and its IRQs)
152 for (instance
= 0; instance
< instanceCount
; instance
++)
154 int instIRQBase
= (instance
* I8259A_IRQCOUNT
);
156 DINT(bug("[Kernel:i8259a] %s: initializing instance #%d\n", __func__
, instance
));
158 xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[instance
];
159 xtPic
->irq_mask
= 0xFFFF;
160 xtPic
->irq_base
= HW_IRQ_BASE
+ instIRQBase
; /* route irqs after the cpu's exceptions */
165 if ((KrnIsSuper()) || ((ssp
= SuperState()) != NULL
))
167 /* Take over the first 8259A's IRQs */
168 for (irq
= instIRQBase
; irq
< (instIRQBase
+ I8259A_IRQCOUNT
); irq
++)
170 if (!krnInitInterrupt(KernelBase
, irq
, i8259a_IntrController
.ic_Node
.ln_Type
, instance
))
172 D(bug("[Kernel:i8259a] %s: failed to acquire IRQ #%d\n", __func__
, irq
);)
176 if ((irq
- instIRQBase
) != 2)
178 if (!core_SetIRQGate(
179 (struct int_gate_64bit
*)__KernBootPrivate
->BOOTIDT
,
180 irq
, (uintptr_t)IntrDefaultGates
[HW_IRQ_BASE
+ irq
]))
182 bug("[Kernel:i8259a] %s: failed to set IRQ %d's gate\n", __func__
, irq
);
184 if (ictl_is_irq_enabled(irq
, KernelBase
))
185 xtPic
->irq_mask
&= ~(1 << (irq
- instIRQBase
));
187 xtPic
->irq_mask
|= (1 << (irq
- instIRQBase
));
190 xtPic
->irq_mask
&= ~(1 << (irq
- instIRQBase
));
196 /* Set up the first registered 8259. Send four ICWs (see 8259 datasheet) */
197 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(MASTER8259_CMDREG
)); /* Initialization sequence for 8259A-1 (edge-triggered, cascaded, ICW4 needed) */
198 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(SLAVE8259_CMDREG
)); /* Initialization sequence for 8259A-2, the same as above */
199 asm("outb %b0,%b1\n\tcall delay"::"a"(xtPic
->irq_base
),"i"(MASTER8259_MASKREG
)); /* IRQs for master */
200 asm("outb %b0,%b1\n\tcall delay"::"a"(xtPic
->irq_base
+ 8),"i"(SLAVE8259_MASKREG
)); /* IRQs for slave */
201 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x04),"i"(MASTER8259_MASKREG
)); /* 8259A-1 is master, slave at IRQ2 */
202 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x02),"i"(SLAVE8259_MASKREG
)); /* 8259A-2 is slave, ID = 2 */
203 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(MASTER8259_MASKREG
)); /* 8086 mode, non-buffered, nonspecial fully nested mode for both */
204 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(SLAVE8259_MASKREG
));
206 /* Now initialize interrupt masks */
207 asm("outb %b0,%b1\n\tcall delay"::"a"((char)(xtPic
->irq_mask
& 0xFF)),"i"(MASTER8259_MASKREG
)); /* Enable cascade int */
208 asm("outb %b0,%b1\n\tcall delay"::"a"((char)(xtPic
->irq_mask
>> 8)),"i"(SLAVE8259_MASKREG
)); /* Mask all interrupts */
211 DINT(bug("[Kernel:i8259a] %s: complete\n", __func__
));
214 bug("[Kernel:i8259a] Failed to allocate controller storage!\n");
218 /* Small delay routine used by i8259a_Init() initializer */
219 asm("\ndelay:\t.short 0x00eb\n\tret");
221 struct IntrController i8259a_IntrController
=
224 .ln_Name
= "8259A PIC",
238 void i8259a_Disable()
240 /* Mask all pic interrupts */
241 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xFF),"i"(MASTER8259_MASKREG
));
242 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xFF),"i"(SLAVE8259_MASKREG
));
249 D(bug("[Kernel:i8259a] %s()\n", __func__
));
251 /* mask all of the interrupts except the cascade pin */
252 outb(0xff, SLAVE8259_MASKREG
);
253 outb(~(1 << 2), MASTER8259_MASKREG
);
254 maskres
= inb(MASTER8259_MASKREG
);
255 if (maskres
== ~(1 << 2))