diff options
Diffstat (limited to 'sys/arch/hp300/dev/frodo.c')
-rw-r--r-- | sys/arch/hp300/dev/frodo.c | 104 |
1 files changed, 84 insertions, 20 deletions
diff --git a/sys/arch/hp300/dev/frodo.c b/sys/arch/hp300/dev/frodo.c index 6cae385aef2..e2ee8bfbb9c 100644 --- a/sys/arch/hp300/dev/frodo.c +++ b/sys/arch/hp300/dev/frodo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frodo.c,v 1.9 2007/01/06 20:09:12 miod Exp $ */ +/* $OpenBSD: frodo.c,v 1.10 2007/01/06 20:17:43 miod Exp $ */ /* $NetBSD: frodo.c,v 1.5 1999/07/31 21:15:20 thorpej Exp $ */ /*- @@ -83,12 +83,14 @@ #include <hp300/dev/frodoreg.h> #include <hp300/dev/frodovar.h> +#include "isabr.h" + struct frodo_softc { struct device sc_dev; /* generic device glue */ volatile u_int8_t *sc_regs; /* register base */ struct isr *sc_intr[FRODO_NINTR]; /* interrupt handlers */ struct isr sc_isr; /* main interrupt handler */ - int sc_refcnt; /* number of interrupt refs */ + u_int sc_refcnt; /* number of interrupt refs */ }; int frodomatch(struct device *, void *, void *); @@ -98,6 +100,7 @@ int frodoprint(void *, const char *); int frodosubmatch(struct device *, void *, void *); int frodointr(void *); +void frodo_state(struct frodo_softc *); void frodo_imask(struct frodo_softc *, u_int16_t, u_int16_t); @@ -114,6 +117,7 @@ struct frodo_attach_args frodo_subdevs[] = { { "apci", NULL, FRODO_APCI_OFFSET(1), FRODO_INTR_APCI1 }, { "apci", NULL, FRODO_APCI_OFFSET(2), FRODO_INTR_APCI2 }, { "apci", NULL, FRODO_APCI_OFFSET(3), FRODO_INTR_APCI3 }, + { "isabr", NULL, 0, 0 }, { NULL, NULL, 0, 0 }, }; @@ -184,11 +188,17 @@ frodoattach(parent, self, aux) FRODO_WRITE(sc, FRODO_PIC_PU, 0xff); FRODO_WRITE(sc, FRODO_PIC_PL, 0xff); - /* Set interrupt polarities. */ + /* Set interrupt polarities... */ FRODO_WRITE(sc, FRODO_PIO_IPR, 0x10); - /* ...and configure for edge triggering. */ - FRODO_WRITE(sc, FRODO_PIO_IELR, 0xcf); + /* ...and configure 1-5 for edge triggering. */ + FRODO_WRITE(sc, FRODO_PIO_IELR, 0xc1); + + /* Initialize IVR high half to zero so we don't need to mask it later */ + FRODO_WRITE(sc, FRODO_PIC_IVR, 0x00); + + /* Mask ISA interrupts until an ISA interrupt handler is registered. */ + FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80); /* * We defer hooking up our interrupt handler until @@ -240,7 +250,7 @@ frodoprint(aux, pnp) return (UNCONF); } -void +int frodo_intr_establish(struct device *frdev, int line, struct isr *isr, const char *name) { @@ -252,8 +262,11 @@ frodo_intr_establish(struct device *frdev, int line, struct isr *isr, sc->sc_dev.dv_xname, line); } if (sc->sc_intr[line] != NULL) { - panic("%s: interrupt line %d already used", +#ifdef DEBUG + printf("%s: interrupt line %d already used\n", sc->sc_dev.dv_xname, line); +#endif + return (EPERM); } /* @@ -279,7 +292,15 @@ frodo_intr_establish(struct device *frdev, int line, struct isr *isr, sc->sc_intr[line] = isr; /* Enable the interrupt line. */ - frodo_imask(sc, (1 << line), 0); + frodo_imask(sc, FRODO_INTR_BIT(line), 0); + +#if NISABR > 0 + /* Unmask ISA interrupts if necessary. */ + if (FRODO_INTR_ISA(line)) + FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x00); +#endif + + return (0); } void @@ -290,13 +311,26 @@ frodo_intr_disestablish(frdev, line) struct frodo_softc *sc = (struct frodo_softc *)frdev; int newpri; +#ifdef DIAGNOSTIC if (sc->sc_intr[line] == NULL) { - panic("%s: no handler for line %d", - sc->sc_dev.dv_xname, line); + printf("%s(%s): no handler for line %d", + sc->sc_dev.dv_xname, __func__, line); + return; } +#endif sc->sc_intr[line] = NULL; - frodo_imask(sc, 0, (1 << line)); + frodo_imask(sc, 0, FRODO_INTR_BIT(line)); + +#if NISABR > 0 + /* Mask ISA interrupts if necessary. */ + if (FRODO_INTR_ISA(line)) { + if (sc->sc_intr[FRODO_INTR_ILOW] == NULL && + sc->sc_intr[FRODO_INTR_IMID] == NULL && + sc->sc_intr[FRODO_INTR_IHIGH] == NULL) + FRODO_WRITE(sc, FRODO_PIO_ISA_CONTROL, 0x80); + } +#endif /* If this was the last, unhook ourselves. */ if (sc->sc_refcnt-- == 1) { @@ -326,21 +360,29 @@ frodointr(arg) { struct frodo_softc *sc = arg; struct isr *fisr; - int line, taken = 0; + int pending, line, rc = 0; + +#ifdef DEBUG + frodo_state(sc); +#endif /* Any interrupts pending? */ - if (FRODO_GETPEND(sc) == 0) - return (0); + while ((pending = FRODO_GETPEND(sc)) != 0) { + rc++; - do { /* * Get pending interrupt; this also clears it for us. */ - line = FRODO_IPEND(sc); + line = FRODO_READ(sc, FRODO_PIC_ACK) /* & 0x0f */; + fisr = sc->sc_intr[line]; if (fisr == NULL) { printf("%s: unhandled interrupt on line %d\n", sc->sc_dev.dv_xname, line); +#ifdef DEBUG + /* Disable interrupt source */ + frodo_imask(sc, 0, FRODO_INTR_BIT(line)); +#endif } else { if ((*fisr->isr_func)(fisr->isr_arg) != 0) { fisr->isr_count.ec_count++; @@ -349,11 +391,17 @@ frodointr(arg) sc->sc_dev.dv_xname, line); } } - if (taken++ > 100) - panic("frodointr: looping, line %d fisr %p", line, fisr); - } while (FRODO_GETPEND(sc) != 0); - return (1); + if (rc > 100) + panic("frodointr: looping, pending %x line %d fisr %p", + pending, line, fisr); + +#ifdef DEBUG + frodo_state(sc); +#endif + } + + return (rc); } void @@ -370,3 +418,19 @@ frodo_imask(sc, set, clear) FRODO_SETMASK(sc, imask); } + +#ifdef DEBUG +void +frodo_state(struct frodo_softc *sc) +{ + int i; + + printf("%s state:", sc->sc_dev.dv_xname); + for (i = 0xc0; i < 0x100; i += 4) { + printf(" %02x", FRODO_READ(sc, i)); + if (i == 0xcc || i == 0xdc || i == 0xec) + printf(" /"); + } + printf("\n"); +} +#endif |