/* Deregister an interrupt handler. */ void isa_intr_disestablish(isa_chipset_tag_t ic, void *arg) { struct intrhand *ih = arg; if (!LEGAL_IRQ(ih->ih_pin)) panic("intr_disestablish: bogus irq"); intr_disestablish(ih); }
/* * Just check to see if an IRQ is available/can be shared. * 0 = interrupt not available * 1 = interrupt shareable * 2 = interrupt all to ourself */ int isa_intr_check(isa_chipset_tag_t ic, int irq, int type) { if (!LEGAL_IRQ(irq) || type == IST_NONE) return (0); switch (intrtype[irq]) { case IST_NONE: return (2); break; case IST_LEVEL: if (type != intrtype[irq]) return (0); return (1); break; case IST_EDGE: case IST_PULSE: if (type != IST_NONE) return (0); } return (1); }
/* * Deregister an interrupt handler. */ void isa_intr_disestablish(isa_chipset_tag_t ic, void *arg) { struct intrhand *ih = arg; struct intrq *iq = &isa_intrq[ih->ih_irq]; int irq = ih->ih_irq; u_int oldirqstate; if (!LEGAL_IRQ(irq)) panic("intr_disestablish: bogus irq"); oldirqstate = disable_interrupts(I32_bit); TAILQ_REMOVE(&iq->iq_list, ih, ih_list); intr_calculatemasks(); restore_interrupts(oldirqstate); free(ih, M_DEVBUF); if (TAILQ_EMPTY(&(iq->iq_list))) iq->iq_ist = IST_NONE; }
int isa_intr_alloc(isa_chipset_tag_t ic, int mask, int type, int *irq) { int i, bestirq, count; int tmp; struct intrhand **p, *q; if (type == IST_NONE) panic("intr_alloc: bogus type"); bestirq = -1; count = -1; /* some interrupts should never be dynamically allocated */ mask &= 0xdef8; /* * XXX some interrupts will be used later (6 for fdc, 12 for pms). * the right answer is to do "breadth-first" searching of devices. */ mask &= 0xefbf; for (i = 0; i < ICU_LEN; i++) { if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0) continue; switch(intrtype[i]) { case IST_NONE: /* * if nothing's using the irq, just return it */ *irq = i; return (0); case IST_EDGE: case IST_LEVEL: if (type != intrtype[i]) continue; /* * if the irq is shareable, count the number of other * handlers, and if it's smaller than the last irq like * this, remember it * * XXX We should probably also consider the * interrupt level and stick IPL_TTY with other * IPL_TTY, etc. */ for (p = &intrhand[i], tmp = 0; (q = *p) != NULL; p = &q->ih_next, tmp++) ; if ((bestirq == -1) || (count > tmp)) { bestirq = i; count = tmp; } break; case IST_PULSE: /* this just isn't shareable */ continue; } } if (bestirq == -1) return (1); *irq = bestirq; return (0); }
/* * Set up an interrupt handler to start being called. * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM. */ void * isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level, int (*ih_fun)(void *), void *ih_arg) { struct intrq *iq; struct intrhand *ih; u_int oldirqstate; #if 0 printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level); #endif /* no point in sleeping unless someone can free memory. */ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) return (NULL); if (!LEGAL_IRQ(irq) || type == IST_NONE) panic("intr_establish: bogus irq or type"); iq = &isa_intrq[irq]; switch (iq->iq_ist) { case IST_NONE: iq->iq_ist = type; #if 0 printf("Setting irq %d to type %d - ", irq, type); #endif if (irq < 8) { outb(0x4d0, (inb(0x4d0) & ~(1 << irq)) | ((type == IST_LEVEL) ? (1 << irq) : 0)); /* printf("%02x\n", inb(0x4d0));*/ } else { outb(0x4d1, (inb(0x4d1) & ~(1 << irq)) | ((type == IST_LEVEL) ? (1 << irq) : 0)); /* printf("%02x\n", inb(0x4d1));*/ } break; case IST_EDGE: case IST_LEVEL: if (iq->iq_ist == type) break; case IST_PULSE: if (type != IST_NONE) panic("intr_establish: can't share %s with %s", isa_intr_typename(iq->iq_ist), isa_intr_typename(type)); break; } ih->ih_func = ih_fun; ih->ih_arg = ih_arg; ih->ih_ipl = level; ih->ih_irq = irq; /* do not stop us */ oldirqstate = disable_interrupts(I32_bit); TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); intr_calculatemasks(); restore_interrupts(oldirqstate); return (ih); }
int isa_intr_alloc(isa_chipset_tag_t ic, int mask, int type, int *irq) { int i, tmp, bestirq, count; struct intrhand **p, *q; struct intrsource *isp; struct cpu_info *ci; if (type == IST_NONE) panic("intr_alloc: bogus type"); ci = &cpu_info_primary; bestirq = -1; count = -1; /* some interrupts should never be dynamically allocated */ mask &= 0xdef8; /* * XXX some interrupts will be used later (6 for fdc, 12 for pms). * the right answer is to do "breadth-first" searching of devices. */ mask &= 0xefbf; mutex_enter(&cpu_lock); for (i = 0; i < NUM_LEGACY_IRQS; i++) { if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0) continue; isp = ci->ci_isources[i]; if (isp == NULL) { /* if nothing's using the irq, just return it */ *irq = i; mutex_exit(&cpu_lock); return 0; } switch(isp->is_type) { case IST_EDGE: case IST_LEVEL: if (type != isp->is_type) continue; /* * if the irq is shareable, count the number of other * handlers, and if it's smaller than the last irq like * this, remember it * * XXX We should probably also consider the * interrupt level and stick IPL_TTY with other * IPL_TTY, etc. */ for (p = &isp->is_handlers, tmp = 0; (q = *p) != NULL; p = &q->ih_next, tmp++) ; if ((bestirq == -1) || (count > tmp)) { bestirq = i; count = tmp; } break; case IST_PULSE: /* this just isn't shareable */ continue; } } mutex_exit(&cpu_lock); if (bestirq == -1) return 1; *irq = bestirq; return 0; }