add the common pc IRQTYPE definitions, and copy them for both the 32bit and 64bit...
[AROS.git] / arch / all-pc / kernel / pic_i8259a.c
blobdde6288e036b6352fa68264e67cc8b49abeb6558
1 /*
2 Copyright © 2011-2017, 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 8259's */
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 must never be disabled. Doing so breaks communication between two 8259's */
84 return FALSE;
86 xtPic->irq_mask &= ~(1 << intNum);
88 if (intNum >= 8)
89 outb((xtPic->irq_mask >> 8) & 0xff, SLAVE8259_MASKREG);
90 else
91 outb(xtPic->irq_mask & 0xff, MASTER8259_MASKREG);
93 return TRUE;
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));
107 intNum &= 15;
108 xtPic->irq_mask |= 1 << intNum;
110 if (intNum >= 8)
112 outb((xtPic->irq_mask >> 8) & 0xff, SLAVE8259_MASKREG);
113 outb(0x62, MASTER8259_CMDREG);
114 outb(0x20, SLAVE8259_CMDREG);
116 else
118 outb(xtPic->irq_mask & 0xff, MASTER8259_MASKREG);
119 outb(0x20, MASTER8259_CMDREG);
122 return TRUE;
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;
132 int instance, irq;
134 DINT(bug("[Kernel:i8259a] %s(%d)\n", __func__, instanceCount));
136 /* sanity check .. */
137 if (i8259a_IntrController.ic_Flags & ICF_DISABLED)
138 return FALSE;
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)
146 * will not work!
149 /* Setup Masks */
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 */
159 if (instance == 0)
161 APTR ssp = NULL;
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);)
172 else
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));
182 else
183 xtPic->irq_mask |= (1 << (irq - instIRQBase));
185 else
186 xtPic->irq_mask &= ~(1 << (irq - instIRQBase));
189 if (ssp)
190 UserState(ssp);
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__));
208 return TRUE;
210 bug("[Kernel:i8259a] Failed to allocate controller storage!\n");
211 return FALSE;
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",
221 .ln_Pri = 0
224 ICTYPE_I8259A,
226 NULL,
227 i8259a_Register,
228 i8259a_Init,
229 i8259a_EnableIRQ,
230 i8259a_DisableIRQ,
231 i8259a_AckIntr,
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));
241 BOOL i8259a_Probe()
243 UBYTE maskres;
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))
252 return TRUE;
253 return FALSE;