|
|
1.1 root 1: /*
2: * Copyright (c) 1996, 1998, 1999, 2000 University of Utah and the Flux Group.
3: * All rights reserved.
4: *
5: * This file is part of the Flux OSKit. The OSKit is free software, also known
6: * as "open source;" you can redistribute it and/or modify it under the terms
7: * of the GNU General Public License (GPL), version 2, as published by the Free
8: * Software Foundation (FSF). To explore alternate licensing terms, contact
9: * the University of Utah at [email protected] or +1-801-585-3271.
10: *
11: * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
12: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13: * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
14: * received a copy of the GPL along with the OSKit; see the file COPYING. If
15: * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
16: */
17:
18: /*
19: * oskit IRQ control object for Mach.
20: */
21:
22: #include <oskit/error.h>
23: #include <oskit/dev/dev.h>
24: #include <oskit/dev/osenv_irq.h>
25: #include <oskit/machine/base_trap.h>
26: #include <oskit/machine/pio.h>
27: #include <oskit/machine/proc_reg.h>
28: #include <oskit/machine/base_irq.h>
29:
30: #include <string.h>
31:
32: #include <machine/spl.h>
33: extern int intnull();
34:
35: #include "ds_oskit.h"
36:
37: #include "kalloc.h"
38: #include "assert.h"
39:
40:
41: /* linked list of functions for an IRQ */
42: struct int_handler {
43: void (*func)(void *);
44: void *data;
45: struct int_handler *next;
46: };
47:
48: /* array of pointers to lists of interrupt handlers */
49: static struct int_handler *handlers[BASE_IRQ_COUNT];
50:
51: /* flag = 1 if sharing allowed; set to 0 if not */
52: static char shareable[BASE_IRQ_COUNT];
53:
54: /* An oskit interrupt handler call osenv_intr_enable to "reenable
55: interrupts" during the handler (it must return with them disabled
56: again). When it does this, what it really means is "reenable OTHER
57: interrupts"--it does it before actually handling the interrupt!
58: We must leave the irq line whose handler is running disabled at the PIC
59: until that handler returns, only enabling other interrupts. */
60:
61: unsigned int nested_pic_mask;
62:
63: static int
64: irq_handler(iunit, old_ipl, ret_addr, regs)
65: int iunit; /* 'unit' number */
66: int old_ipl; /* old interrupt level */
67: void *ret_addr __attribute__((unused)); /* in interrupt handler */
68: void *regs __attribute__((unused)); /* saved registers */
69: {
70: const unsigned int irq = iunit;
71: struct int_handler *current = handlers[irq];
72: unsigned int omask = nested_pic_mask & (1 << irq);
73:
74: nested_pic_mask |= 1 << irq;
75:
76: while (current) {
77: osenv_assert(current->func);
78: current->func(current->data);
79: current = current->next;
80: }
81:
82: nested_pic_mask &= ~(1 << irq);
83: nested_pic_mask |= omask;
84:
85: return 0;
86: }
87:
88: int intpri_oskit = /* SPL0; */ SPLIO; /* XXX */
89:
90: /* The one and only. */
91: static struct oskit_osenv_irq_ops osenv_irq_ops;
92: static struct oskit_osenv_irq osenv_irq_object = {&osenv_irq_ops};
93:
94: static OSKIT_COMDECL
95: irq_query(oskit_osenv_irq_t *s, const oskit_iid_t *iid, void **out_ihandle)
96: {
97: if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
98: memcmp(iid, &oskit_osenv_irq_iid, sizeof(*iid)) == 0) {
99: *out_ihandle = s;
100: return 0;
101: }
102:
103: *out_ihandle = 0;
104: return OSKIT_E_NOINTERFACE;
105: };
106:
107: static OSKIT_COMDECL_U
108: irq_addref(oskit_osenv_irq_t *s)
109: {
110: /* Only one object */
111: return 1;
112: }
113:
114: static OSKIT_COMDECL_U
115: irq_release(oskit_osenv_irq_t *s)
116: {
117: /* Only one object */
118: return 1;
119: }
120:
121:
122: /* This is a special kludge for the minimal console. If console_irq is -1
123: during the first irq_alloc, we set it to the irq being allocated.
124: Thereafter, allocating that irq will silently succeed and override
125: the handler installed for the minimal console, which we save in
126: console_irq_handler; freeing that irq will restore the console handler. */
127:
128: int console_irq;
129: static struct int_handler *console_irq_handler;
130:
131: static OSKIT_COMDECL_U
132: irq_alloc(oskit_osenv_irq_t *o, int irq,
133: void (*handler)(void *), void *data, int flags)
134: {
135: struct int_handler *temp, **p;
136: int first_time;
137:
138: if (irq < 0 || irq >= BASE_IRQ_COUNT)
139: return OSKIT_EINVAL;
140:
141: first_time = (handlers[irq] == NULL);
142:
143: if (first_time && ivect[irq] != intnull)
144: return OSKIT_EBUSY;
145:
146: assert(intpri_oskit != SPL0);
147:
148: if (!first_time && intpri[irq] != intpri_oskit) {
149: osenv_log(OSENV_LOG_ERR, "oskit wants irq %d at pri %d vs %d",
150: irq, intpri_oskit, intpri[irq]);
151: return OSKIT_EBUSY;
152: }
153:
154: /*
155: * This is a blocking operation,
156: * so to avoid races we need to do it
157: * before we start mucking with data structures.
158: */
159: temp = (void *) kalloc(sizeof(struct int_handler));
160: if (temp == NULL)
161: return OSKIT_ENOMEM;
162: temp->func = handler;
163: temp->data = data;
164: temp->next = NULL;
165:
166: /* Special hack for the minimal com and direct console devices. */
167: if (console_irq == -1) {
168: /* ds_osenv_init sets console_irq to -1 while initializing the
169: console, so we know this is the irq being allocated for it.
170: XXX we assume there is only one!
171: */
172: assert (first_time);
173: console_irq = irq;
174: }
175: else if (irq == console_irq && console_irq_handler == NULL) {
176: /* Attempting to re-allocate the console's irq.
177: This must be a real device driver taking over
178: from the minimal console. Let it. */
179: assert (! first_time);
180: assert (handlers[irq] != NULL);
181: console_irq_handler = handlers[irq];
182: osenv_log(OSENV_LOG_DEBUG,
183: "irq %d stolen from console\n", irq);
184: handlers[irq] = temp;
185: shareable[irq] = (flags & OSENV_IRQ_SHAREABLE) != 0;
186: return 0;
187: }
188:
189: /*
190: * Fail if the irq is already in use
191: * and either the new handler or the existing handler
192: * is not shareable.
193: */
194: if (!first_time &&
195: (!shareable[irq] || !(flags & OSENV_IRQ_SHAREABLE))) {
196: kfree(temp, sizeof(struct int_handler));
197: return OSKIT_EBUSY;
198: }
199:
200: /*
201: * Note that we only hook in the new handler
202: * after its structure has been fully initialized;
203: * this way we don't have to disable interrupts,
204: * because interrupt-level code only scans the list.
205: */
206: for (p = &handlers[irq]; *p != NULL; p = &(*p)->next);
207: *p = temp;
208:
209: if (first_time) {
210: int x = splhigh ();
211: shareable[irq] = (flags & OSENV_IRQ_SHAREABLE) != 0;
212: intpri[irq] = intpri_oskit;
213: ivect[irq] = irq_handler;
214: iunit[irq] = irq;
215: form_pic_mask();
216: splx(x);
217: }
218:
219: return 0;
220: }
221:
222:
223: static OSKIT_COMDECL_V
224: irq_free(oskit_osenv_irq_t *o, int irq,
225: void (*handler)(void *), void *data)
226: {
227: struct int_handler *temp, **p;
228:
229: osenv_assert(irq >= 0 && irq < BASE_IRQ_COUNT);
230: assert(ivect[irq] == irq_handler);
231:
232: /*
233: * If this is the only handler for this IRQ,
234: * then disable the IRQ before unregistering it,
235: * to avoid a possible infinite interrupt loop
236: * if the interrupt comes at just the wrong time.
237: * Not that this is ever likely to happen,
238: * but you never know with PC hardware...
239: */
240: temp = handlers[irq];
241: if (temp != NULL &&
242: temp->func == handler && temp->data == data &&
243: temp->next == NULL) {
244: if (irq == console_irq) {
245: /* Special hack for the minimal console's irq.
246: Restore the console's handler now that no real
247: driver is using it.
248: XXX this is probably not actually useful since
249: the driver won't have left the device in the same
250: state the minimal console driver expects.
251: */
252: handlers[irq] = console_irq_handler;
253: shareable[irq] = 0;
254: console_irq_handler = NULL;
255: osenv_log(OSENV_LOG_DEBUG,
256: "irq %d returned to console\n", irq);
257: }
258: else {
259: osenv_irq_disable(irq);
260: handlers[irq] = NULL;
261: intpri[irq] = SPL0;
262: ivect[irq] = intnull;
263: iunit[irq] = irq;
264: }
265: kfree(temp, sizeof(struct int_handler));
266: return;
267: }
268:
269: /*
270: * Find and unlink the handler from the list.
271: * Interrupt handlers may safely scan the list during this time,
272: * but we know no one else will concurrently modify it
273: * because only process-level code modifies the list.
274: */
275: p = &handlers[irq];
276: while (((temp = *p) != NULL) &&
277: (temp->func != handler || temp->data != data))
278: p = &temp->next;
279:
280: /* not found? */
281: if (temp == NULL) {
282: osenv_log(OSENV_LOG_WARNING,
283: "osenv_irq_free: interrupt handler not registered!\n");
284: return;
285: }
286:
287: /* remove it! */
288: *p = temp->next;
289:
290: kfree(temp, sizeof(struct int_handler));
291: }
292:
293: static OSKIT_COMDECL_V
294: irq_disable(oskit_osenv_irq_t *o, int irq)
295: {
296: spl_t s = splhigh (); /* XXX make sure it's a change */
297: nested_pic_mask |= (1 << irq);
298: splx (s);
299: }
300:
301: static OSKIT_COMDECL_V
302: irq_enable(oskit_osenv_irq_t *o, int irq)
303: {
304: spl_t s = splhigh ();
305: nested_pic_mask &= ~(1 << irq);
306: splx (s);
307: }
308:
309: static OSKIT_COMDECL_U
310: irq_pending(oskit_osenv_irq_t *o, int irq)
311: {
312: return osenv_irq_pending(irq);
313: }
314:
315: static struct oskit_osenv_irq_ops osenv_irq_ops = {
316: irq_query,
317: irq_addref,
318: irq_release,
319: irq_alloc,
320: irq_free,
321: irq_disable,
322: irq_enable,
323: irq_pending,
324: };
325:
326: /*
327: * Return a reference to the one and only irq object.
328: */
329: oskit_osenv_irq_t *
330: oskit_create_osenv_irq(void)
331: {
332: return &osenv_irq_object;
333: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.