Fix IO memory access .. SB128 driver makes noises in VMWare - CMI is untested (Curren...
[AROS.git] / arch / i386-pc / exec / core.c
blob0708acad6982053471c5cdc111f5cdbcbc3ee121
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Interrupt core, part of kernel.resource
6 Lang: english
7 */
9 #include "core.h"
10 #include "traps.h"
11 //#include "include/machine.i"
12 #include <asm/io.h>
13 #include <exec/types.h>
14 #include <exec/execbase.h>
15 #include <string.h>
17 #define __text __attribute__((section(".text")))
19 struct view { unsigned char sign; unsigned char attr; };
21 extern unsigned int cached_irq_mask;
22 extern unsigned long io_apic_irqs;
23 extern struct irqDescriptor irq_desc[];
24 void handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqServer * is);
27 * Build all interrupt assembly code needed. We use some very ugly macros
28 * which were taken from linux sources.
31 BUILD_COMMON_IRQ()
33 #define BI(x,y) \
34 BUILD_IRQ(x##y)
36 #define BUILD_16_IRQS(x) \
37 BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
38 BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
39 BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
40 BI(x,c) BI(x,d) BI(x,e) BI(x,f)
43 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
44 * (these are usually mapped to vectors 0x20-0x30)
46 BUILD_16_IRQS(0x0)
48 #undef BUILD_16_IRQS
49 #undef BI
51 #define IRQ(x,y) \
52 (const void (*)(void))IRQ##x##y##_interrupt
54 #define IRQLIST_16(x) \
55 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
56 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
57 IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
58 IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
60 const void (*interrupt[NR_IRQS])(void) __text = {
61 IRQLIST_16(0x0),
64 #undef IRQ
65 #undef IRQLIST_16
68 * This is the 'legacy' 8259A Programmable Interrupt Controller,
69 * present in the majority of PC/AT boxes.
72 static void do_8259A_IRQ(unsigned int, struct pt_regs *);
73 static void enable_8259A_irq(unsigned int);
74 void disable_8259A_irq(unsigned int);
76 #define startup_8259A_irq enable_8259A_irq
77 #define shutdown_8259A_irq disable_8259A_irq
79 static const struct irqController i8259_controller =
81 "XT-PIC",
82 startup_8259A_irq,
83 shutdown_8259A_irq,
84 do_8259A_IRQ,
85 enable_8259A_irq,
86 disable_8259A_irq
89 #define __byte(x,y) (((unsigned char *)&(y))[x])
90 #define cached_21 (__byte(0,cached_irq_mask))
91 #define cached_A1 (__byte(1,cached_irq_mask))
93 void disable_8259A_irq(unsigned int irq)
95 cached_irq_mask |= (1 << irq);
96 if (irq & 8)
98 outb(cached_A1, 0xa1);
99 } else
101 outb(cached_21, 0x21);
105 static void enable_8259A_irq(unsigned int irq)
107 cached_irq_mask &= ~(1 << irq);
108 if (irq & 8) {
109 outb(cached_A1,0xA1);
110 } else {
111 outb(cached_21,0x21);
116 * Careful! The 8259A is a fragile beast, it pretty
117 * much _has_ to be done exactly like this (mask it
118 * first, _then_ send the EOI, and the order of EOI
119 * to the two 8259s is important!
121 static inline void mask_and_ack_8259A(unsigned int irq)
123 cached_irq_mask |= 1 << irq;
124 if (irq & 8) {
125 // inb(0xA1); /* DUMMY */
126 outb(cached_A1,0xA1);
127 outb(0x62,0x20); /* Specific EOI to cascade */
128 outb(0x20,0xA0);
129 } else {
130 // inb(0x21); /* DUMMY */
131 outb(cached_21,0x21);
132 outb(0x20,0x20);
136 static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
138 struct irqServer * iServer;
139 struct irqDescriptor *desc = &irq_desc[irq];
142 unsigned int status;
143 mask_and_ack_8259A(irq);
144 status = desc->id_status & ~(IRQ_REPLAY | IRQ_WAITING);
145 iServer = NULL;
146 if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
147 iServer = desc->id_server;
148 status |= IRQ_INPROGRESS;
150 desc->id_status = status;
153 /* Exit early if we had no action or it was disabled */
154 if (!iServer)
155 return;
157 handle_IRQ_event(irq, regs, iServer);
160 unsigned int status = desc->id_status & ~IRQ_INPROGRESS;
161 desc->id_status = status;
162 if (!(status & IRQ_DISABLED))
163 enable_8259A_irq(irq);
167 /*******************************************************************************
168 Lowlevel IRQ functions used by each controller
169 *******************************************************************************/
171 void handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqServer * is)
173 __cli();
174 is->is_handler(irq, is->is_UserData, regs);
175 __cli();
179 * Generic enable/disable code: this just calls
180 * down into the PIC-specific version for the actual
181 * hardware disable after having gotten the irq
182 * controller lock.
184 void disable_irq_nosync(unsigned int irq)
186 if (!irq_desc[irq].id_depth++) {
187 irq_desc[irq].id_status |= IRQ_DISABLED;
188 irq_desc[irq].id_handler->ic_disable(irq);
193 * Synchronous version of the above, making sure the IRQ is
194 * no longer running on any other IRQ..
196 void disable_irq(unsigned int irq)
198 disable_irq_nosync(irq);
201 void enable_irq(unsigned int irq)
203 switch (irq_desc[irq].id_depth)
205 case 0: break;
206 case 1:
207 irq_desc[irq].id_status &= ~IRQ_DISABLED;
208 irq_desc[irq].id_handler->ic_enable(irq);
209 /* fall through */
210 default:
211 irq_desc[irq].id_depth--;
216 * do_IRQ handles all normal device IRQ's (the special
217 * SMP cross-CPU interrupts have their own specific
218 * handlers).
220 asmlinkage void do_IRQ(struct pt_regs regs)
223 * We ack quickly, we don't want the irq controller
224 * thinking we're snobs just because some other CPU has
225 * disabled global interrupts (we have already done the
226 * INT_ACK cycles, it's too late to try to pretend to the
227 * controller that we aren't taking the interrupt).
229 * 0 return value means that this irq is already being
230 * handled by some other CPU. (or is disabled)
233 irq_desc[regs.orig_eax].id_count++;
234 irq_desc[regs.orig_eax].id_handler->ic_handle(regs.orig_eax, &regs);
235 #if 0
237 int i;
238 for (i=0; i<16; i++)
240 ((struct view*)0xb8000)[64+i].attr = 0x1f;
241 ((struct view*)0xb8000)[64+i].sign =
242 (irq_desc[i].id_count & 7) ? '0' + (irq_desc[i].id_count & 7):'.';
245 #endif
249 extern struct ExecBase *SysBase;
250 #undef Elapsed
251 #undef AttnResched
253 static void VBL_handler(int i, void *user, struct pt_regs *regs)
255 if (SysBase->Elapsed == 0)
257 SysBase->SysFlags |= 0x2000;
258 SysBase->AttnResched |= 0x80;
260 else SysBase->Elapsed--;
263 static struct irqServer VBlank = { VBL_handler, "VBlank", NULL };
265 #define HZ 50
266 #define LATCH ((1193180 + 25)/50)
268 void irqSet(int irq, struct irqServer *is)
270 if (is)
272 irq_desc[irq].id_server = is;
273 irq_desc[irq].id_depth = 0;
274 irq_desc[irq].id_status &= ~IRQ_DISABLED;
275 irq_desc[irq].id_handler->ic_startup(irq);
279 void irqSetup()
281 int i;
283 cached_irq_mask = 0xffff;
284 io_apic_irqs = 0;
286 #if 0
287 asm("rep\n\tstosb"
289 :"eax"(0), /* Fill with 0 */
290 "D"(&irq_desc), /* irq_desc table */
291 "ecx"(512/4));
292 #else
293 bzero(&irq_desc, 512);
294 #endif
296 for (i = 0; i<NR_IRQS; i++)
298 irq_desc[i].id_handler = &i8259_controller;
299 irq_desc[i].id_status = IRQ_DISABLED;
300 irq_desc[i].id_depth = 0;
301 irq_desc[i].id_server = 0;
303 set_intr_gate(FIRST_EXT_VECTOR + i, interrupt[i]);
306 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
307 outb_p(LATCH & 0xff , 0x40); /* LSB */
308 outb(LATCH >> 8 , 0x40); /* MSB */
310 irq_desc[0].id_server = &VBlank;
311 irq_desc[0].id_depth = 0;
312 irq_desc[0].id_status &= ~IRQ_DISABLED;
313 irq_desc[0].id_handler->ic_startup(0);
317 * Interrupts
320 int sys_Cause(struct pt_regs);
321 int sys_Supervisor(struct pt_regs);
322 int sys_None(struct pt_regs regs) { return 0; }
324 asmlinkage int sys_ColdReboot(struct pt_regs regs)
326 __asm__("jmp kernel_startup");
327 return 0;
330 int (*sys_call_table[])(struct pt_regs) __text =
332 sys_Cause,
333 sys_ColdReboot,
334 sys_Supervisor,
335 sys_None