revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / kernel / pic_i8259a.c
blob0c26625b9a13bcd39c21cafcc349c602cba7d608
1 /*
2 Copyright © 2011-2018, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Intel 8259A "Legacy" PIC driver.
6 */
8 #include <proto/exec.h>
10 #define __KERNEL_NOLIBBASE__
11 #include <proto/kernel.h>
13 #include <asm/io.h>
14 #include <inttypes.h>
16 #include "kernel_base.h"
17 #include "kernel_intern.h"
18 #include "kernel_debug.h"
19 #include "kernel_interrupts.h"
21 #define D(x)
22 #define DINT(x)
24 struct i8259a_Instance
26 UWORD irq_mask;
27 UBYTE irq_base;
30 struct i8259a_Private
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)
41 return (icid_t)-1;
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));
55 intNum &= 15;
57 if (intNum == 2)
59 /* IRQ2 must never be disabled. Doing so breaks communication between two 8259s */
60 return FALSE;
62 xtPic->irq_mask |= 1 << intNum;
64 if (intNum >= 8)
65 outb((xtPic->irq_mask >> 8) & 0xff, SLAVE8259_MASKREG);
66 else
67 outb(xtPic->irq_mask & 0xff, MASTER8259_MASKREG);
69 return TRUE;
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));
79 intNum &= 15;
81 if (intNum == 2)
83 /* IRQ2 is always enabled anyway, and it's not a "real" IRQ, so it's probably
84 * appropriate to report failure */
85 return FALSE;
87 xtPic->irq_mask &= ~(1 << intNum);
89 if (intNum >= 8)
90 outb((xtPic->irq_mask >> 8) & 0xff, SLAVE8259_MASKREG);
91 else
92 outb(xtPic->irq_mask & 0xff, MASTER8259_MASKREG);
94 return TRUE;
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));
108 intNum &= 15;
109 xtPic->irq_mask |= 1 << intNum;
111 if (intNum >= 8)
113 outb((xtPic->irq_mask >> 8) & 0xff, SLAVE8259_MASKREG);
114 outb(0x62, MASTER8259_CMDREG);
115 outb(0x20, SLAVE8259_CMDREG);
117 else
119 outb(xtPic->irq_mask & 0xff, MASTER8259_MASKREG);
120 outb(0x20, MASTER8259_CMDREG);
123 return TRUE;
127 BOOL i8259a_Init(struct KernelBase *KernelBase, icid_t instanceCount)
129 struct i8259a_Private *xtpicPriv;
130 struct i8259a_Instance *xtPic;
131 int instance, irq;
133 DINT(bug("[Kernel:i8259a] %s(%d)\n", __func__, instanceCount));
135 /* Sanity check */
136 if (i8259a_IntrController.ic_Flags & ICF_DISABLED)
137 return FALSE;
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)
148 * will not work!
151 /* Setup Masks */
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 */
161 if (instance == 0)
163 APTR ssp = NULL;
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);)
174 else
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));
186 else
187 xtPic->irq_mask |= (1 << (irq - instIRQBase));
189 else
190 xtPic->irq_mask &= ~(1 << (irq - instIRQBase));
193 if (ssp)
194 UserState(ssp);
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__));
212 return TRUE;
214 bug("[Kernel:i8259a] Failed to allocate controller storage!\n");
215 return FALSE;
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",
225 .ln_Pri = 0
228 ICTYPE_I8259A,
230 NULL,
231 i8259a_Register,
232 i8259a_Init,
233 i8259a_EnableIRQ,
234 i8259a_DisableIRQ,
235 i8259a_AckIntr,
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));
245 BOOL i8259a_Probe()
247 BYTE maskres;
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))
256 return TRUE;
257 return FALSE;