/* * Deregister an interrupt handler. */ void sa11x0_intr_disestablish(sa11x0_chipset_tag_t ic, void *arg) { struct irqhandler *ih = arg; int irq = ih->ih_irq; int saved_cpsr; struct irqhandler **p, *q; #if DIAGNOSTIC if (irq < 0 || irq >= ICU_LEN) panic("intr_disestablish: bogus irq"); #endif /* * Remove the handler from the chain. * This is O(n^2), too. */ for (p = &irqhandlers[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next) ; if (q) *p = q->ih_next; else panic("intr_disestablish: handler not registered"); free(ih, M_DEVBUF); intr_calculatemasks(); saved_cpsr = SetCPSR(I32_bit, I32_bit); set_spl_masks(); irq_setmasks(); SetCPSR(I32_bit, saved_cpsr & I32_bit); }
void irq_init(void) { int loop; /* Clear all the IRQ handlers and the irq block masks */ for (loop = 0; loop < NIRQS; ++loop) { irqhandlers[loop] = NULL; } /* * Setup the irqmasks for the different Interrupt Priority Levels * We will start with no bits set and these will be updated as handlers * are installed at different IPL's. */ for (loop = 0; loop < NIPL; ++loop) irqmasks[loop] = 0; current_mask = 0x00000000; disabled_mask = 0x00000000; actual_mask = 0x00000000; set_spl_masks(); /* Enable IRQ's and FIQ's */ enable_interrupts(I32_bit | F32_bit); }
void * sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg) { int saved_cpsr; struct irqhandler **p, *q, *ih; static struct irqhandler fakehand = {fakeintr}; /* no point in sleeping unless someone can free memory. */ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) panic("sa11x0_intr_establish: can't malloc handler info"); if (irq < 0 || irq >= ICU_LEN || type == IST_NONE) panic("intr_establish: bogus irq or type"); /* All interrupts are level intrs. */ /* * Figure out where to put the handler. * This is O(N^2), but we want to preserve the order, and N is * generally small. */ for (p = &irqhandlers[irq]; (q = *p) != NULL; p = &q->ih_next) ; /* * Actually install a fake handler momentarily, since we might be doing * this with interrupts enabled and don't want the real routine called * until masking is set up. */ fakehand.ih_level = level; *p = &fakehand; intr_calculatemasks(); /* * Poke the real handler in now. */ ih->ih_func = ih_fun; ih->ih_arg = ih_arg; ih->ih_count = 0; ih->ih_next = NULL; ih->ih_level = level; ih->ih_irq = irq; ih->ih_name = NULL; /* XXX */ *p = ih; saved_cpsr = SetCPSR(I32_bit, I32_bit); set_spl_masks(); irq_setmasks(); SetCPSR(I32_bit, saved_cpsr & I32_bit); #ifdef DEBUG dumpirqhandlers(); #endif return (ih); }
int irq_release(int irq, irqhandler_t *handler) { irqhandler_t *irqhand; irqhandler_t **prehand; /* * IRQ_INSTRUCT indicates that we should get the irq number * from the irq structure */ if (irq == IRQ_INSTRUCT) irq = handler->ih_num; /* Make sure the irq number is valid */ if (irq < 0 || irq >= NIRQS) return(-1); /* Locate the handler */ prehand = &irqhandlers[irq]; irqhand = *prehand; while (irqhand && handler != irqhand) { prehand = &irqhand->ih_next; irqhand = *prehand; } /* Remove the handler if located */ if (irqhand) *prehand = irqhand->ih_next; else return(-1); /* The handler has been removed from the chain so mark it as inactive */ irqhand->ih_flags &= ~IRQ_FLAG_ACTIVE; /* Make sure the head of the handler list is active */ if (irqhandlers[irq]) irqhandlers[irq]->ih_flags |= IRQ_FLAG_ACTIVE; evcnt_detach(&irqhand->ih_ev); irq_calculatemasks(); /* * Disable the appropriate mask bit if there are no handlers left for * this IRQ. */ if (irqhandlers[irq] == NULL) disable_irq(irq); set_spl_masks(); return(0); }
int irq_claim(int irq, irqhandler_t *handler, const char *group, const char *name) { #ifdef DIAGNOSTIC /* Sanity check */ if (handler == NULL) panic("NULL interrupt handler"); if (handler->ih_func == NULL) panic("Interrupt handler does not have a function"); #endif /* DIAGNOSTIC */ /* * IRQ_INSTRUCT indicates that we should get the irq number * from the irq structure */ if (irq == IRQ_INSTRUCT) irq = handler->ih_num; /* Make sure the irq number is valid */ if (irq < 0 || irq >= NIRQS) return(-1); /* Make sure the level is valid */ if (handler->ih_level < 0 || handler->ih_level >= NIPL) return(-1); /* Attach evcnt */ evcnt_attach_dynamic(&handler->ih_ev, EVCNT_TYPE_INTR, NULL, group, name); /* Attach handler at top of chain */ handler->ih_next = irqhandlers[irq]; irqhandlers[irq] = handler; /* * Reset the flags for this handler. * As the handler is now in the chain mark it as active. */ handler->ih_flags = 0 | IRQ_FLAG_ACTIVE; /* * Record the interrupt number for accounting. * Done here as the accounting number may not be the same as the * IRQ number though for the moment they are */ handler->ih_num = irq; irq_calculatemasks(); enable_irq(irq); set_spl_masks(); return(0); }