source: trunk/minix/kernel/i8259.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 6.4 KB
Line 
1/* This file contains routines for initializing the 8259 interrupt controller:
2 * put_irq_handler: register an interrupt handler
3 * rm_irq_handler: deregister an interrupt handler
4 * intr_handle: handle a hardware interrupt
5 * intr_init: initialize the interrupt controller(s)
6 */
7
8#include "kernel.h"
9#include "proc.h"
10#include <minix/com.h>
11
12#define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */
13#define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */
14#define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */
15#define ICW4_AT_SLAVE 0x01 /* not SFNM, not buffered, normal EOI, 8086 */
16#define ICW4_AT_MASTER 0x05 /* not SFNM, not buffered, normal EOI, 8086 */
17#define ICW4_PC_SLAVE 0x09 /* not SFNM, buffered, normal EOI, 8086 */
18#define ICW4_PC_MASTER 0x0D /* not SFNM, buffered, normal EOI, 8086 */
19
20#if _WORD_SIZE == 2
21typedef _PROTOTYPE( void (*vecaddr_t), (void) );
22
23FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) );
24
25PRIVATE vecaddr_t int_vec[] = {
26 int00, int01, int02, int03, int04, int05, int06, int07,
27};
28
29PRIVATE vecaddr_t irq_vec[] = {
30 hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07,
31 hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15,
32};
33#else
34#define set_vec(nr, addr) ((void)0)
35#endif
36
37/*===========================================================================*
38 * intr_init *
39 *===========================================================================*/
40PUBLIC void intr_init(mine)
41int mine;
42{
43/* Initialize the 8259s, finishing with all interrupts disabled. This is
44 * only done in protected mode, in real mode we don't touch the 8259s, but
45 * use the BIOS locations instead. The flag "mine" is set if the 8259s are
46 * to be programmed for MINIX, or to be reset to what the BIOS expects.
47 */
48 int i;
49
50 intr_disable();
51
52 if (machine.prot) {
53 /* The AT and newer PS/2 have two interrupt controllers, one master,
54 * one slaved at IRQ 2. (We don't have to deal with the PC that
55 * has just one controller, because it must run in real mode.)
56 */
57 outb(INT_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
58 outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
59 /* ICW2 for master */
60 outb(INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */
61 outb(INT_CTLMASK, ICW4_AT_MASTER);
62 outb(INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
63 outb(INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
64 outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
65 /* ICW2 for slave */
66 outb(INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */
67 outb(INT2_CTLMASK, ICW4_AT_SLAVE);
68 outb(INT2_CTLMASK, ~0); /* IRQ 8-15 mask */
69
70 /* Copy the BIOS vectors from the BIOS to the Minix location, so we
71 * can still make BIOS calls without reprogramming the i8259s.
72 */
73#if IRQ0_VECTOR != BIOS_IRQ0_VEC
74 phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
75#endif
76#if IRQ8_VECTOR != BIOS_IRQ8_VEC
77 phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L);
78#endif
79 } else {
80 /* Use the BIOS interrupt vectors in real mode. We only reprogram the
81 * exceptions here, the interrupt vectors are reprogrammed on demand.
82 * SYS_VECTOR is the Minix system call for message passing.
83 */
84 for (i = 0; i < 8; i++) set_vec(i, int_vec[i]);
85 set_vec(SYS_VECTOR, s_call);
86 }
87}
88
89/*===========================================================================*
90 * put_irq_handler *
91 *===========================================================================*/
92PUBLIC void put_irq_handler(hook, irq, handler)
93irq_hook_t *hook;
94int irq;
95irq_handler_t handler;
96{
97/* Register an interrupt handler. */
98 int id;
99 irq_hook_t **line;
100
101 if (irq < 0 || irq >= NR_IRQ_VECTORS)
102 panic("invalid call to put_irq_handler", irq);
103
104 line = &irq_handlers[irq];
105 id = 1;
106 while (*line != NULL) {
107 if (hook == *line) return; /* extra initialization */
108 line = &(*line)->next;
109 id <<= 1;
110 }
111 if (id == 0) panic("Too many handlers for irq", irq);
112
113 hook->next = NULL;
114 hook->handler = handler;
115 hook->irq = irq;
116 hook->id = id;
117 *line = hook;
118
119 irq_use |= 1 << irq;
120}
121
122/*===========================================================================*
123 * rm_irq_handler *
124 *===========================================================================*/
125PUBLIC void rm_irq_handler(hook)
126irq_hook_t *hook;
127{
128/* Unregister an interrupt handler. */
129 int irq = hook->irq;
130 int id = hook->id;
131 irq_hook_t **line;
132
133 if (irq < 0 || irq >= NR_IRQ_VECTORS)
134 panic("invalid call to rm_irq_handler", irq);
135
136 line = &irq_handlers[irq];
137 while (*line != NULL) {
138 if ((*line)->id == id) {
139 (*line) = (*line)->next;
140 if (! irq_handlers[irq]) irq_use &= ~(1 << irq);
141 return;
142 }
143 line = &(*line)->next;
144 }
145 /* When the handler is not found, normally return here. */
146}
147
148/*===========================================================================*
149 * intr_handle *
150 *===========================================================================*/
151PUBLIC void intr_handle(hook)
152irq_hook_t *hook;
153{
154/* Call the interrupt handlers for an interrupt with the given hook list.
155 * The assembly part of the handler has already masked the IRQ, reenabled the
156 * controller(s) and enabled interrupts.
157 */
158
159 /* Call list of handlers for an IRQ. */
160 while (hook != NULL) {
161 /* For each handler in the list, mark it active by setting its ID bit,
162 * call the function, and unmark it if the function returns true.
163 */
164 irq_actids[hook->irq] |= hook->id;
165 if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id;
166 hook = hook->next;
167 }
168
169 /* The assembly code will now disable interrupts, unmask the IRQ if and only
170 * if all active ID bits are cleared, and restart a process.
171 */
172}
173
174#if _WORD_SIZE == 2
175/*===========================================================================*
176 * set_vec *
177 *===========================================================================*/
178PRIVATE void set_vec(vec_nr, addr)
179int vec_nr; /* which vector */
180vecaddr_t addr; /* where to start */
181{
182/* Set up a real mode interrupt vector. */
183
184 u16_t vec[2];
185
186 /* Build the vector in the array 'vec'. */
187 vec[0] = (u16_t) addr;
188 vec[1] = (u16_t) physb_to_hclick(code_base);
189
190 /* Copy the vector into place. */
191 phys_copy(vir2phys(vec), vec_nr * 4L, 4L);
192}
193#endif /* _WORD_SIZE == 2 */
Note: See TracBrowser for help on using the repository browser.