summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pccbb/pccbb.c57
1 files changed, 47 insertions, 10 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index f0178e7..81f848a 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002 M. Warner Losh.
+ * Copyright (c) 2002-2003 M. Warner Losh.
* Copyright (c) 2000,2001 Jonathan Chen.
* All rights reserved.
*
@@ -399,6 +399,39 @@ cbb_probe(device_t brdev)
}
+/*
+ * Disable function interrupts by telling the bridge to generate IRQ1
+ * interrupts. These interrupts aren't really generated by the chip, since
+ * IRQ1 is reserved. Some chipsets assert INTA# inappropriately during
+ * initialization, so this helps to work around the problem.
+ */
+static void
+cbb_disable_func_intr(struct cbb_softc *sc)
+{
+ uint8_t reg;
+
+ reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
+ EXCA_INTR_IRQ_RESERVED1;
+ exca_putb(&sc->exca, EXCA_INTR, reg);
+}
+
+/*
+ * Enable function interrupts. We turn on function interrupts when the card
+ * requests an interrupt. The PCMCIA standard says that we should set
+ * the lower 4 bits to 0 to route via PCI. Note: we call this for both
+ * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus
+ * cards.
+ */
+static void
+cbb_enable_func_intr(struct cbb_softc *sc)
+{
+ uint8_t reg;
+
+ reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
+ EXCA_INTR_IRQ_NONE;
+ exca_putb(&sc->exca, EXCA_INTR, reg);
+}
+
static void
cbb_chipinit(struct cbb_softc *sc)
{
@@ -566,14 +599,16 @@ cbb_chipinit(struct cbb_softc *sc)
}
/*
- * Need to tell ExCA registers to route via PCI interrupts. There
- * are two ways to do this. Once is to set INTR_ENABLE and the
- * other is to set CSC to 0. Since both methods are mutually
- * compatible, we do both.
+ * Need to tell ExCA registers to CSC interrupts route via PCI
+ * interrupts. There are two ways to do this. Once is to set
+ * INTR_ENABLE and the other is to set CSC to 0. Since both
+ * methods are mutually compatible, we do both.
*/
exca_putb(&sc->exca, EXCA_INTR, EXCA_INTR_ENABLE);
exca_putb(&sc->exca, EXCA_CSC_INTR, 0);
+ cbb_disable_func_intr(sc);
+
/* close all memory and io windows */
pci_write_config(sc->dev, CBBR_MEMBASE0, 0xffffffff, 4);
pci_write_config(sc->dev, CBBR_MEMLIMIT0, 0, 4);
@@ -869,6 +904,7 @@ cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
ih->arg = arg;
ih->flags = flags & INTR_MPSAFE;
STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries);
+ cbb_enable_func_intr(sc);
/*
* XXX need to turn on ISA interrupts, if we ever support them, but
* XXX for now that's all we need to do.
@@ -952,7 +988,10 @@ cbb_event_thread(void *arg)
mtx_lock(&Giant);
status = cbb_get(sc, CBB_SOCKET_STATE);
DPRINTF(("Status is 0x%x\n", status));
- if (status & CBB_STATE_NOT_A_CARD) {
+ if ((status & CBB_STATE_CD) != 0) {
+ not_a_card = 0; /* We know card type */
+ cbb_removal(sc);
+ } else if (status & CBB_STATE_NOT_A_CARD) {
/*
* Up to 20 times, try to rescan the card when we
* see NOT_A_CARD.
@@ -967,10 +1006,7 @@ cbb_event_thread(void *arg)
}
} else {
not_a_card = 0; /* We know card type */
- if ((status & CBB_STATE_CD) == 0)
- cbb_insert(sc);
- else
- cbb_removal(sc);
+ cbb_insert(sc);
}
mtx_unlock(&Giant);
@@ -1092,6 +1128,7 @@ cbb_intr(void *arg)
cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
mtx_lock(&sc->mtx);
sc->flags &= ~CBB_CARD_OK;
+ cbb_disable_func_intr(sc);
DPRINTF(("Waking up thread\n"));
cv_signal(&sc->cv);
mtx_unlock(&sc->mtx);
OpenPOWER on IntegriCloud