|
|
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.