Annotation of OSKit-Mach/oskit/osenv_irq.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.