2 Copyright © 2011-2017, 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 8259's */
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 must never be disabled. Doing so breaks communication between two 8259's */
86 xtPic
->irq_mask
&= ~(1 << intNum
);
89 outb((xtPic
->irq_mask
>> 8) & 0xff, SLAVE8259_MASKREG
);
91 outb(xtPic
->irq_mask
& 0xff, MASTER8259_MASKREG
);
97 * Careful! The 8259A is a fragile beast, it pretty much _has_ to be done exactly like this (mask it
98 * first, _then_ send the EOI, and the order of EOI to the two 8259s is important!
100 BOOL
i8259a_AckIntr(APTR icPrivate
, icid_t icInstance
, icid_t intNum
) // uint16_t *irqmask)
102 struct i8259a_Private
*xtpicPriv
= (struct i8259a_Private
*)icPrivate
;
103 struct i8259a_Instance
*xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[icInstance
];
105 DINT(bug("[Kernel:i8259a] %s(0x%p, %d, %d)\n", __func__
, icPrivate
, icInstance
, intNum
));
108 xtPic
->irq_mask
|= 1 << intNum
;
112 outb((xtPic
->irq_mask
>> 8) & 0xff, SLAVE8259_MASKREG
);
113 outb(0x62, MASTER8259_CMDREG
);
114 outb(0x20, SLAVE8259_CMDREG
);
118 outb(xtPic
->irq_mask
& 0xff, MASTER8259_MASKREG
);
119 outb(0x20, MASTER8259_CMDREG
);
126 BOOL
i8259a_Init(struct KernelBase
*KernelBase
, icid_t instanceCount
)
128 struct PlatformData
*kernPlatD
= (struct PlatformData
*)KernelBase
->kb_PlatformData
;
129 struct APICData
*apicPrivate
= kernPlatD
->kb_APIC
;
130 struct i8259a_Private
*xtpicPriv
;
131 struct i8259a_Instance
*xtPic
;
134 DINT(bug("[Kernel:i8259a] %s(%d)\n", __func__
, instanceCount
));
136 /* sanity check .. */
137 if (i8259a_IntrController
.ic_Flags
& ICF_DISABLED
)
140 xtpicPriv
= (struct i8259a_Private
*)AllocMem(sizeof(struct i8259a_Instance
) * instanceCount
, MEMF_ANY
);
141 if ((i8259a_IntrController
.ic_Private
= xtpicPriv
) != NULL
)
144 * After initialization everything is disabled except cascade interrupt (IRQ 2).
145 * Be careful and don't miss this! Without IRQ2 enabled slave 8259 (and its IRQs)
150 for (instance
= 0; instance
< instanceCount
; instance
++)
152 int instIRQBase
= (instance
* I8259A_IRQCOUNT
);
154 DINT(bug("[Kernel:i8259a] %s: initializing instance #%d\n", __func__
, instance
));
156 xtPic
= (struct i8259a_Instance
*)&xtpicPriv
->irq_ic
[instance
];
157 xtPic
->irq_mask
= 0xFFFF;
158 xtPic
->irq_base
= HW_IRQ_BASE
+ instIRQBase
; /* route irqs after the cpu's exceptions */
163 if ((KrnIsSuper()) || ((ssp
= SuperState()) != NULL
))
165 /* Take over the first 8259a IRQ's */
166 for (irq
= instIRQBase
; irq
< (instIRQBase
+ I8259A_IRQCOUNT
); irq
++)
168 if (!krnInitInterrupt(KernelBase
, irq
, i8259a_IntrController
.ic_Node
.ln_Type
, instance
))
170 D(bug("[Kernel:i8259a] %s: failed to acquire IRQ #%d\n", __func__
, irq
);)
174 if ((irq
- instIRQBase
) != 2)
176 if (!core_SetIRQGate((struct int_gate_64bit
*)apicPrivate
->cores
[0].cpu_IDT
, irq
, (uintptr_t)IntrDefaultGates
[HW_IRQ_BASE
+ irq
]))
178 bug("[Kernel:i8259a] %s: failed to set IRQ %d's gate\n", __func__
, irq
);
180 if (ictl_is_irq_enabled(irq
, KernelBase
))
181 xtPic
->irq_mask
&= ~(1 << (irq
- instIRQBase
));
183 xtPic
->irq_mask
|= (1 << (irq
- instIRQBase
));
186 xtPic
->irq_mask
&= ~(1 << (irq
- instIRQBase
));
192 /* Setup the first registered 8259. Send four ICWs (see 8529 datasheet) */
193 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(MASTER8259_CMDREG
)); /* Initialization sequence for 8259A-1 (edge-triggered, cascaded, ICW4 needed) */
194 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(SLAVE8259_CMDREG
)); /* Initialization sequence for 8259A-2, the same as above */
195 asm("outb %b0,%b1\n\tcall delay"::"a"(xtPic
->irq_base
),"i"(MASTER8259_MASKREG
)); /* IRQs for master */
196 asm("outb %b0,%b1\n\tcall delay"::"a"(xtPic
->irq_base
+ 8),"i"(SLAVE8259_MASKREG
)); /* IRQs for slave */
197 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x04),"i"(MASTER8259_MASKREG
)); /* 8259A-1 is master, slave at IRQ2 */
198 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x02),"i"(SLAVE8259_MASKREG
)); /* 8259A-2 is slave, ID = 2 */
199 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(MASTER8259_MASKREG
)); /* 8086 mode, non-buffered, nonspecial fully nested mode for both */
200 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(SLAVE8259_MASKREG
));
202 /* Now initialize interrupt masks */
203 asm("outb %b0,%b1\n\tcall delay"::"a"((char)(xtPic
->irq_mask
& 0xFF)),"i"(MASTER8259_MASKREG
)); /* Enable cascade int */
204 asm("outb %b0,%b1\n\tcall delay"::"a"((char)(xtPic
->irq_mask
> 8)),"i"(SLAVE8259_MASKREG
)); /* Mask all interrupts */
207 DINT(bug("[Kernel:i8259a] %s: complete\n", __func__
));
210 bug("[Kernel:i8259a] Failed to allocate controller storage!\n");
214 /* Small delay routine used by i8259a_Init() initializer */
215 asm("\ndelay:\t.short 0x00eb\n\tret");
217 struct IntrController i8259a_IntrController
=
220 .ln_Name
= "8259A PIC",
234 void i8259a_Disable()
236 /* Mask all pic interrupts */
237 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xFF),"i"(MASTER8259_MASKREG
));
238 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xFF),"i"(SLAVE8259_MASKREG
));
245 D(bug("[Kernel:i8259a] %s()\n", __func__
));
247 /* mask all of the interrupts except the cascade pin */
248 outb(0xff, SLAVE8259_MASKREG
);
249 outb(~(1 << 2), MASTER8259_MASKREG
);
250 maskres
= inb(MASTER8259_MASKREG
);
251 if (maskres
== ~(1 << 2))