summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2004-08-12 06:50:29 +0000
committerimp <imp@FreeBSD.org>2004-08-12 06:50:29 +0000
commit2d3c2de7f059f18e9a1bf5fc5f28a4c05d4c3d67 (patch)
treecdc59ea0b1ff2b64441b90225ec989ce164f67ce /sys/dev
parent885cdf40be7de7817e04fa76d24b1767513f4f55 (diff)
downloadFreeBSD-src-2d3c2de7f059f18e9a1bf5fc5f28a4c05d4c3d67.zip
FreeBSD-src-2d3c2de7f059f18e9a1bf5fc5f28a4c05d4c3d67.tar.gz
Move towards isa attachment for pccbb. This is a work in progress, but
works well with the pci attachment.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pccbb/pccbb.c823
-rw-r--r--sys/dev/pccbb/pccbb_isa.c221
-rw-r--r--sys/dev/pccbb/pccbb_pci.c655
-rw-r--r--sys/dev/pccbb/pccbbvar.h77
4 files changed, 1086 insertions, 690 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index d9a65f9..418696e 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -59,6 +59,9 @@
/*
* Driver for PCI to CardBus Bridge chips
+ * and PCI to PCMCIA Bridge chips
+ * and ISA to PCMCIA host adapters
+ * and C Bus to PCMCIA host adapters
*
* References:
* TI Datasheets:
@@ -76,20 +79,20 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/proc.h>
+#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
#include <sys/sysctl.h>
-#include <sys/kthread.h>
-#include <sys/bus.h>
+#include <sys/systm.h>
#include <machine/bus.h>
-#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/pci/pcireg.h>
@@ -124,90 +127,7 @@ __FBSDID("$FreeBSD$");
#define CBB_START_32_IO 0x1000
#define CBB_START_16_IO 0x100
-struct yenta_chipinfo {
- uint32_t yc_id;
- const char *yc_name;
- int yc_chiptype;
-} yc_chipsets[] = {
- /* Texas Instruments chips */
- {PCIC_ID_TI1031, "TI1031 PCI-PC Card Bridge", CB_TI113X},
- {PCIC_ID_TI1130, "TI1130 PCI-CardBus Bridge", CB_TI113X},
- {PCIC_ID_TI1131, "TI1131 PCI-CardBus Bridge", CB_TI113X},
-
- {PCIC_ID_TI1210, "TI1210 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1211, "TI1211 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1220, "TI1220 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1221, "TI1221 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1225, "TI1225 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1250, "TI1250 PCI-CardBus Bridge", CB_TI125X},
- {PCIC_ID_TI1251, "TI1251 PCI-CardBus Bridge", CB_TI125X},
- {PCIC_ID_TI1251B,"TI1251B PCI-CardBus Bridge",CB_TI125X},
- {PCIC_ID_TI1260, "TI1260 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1260B,"TI1260B PCI-CardBus Bridge",CB_TI12XX},
- {PCIC_ID_TI1410, "TI1410 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1420, "TI1420 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1421, "TI1421 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1450, "TI1450 PCI-CardBus Bridge", CB_TI125X}, /*SIC!*/
- {PCIC_ID_TI1451, "TI1451 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1510, "TI1510 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1515, "TI1515 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1520, "TI1520 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1530, "TI1530 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI1620, "TI1620 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI4410, "TI4410 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI4450, "TI4450 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI4451, "TI4451 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI4510, "TI4510 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI4520, "TI4520 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI6411, "TI[67]x[12]1 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI6420, "TI[67]x20 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI6420SC, "TI[67]x20 (SC) PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7410, "TI7410 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7510, "TI7510 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7610, "TI7610 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7610M, "TI7610 (M) PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7610SD, "TI7610 (SD) PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_TI7610MS, "TI7610 (MS) PCI-CardBus Bridge", CB_TI12XX},
-
- /* ENE */
- {PCIC_ID_ENE_CB710, "ENE CB710 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_ENE_CB720, "ENE CB720 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_ENE_CB1211, "ENE CB1211 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_ENE_CB1225, "ENE CB1225 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_ENE_CB1410, "ENE CB1410 PCI-CardBus Bridge", CB_TI12XX},
- {PCIC_ID_ENE_CB1420, "ENE CB1420 PCI-CardBus Bridge", CB_TI12XX},
-
- /* Ricoh chips */
- {PCIC_ID_RICOH_RL5C465, "RF5C465 PCI-CardBus Bridge", CB_RF5C46X},
- {PCIC_ID_RICOH_RL5C466, "RF5C466 PCI-CardBus Bridge", CB_RF5C46X},
- {PCIC_ID_RICOH_RL5C475, "RF5C475 PCI-CardBus Bridge", CB_RF5C47X},
- {PCIC_ID_RICOH_RL5C476, "RF5C476 PCI-CardBus Bridge", CB_RF5C47X},
- {PCIC_ID_RICOH_RL5C477, "RF5C477 PCI-CardBus Bridge", CB_RF5C47X},
- {PCIC_ID_RICOH_RL5C478, "RF5C478 PCI-CardBus Bridge", CB_RF5C47X},
-
- /* Toshiba products */
- {PCIC_ID_TOPIC95, "ToPIC95 PCI-CardBus Bridge", CB_TOPIC95},
- {PCIC_ID_TOPIC95B, "ToPIC95B PCI-CardBus Bridge", CB_TOPIC95},
- {PCIC_ID_TOPIC97, "ToPIC97 PCI-CardBus Bridge", CB_TOPIC97},
- {PCIC_ID_TOPIC100, "ToPIC100 PCI-CardBus Bridge", CB_TOPIC97},
-
- /* Cirrus Logic */
- {PCIC_ID_CLPD6832, "CLPD6832 PCI-CardBus Bridge", CB_CIRRUS},
- {PCIC_ID_CLPD6833, "CLPD6833 PCI-CardBus Bridge", CB_CIRRUS},
- {PCIC_ID_CLPD6834, "CLPD6834 PCI-CardBus Bridge", CB_CIRRUS},
-
- /* 02Micro */
- {PCIC_ID_OZ6832, "O2Micro OZ6832/6833 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ6860, "O2Micro OZ6836/6860 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ6872, "O2Micro OZ6812/6872 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ6912, "O2Micro OZ6912/6972 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ6922, "O2Micro OZ6922 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ6933, "O2Micro OZ6933 PCI-CardBus Bridge", CB_O2MICRO},
- {PCIC_ID_OZ711E1, "O2Micro OZ711E1 PCI-CardBus Bridge", CB_O2MICRO},
-
- /* sentinel */
- {0 /* null id */, "unknown", CB_UNKNOWN},
-};
+devclass_t cbb_devclass;
/* sysctl vars */
SYSCTL_NODE(_hw, OID_AUTO, cbb, CTLFLAG_RD, 0, "CBB parameters");
@@ -236,25 +156,10 @@ TUNABLE_INT("hw.cbb.debug", &cbb_debug);
SYSCTL_ULONG(_hw_cbb, OID_AUTO, debug, CTLFLAG_RW, &cbb_debug, 0,
"Verbose cardbus bridge debugging");
-static int cbb_chipset(uint32_t pci_id, const char **namep);
-static int cbb_probe(device_t brdev);
-static void cbb_chipinit(struct cbb_softc *sc);
-static int cbb_attach(device_t brdev);
-static int cbb_detach(device_t brdev);
-static int cbb_shutdown(device_t brdev);
-static void cbb_driver_added(device_t brdev, driver_t *driver);
-static void cbb_child_detached(device_t brdev, device_t child);
-static void cbb_event_thread(void *arg);
static void cbb_insert(struct cbb_softc *sc);
static void cbb_removal(struct cbb_softc *sc);
-static void cbb_intr(void *arg);
static int cbb_detect_voltage(device_t brdev);
-static int cbb_power(device_t brdev, int volts);
static void cbb_cardbus_reset(device_t brdev);
-static int cbb_cardbus_power_enable_socket(device_t brdev,
- device_t child);
-static void cbb_cardbus_power_disable_socket(device_t brdev,
- device_t child);
static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start,
uint32_t end);
static int cbb_cardbus_mem_open(device_t brdev, int win,
@@ -269,52 +174,11 @@ static struct resource *cbb_cardbus_alloc_resource(device_t brdev,
u_long end, u_long count, u_int flags);
static int cbb_cardbus_release_resource(device_t brdev, device_t child,
int type, int rid, struct resource *res);
-static int cbb_power_enable_socket(device_t brdev, device_t child);
-static void cbb_power_disable_socket(device_t brdev, device_t child);
-static int cbb_activate_resource(device_t brdev, device_t child,
- int type, int rid, struct resource *r);
-static int cbb_deactivate_resource(device_t brdev, device_t child,
- int type, int rid, struct resource *r);
-static struct resource *cbb_alloc_resource(device_t brdev, device_t child,
- int type, int *rid, u_long start, u_long end, u_long count,
- u_int flags);
-static int cbb_release_resource(device_t brdev, device_t child,
- int type, int rid, struct resource *r);
-static int cbb_read_ivar(device_t brdev, device_t child, int which,
- uintptr_t *result);
-static int cbb_write_ivar(device_t brdev, device_t child, int which,
- uintptr_t value);
-static int cbb_maxslots(device_t brdev);
-static uint32_t cbb_read_config(device_t brdev, int b, int s, int f,
- int reg, int width);
-static void cbb_write_config(device_t brdev, int b, int s, int f,
- int reg, uint32_t val, int width);
-
-/*
- */
-static __inline void
-cbb_set(struct cbb_softc *sc, uint32_t reg, uint32_t val)
-{
- bus_space_write_4(sc->bst, sc->bsh, reg, val);
-}
-
-static __inline uint32_t
-cbb_get(struct cbb_softc *sc, uint32_t reg)
-{
- return (bus_space_read_4(sc->bst, sc->bsh, reg));
-}
-
-static __inline void
-cbb_setb(struct cbb_softc *sc, uint32_t reg, uint32_t bits)
-{
- cbb_set(sc, reg, cbb_get(sc, reg) | bits);
-}
-
-static __inline void
-cbb_clrb(struct cbb_softc *sc, uint32_t reg, uint32_t bits)
-{
- cbb_set(sc, reg, cbb_get(sc, reg) & ~bits);
-}
+static int cbb_cardbus_power_enable_socket(device_t brdev,
+ device_t child);
+static void cbb_cardbus_power_disable_socket(device_t brdev,
+ device_t child);
+static void cbb_func_intr(void *arg);
static void
cbb_remove_res(struct cbb_softc *sc, struct resource *res)
@@ -375,56 +239,6 @@ cbb_destroy_res(struct cbb_softc *sc)
}
}
-/************************************************************************/
-/* Probe/Attach */
-/************************************************************************/
-
-static int
-cbb_chipset(uint32_t pci_id, const char **namep)
-{
- struct yenta_chipinfo *ycp;
-
- for (ycp = yc_chipsets; ycp->yc_id != 0 && pci_id != ycp->yc_id; ++ycp)
- continue;
- if (namep != NULL)
- *namep = ycp->yc_name;
- return (ycp->yc_chiptype);
-}
-
-static int
-cbb_probe(device_t brdev)
-{
- const char *name;
- uint32_t progif;
- uint32_t subclass;
-
- /*
- * Do we know that we support the chipset? If so, then we
- * accept the device.
- */
- if (cbb_chipset(pci_get_devid(brdev), &name) != CB_UNKNOWN) {
- device_set_desc(brdev, name);
- return (0);
- }
-
- /*
- * We do support generic CardBus bridges. All that we've seen
- * to date have progif 0 (the Yenta spec, and successors mandate
- * this). We do not support PCI PCMCIA bridges (with one exception)
- * with this driver since they generally are I/O mapped. Those
- * are supported by the pcic driver. This should help us be more
- * future proof.
- */
- subclass = pci_get_subclass(brdev);
- progif = pci_get_progif(brdev);
- if (subclass == PCIS_BRIDGE_CARDBUS && progif == 0) {
- device_set_desc(brdev, "PCI-CardBus Bridge");
- return (0);
- }
- return (ENXIO);
-}
-
-
/*
* Disable function interrupts by telling the bridge to generate IRQ1
* interrupts. These interrupts aren't really generated by the chip, since
@@ -436,15 +250,15 @@ cbb_probe(device_t brdev)
* XXX actually signal IRQ1 over their serial interrupt connections to
* XXX the south bridge. Disable it it for now.
*/
-static void
+void
cbb_disable_func_intr(struct cbb_softc *sc)
{
#if 0
uint8_t reg;
- reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
+ reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
EXCA_INTR_IRQ_RESERVED1;
- exca_putb(&sc->exca, EXCA_INTR, reg);
+ exca_putb(&sc->exca[0], EXCA_INTR, reg);
#endif
}
@@ -460,376 +274,12 @@ cbb_enable_func_intr(struct cbb_softc *sc)
{
uint8_t reg;
- reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
+ reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
EXCA_INTR_IRQ_NONE;
- exca_putb(&sc->exca, EXCA_INTR, reg);
+ exca_putb(&sc->exca[0], EXCA_INTR, reg);
}
-static void
-cbb_chipinit(struct cbb_softc *sc)
-{
- uint32_t mux, sysctrl, reg;
-
- /* Set CardBus latency timer */
- if (pci_read_config(sc->dev, PCIR_SECLAT_1, 1) < 0x20)
- pci_write_config(sc->dev, PCIR_SECLAT_1, 0x20, 1);
-
- /* Set PCI latency timer */
- if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20)
- pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1);
-
- /* Enable memory access */
- PCI_MASK_CONFIG(sc->dev, PCIR_COMMAND,
- | PCIM_CMD_MEMEN
- | PCIM_CMD_PORTEN
- | PCIM_CMD_BUSMASTEREN, 2);
-
- /* disable Legacy IO */
- switch (sc->chipset) {
- case CB_RF5C46X:
- PCI_MASK_CONFIG(sc->dev, CBBR_BRIDGECTRL,
- & ~(CBBM_BRIDGECTRL_RL_3E0_EN |
- CBBM_BRIDGECTRL_RL_3E2_EN), 2);
- break;
- default:
- pci_write_config(sc->dev, CBBR_LEGACY, 0x0, 4);
- break;
- }
-
- /* Use PCI interrupt for interrupt routing */
- PCI_MASK2_CONFIG(sc->dev, CBBR_BRIDGECTRL,
- & ~(CBBM_BRIDGECTRL_MASTER_ABORT |
- CBBM_BRIDGECTRL_INTR_IREQ_EN),
- | CBBM_BRIDGECTRL_WRITE_POST_EN,
- 2);
-
- /*
- * XXX this should be a function table, ala OLDCARD. This means
- * that we could more easily support ISA interrupts for pccard
- * cards if we had to.
- */
- switch (sc->chipset) {
- case CB_TI113X:
- /*
- * The TI 1031, TI 1130 and TI 1131 all require another bit
- * be set to enable PCI routing of interrupts, and then
- * a bit for each of the CSC and Function interrupts we
- * want routed.
- */
- PCI_MASK_CONFIG(sc->dev, CBBR_CBCTRL,
- | CBBM_CBCTRL_113X_PCI_INTR |
- CBBM_CBCTRL_113X_PCI_CSC | CBBM_CBCTRL_113X_PCI_IRQ_EN,
- 1);
- PCI_MASK_CONFIG(sc->dev, CBBR_DEVCTRL,
- & ~(CBBM_DEVCTRL_INT_SERIAL |
- CBBM_DEVCTRL_INT_PCI), 1);
- break;
- case CB_TI12XX:
- /*
- * Some TI 12xx (and [14][45]xx) based pci cards
- * sometimes have issues with the MFUNC register not
- * being initialized due to a bad EEPROM on board.
- * Laptops that this matters on have this register
- * properly initialized.
- *
- * The TI125X parts have a different register.
- */
- mux = pci_read_config(sc->dev, CBBR_MFUNC, 4);
- sysctrl = pci_read_config(sc->dev, CBBR_SYSCTRL, 4);
- if (mux == 0) {
- mux = (mux & ~CBBM_MFUNC_PIN0) |
- CBBM_MFUNC_PIN0_INTA;
- if ((sysctrl & CBBM_SYSCTRL_INTRTIE) == 0)
- mux = (mux & ~CBBM_MFUNC_PIN1) |
- CBBM_MFUNC_PIN1_INTB;
- pci_write_config(sc->dev, CBBR_MFUNC, mux, 4);
- }
- /*FALLTHROUGH*/
- case CB_TI125X:
- /*
- * Disable zoom video. Some machines initialize this
- * improperly and exerpience has shown that this helps
- * prevent strange behavior.
- */
- pci_write_config(sc->dev, CBBR_MMCTRL, 0, 4);
- break;
- case CB_O2MICRO:
- /*
- * Issue #1: INT# generated at the same time as
- * selected ISA IRQ. When IREQ# or STSCHG# is active,
- * in addition to the ISA IRQ being generated, INT#
- * will also be generated at the same time.
- *
- * Some of the older controllers have an issue in
- * which the slot's PCI INT# will be asserted whenever
- * IREQ# or STSCGH# is asserted even if ExCA registers
- * 03h or 05h have an ISA IRQ selected.
- *
- * The fix for this issue, which will work for any
- * controller (old or new), is to set ExCA registers
- * 3Ah (slot 0) & 7Ah (slot 1) bits 7:4 = 1010b.
- * These bits are undocumented. By setting this
- * register (of each slot) to '1010xxxxb' a routing of
- * IREQ# to INTC# and STSCHG# to INTC# is selected.
- * Since INTC# isn't connected there will be no
- * unexpected PCI INT when IREQ# or STSCHG# is active.
- * However, INTA# (slot 0) or INTB# (slot 1) will
- * still be correctly generated if NO ISA IRQ is
- * selected (ExCA regs 03h or 05h are cleared).
- */
- reg = exca_getb(&sc->exca, EXCA_O2MICRO_CTRL_C);
- reg = (reg & 0x0f) |
- EXCA_O2CC_IREQ_INTC | EXCA_O2CC_STSCHG_INTC;
- exca_putb(&sc->exca, EXCA_O2MICRO_CTRL_C, reg);
-
- break;
- case CB_TOPIC97:
- /*
- * Disable Zoom Video, ToPIC 97, 100.
- */
- pci_write_config(sc->dev, CBBR_TOPIC_ZV_CONTROL, 0, 1);
- /*
- * ToPIC 97, 100
- * At offset 0xa1: INTERRUPT CONTROL register
- * 0x1: Turn on INT interrupts.
- */
- PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_INTCTRL,
- | CBBM_TOPIC_INTCTRL_INTIRQSEL, 1);
- goto topic_common;
- case CB_TOPIC95:
- /*
- * SOCKETCTRL appears to be TOPIC 95/B specific
- */
- PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_SOCKETCTRL,
- | CBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL, 4);
-
- topic_common:;
- /*
- * At offset 0xa0: SLOT CONTROL
- * 0x80 Enable CardBus Functionality
- * 0x40 Enable CardBus and PC Card registers
- * 0x20 Lock ID in exca regs
- * 0x10 Write protect ID in config regs
- * Clear the rest of the bits, which defaults the slot
- * in legacy mode to 0x3e0 and offset 0. (legacy
- * mode is determined elsewhere)
- */
- pci_write_config(sc->dev, CBBR_TOPIC_SLOTCTRL,
- CBBM_TOPIC_SLOTCTRL_SLOTON |
- CBBM_TOPIC_SLOTCTRL_SLOTEN |
- CBBM_TOPIC_SLOTCTRL_ID_LOCK |
- CBBM_TOPIC_SLOTCTRL_ID_WP, 1);
-
- /*
- * At offset 0xa3 Card Detect Control Register
- * 0x80 CARDBUS enbale
- * 0x01 Cleared for hardware change detect
- */
- PCI_MASK2_CONFIG(sc->dev, CBBR_TOPIC_CDC,
- | CBBM_TOPIC_CDC_CARDBUS,
- & ~CBBM_TOPIC_CDC_SWDETECT, 4);
- break;
- }
-
- /*
- * 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);
- pci_write_config(sc->dev, CBBR_MEMBASE1, 0xffffffff, 4);
- pci_write_config(sc->dev, CBBR_MEMLIMIT1, 0, 4);
- pci_write_config(sc->dev, CBBR_IOBASE0, 0xffffffff, 4);
- pci_write_config(sc->dev, CBBR_IOLIMIT0, 0, 4);
- pci_write_config(sc->dev, CBBR_IOBASE1, 0xffffffff, 4);
- pci_write_config(sc->dev, CBBR_IOLIMIT1, 0, 4);
-}
-
-#ifndef BURN_BRIDGES
-/*
- * Still need this because the pci code only does power for type 0
- * header devices.
- */
-static void
-cbb_powerstate_d0(device_t dev)
-{
- u_int32_t membase, irq;
-
- if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
- /* Save important PCI config data. */
- membase = pci_read_config(dev, CBBR_SOCKBASE, 4);
- irq = pci_read_config(dev, PCIR_INTLINE, 4);
-
- /* Reset the power state. */
- device_printf(dev, "chip is in D%d power mode "
- "-- setting to D0\n", pci_get_powerstate(dev));
-
- pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-
- /* Restore PCI config data. */
- pci_write_config(dev, CBBR_SOCKBASE, membase, 4);
- pci_write_config(dev, PCIR_INTLINE, irq, 4);
- }
-}
-#endif
-
-/*
- * Print out the config space
- */
-static void
-cbb_print_config(device_t dev)
-{
- int i;
-
- device_printf(dev, "PCI Configuration space:");
- for (i = 0; i < 256; i += 4) {
- if (i % 16 == 0)
- printf("\n 0x%02x: ", i);
- printf("0x%08x ", pci_read_config(dev, i, 4));
- }
- printf("\n");
-}
-
-static int
-cbb_attach(device_t brdev)
-{
- static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
- struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
- int rid, bus, pribus;
- device_t parent;
-
- parent = device_get_parent(brdev);
- mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
- cv_init(&sc->cv, "cbb cv");
- sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL);
- sc->dev = brdev;
- sc->cbdev = NULL;
- sc->exca.pccarddev = NULL;
- sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
- sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
- SLIST_INIT(&sc->rl);
- STAILQ_INIT(&sc->intr_handlers);
-#ifndef BURN_BRIDGES
- cbb_powerstate_d0(brdev);
-#endif
-
- rid = CBBR_SOCKBASE;
- sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
- RF_ACTIVE);
- if (!sc->base_res) {
- device_printf(brdev, "Could not map register memory\n");
- mtx_destroy(&sc->mtx);
- cv_destroy(&sc->cv);
- return (ENOMEM);
- } else {
- DEVPRINTF((brdev, "Found memory at %08lx\n",
- rman_get_start(sc->base_res)));
- }
-
- sc->bst = rman_get_bustag(sc->base_res);
- sc->bsh = rman_get_bushandle(sc->base_res);
- exca_init(&sc->exca, brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
- sc->exca.flags |= EXCA_HAS_MEMREG_WIN;
- sc->exca.chipset = EXCA_CARDBUS;
- cbb_chipinit(sc);
-
- /*
- * This is a gross hack. We should be scanning the entire pci
- * tree, assigning bus numbers in a way such that we (1) can
- * reserve 1 extra bus just in case and (2) all sub busses
- * are in an appropriate range.
- */
- bus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
- pribus = pcib_get_bus(parent);
- DEVPRINTF((brdev, "Secondary bus is %d\n", bus));
- if (bus == 0) {
- if (curr_bus_number <= pribus)
- curr_bus_number = pribus + 1;
- if (pci_read_config(brdev, PCIR_PRIBUS_2, 1) != pribus) {
- DEVPRINTF((brdev, "Setting primary bus to %d\n", pribus));
- pci_write_config(brdev, PCIR_PRIBUS_2, pribus, 1);
- }
- bus = curr_bus_number;
- DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", bus,
- bus + 1));
- sc->secbus = bus;
- sc->subbus = bus + 1;
- pci_write_config(brdev, PCIR_SECBUS_2, bus, 1);
- pci_write_config(brdev, PCIR_SUBBUS_2, bus + 1, 1);
- curr_bus_number += 2;
- }
-
- /* attach children */
- sc->cbdev = device_add_child(brdev, "cardbus", -1);
- if (sc->cbdev == NULL)
- DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n"));
- else if (device_probe_and_attach(sc->cbdev) != 0)
- DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n"));
-
- sc->exca.pccarddev = device_add_child(brdev, "pccard", -1);
- if (sc->exca.pccarddev == NULL)
- DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n"));
- else if (device_probe_and_attach(sc->exca.pccarddev) != 0)
- DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n"));
-
- /* Map and establish the interrupt. */
- rid = 0;
- sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid,
- RF_SHAREABLE | RF_ACTIVE);
- if (sc->irq_res == NULL) {
- printf("cbb: Unable to map IRQ...\n");
- goto err;
- }
-
- if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE,
- cbb_intr, sc, &sc->intrhand)) {
- device_printf(brdev, "couldn't establish interrupt");
- goto err;
- }
-
- /* reset 16-bit pcmcia bus */
- exca_clrb(&sc->exca, EXCA_INTR, EXCA_INTR_RESET);
-
- /* turn off power */
- cbb_power(brdev, CARD_OFF);
-
- /* CSC Interrupt: Card detect interrupt on */
- cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
-
- /* reset interrupt */
- cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));
-
- if (bootverbose)
- cbb_print_config(brdev);
-
- /* Start the thread */
- if (kthread_create(cbb_event_thread, sc, &sc->event_thread, 0, 0,
- "%s", device_get_nameunit(brdev))) {
- device_printf(brdev, "unable to create event thread.\n");
- panic("cbb_create_event_thread");
- }
- return (0);
-err:
- if (sc->irq_res)
- bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
- if (sc->base_res) {
- bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
- sc->base_res);
- }
- mtx_destroy(&sc->mtx);
- cv_destroy(&sc->cv);
- return (ENOMEM);
-}
-
-static int
+int
cbb_detach(device_t brdev)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -852,6 +302,10 @@ cbb_detach(device_t brdev)
return (ENXIO);
mtx_lock(&sc->mtx);
+ /*
+ * XXX do we teardown all the ones still registered to guard against
+ * XXX buggy client drivers?
+ */
bus_teardown_intr(brdev, sc->irq_res, sc->intrhand);
sc->flags |= CBB_KTHREAD_DONE;
if (sc->flags & CBB_KTHREAD_RUNNING) {
@@ -868,20 +322,20 @@ cbb_detach(device_t brdev)
return (0);
}
-static int
+int
cbb_shutdown(device_t brdev)
{
struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
/* properly reset everything at shutdown */
PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2);
- exca_clrb(&sc->exca, EXCA_INTR, EXCA_INTR_RESET);
+ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
cbb_set(sc, CBB_SOCKET_MASK, 0);
cbb_power(brdev, CARD_OFF);
- exca_putb(&sc->exca, EXCA_ADDRWIN_ENABLE, 0);
+ exca_putb(&sc->exca[0], EXCA_ADDRWIN_ENABLE, 0);
pci_write_config(brdev, CBBR_MEMBASE0, 0, 4);
pci_write_config(brdev, CBBR_MEMLIMIT0, 0, 4);
pci_write_config(brdev, CBBR_MEMBASE1, 0, 4);
@@ -894,18 +348,15 @@ cbb_shutdown(device_t brdev)
return (0);
}
-static int
+int
cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
int flags, driver_intr_t *intr, void *arg, void **cookiep)
{
struct cbb_intrhand *ih;
struct cbb_softc *sc = device_get_softc(dev);
+ int err;
/*
- * You aren't allowed to have fast interrupts for pccard/cardbus
- * things since those interrupts are PCI and shared. Since we use
- * the PCI interrupt for the status change interrupts, it can't be
- * free for use by the driver. Fast interrupts must not be shared.
* Well, this is no longer strictly true. You can have multiple
* FAST ISRs, but can't mix fast and slow, so we have to assume
* least common denominator until the base system supports mixing
@@ -919,32 +370,44 @@ cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
*cookiep = ih;
ih->intr = intr;
ih->arg = arg;
- ih->flags = flags & INTR_MPSAFE;
- STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries);
- cbb_enable_func_intr(sc);
+ ih->sc = sc;
/*
* XXX need to turn on ISA interrupts, if we ever support them, but
* XXX for now that's all we need to do.
*/
- return (0);
+ err = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags,
+ cbb_func_intr, ih, &ih->cookie);
+ if (err != 0) {
+ free(ih, M_DEVBUF);
+ return (err);
+ }
+ STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries);
+ cbb_enable_func_intr(sc);
+ sc->flags |= CBB_CARD_OK;
+ return 0;
}
-static int
+int
cbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
void *cookie)
{
struct cbb_intrhand *ih;
struct cbb_softc *sc = device_get_softc(dev);
+ int err;
/* XXX Need to do different things for ISA interrupts. */
ih = (struct cbb_intrhand *) cookie;
+ err = BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq,
+ ih->cookie);
+ if (err != 0)
+ return (err);
STAILQ_REMOVE(&sc->intr_handlers, ih, cbb_intrhand, entries);
free(ih, M_DEVBUF);
return (0);
}
-static void
+void
cbb_driver_added(device_t brdev, driver_t *driver)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -971,12 +434,12 @@ cbb_driver_added(device_t brdev, driver_t *driver)
}
}
-static void
+void
cbb_child_detached(device_t brdev, device_t child)
{
struct cbb_softc *sc = device_get_softc(brdev);
- if (child != sc->cbdev && child != sc->exca.pccarddev)
+ if (child != sc->cbdev && child != sc->exca[0].pccarddev)
device_printf(brdev, "Unknown child detached: %s\n",
device_get_nameunit(child));
}
@@ -985,7 +448,7 @@ cbb_child_detached(device_t brdev, device_t child)
/* Kthreads */
/************************************************************************/
-static void
+void
cbb_event_thread(void *arg)
{
struct cbb_softc *sc = arg;
@@ -1070,13 +533,13 @@ cbb_insert(struct cbb_softc *sc)
sockevent, sockstate));
if (sockstate & CBB_STATE_R2_CARD) {
- if (sc->exca.pccarddev)
- sc->flags |= CBB_16BIT_CARD | CBB_CARD_OK;
- exca_insert(&sc->exca);
+ if (sc->exca[0].pccarddev) {
+ sc->flags |= CBB_16BIT_CARD;
+ exca_insert(&sc->exca[0]);
+ }
} else if (sockstate & CBB_STATE_CB_CARD) {
if (sc->cbdev != NULL) {
sc->flags &= ~CBB_16BIT_CARD;
- sc->flags |= CBB_CARD_OK;
if (CARD_ATTACH_CARD(sc->cbdev) != 0)
device_printf(sc->dev,
"CardBus card activation failed\n");
@@ -1096,8 +559,9 @@ cbb_insert(struct cbb_softc *sc)
static void
cbb_removal(struct cbb_softc *sc)
{
+ sc->flags &= ~CBB_CARD_OK;
if (sc->flags & CBB_16BIT_CARD) {
- exca_removal(&sc->exca);
+ exca_removal(&sc->exca[0]);
} else {
if (sc->cbdev != NULL)
CARD_DETACH_CARD(sc->cbdev);
@@ -1109,12 +573,55 @@ cbb_removal(struct cbb_softc *sc)
/* Interrupt Handler */
/************************************************************************/
+/*
+ * Since we touch hardware in the worst case, we don't need to use atomic
+ * ops on the CARD_OK tests. They would save us a trip to the hardware
+ * if CARD_OK was recently cleared and the caches haven't updated yet.
+ * However, an atomic op costs between 100-200 CPU cycles. On a 3GHz
+ * machine, this is about 33-66ns, whereas a trip the the hardware
+ * is about that. On slower machines, the cost is even higher, so the
+ * trip to the hardware is cheaper and achieves the same ends that
+ * a fully locked operation would give us.
+ *
+ * This is a separate routine because we'd have to use locking and/or
+ * other synchronization in cbb_intr to do this there. That would be
+ * even more expensive.
+ *
+ * I need to investigate what this means for a SMP machine with multiple
+ * CPUs servicing the ISR when an eject happens. In the case of a dirty
+ * eject, CD glitches and we might read 'card present' from the hardware
+ * due to this jitter. If we assumed that cbb_intr() ran before
+ * cbb_func_intr(), we could just check the SOCKET_MASK register and if
+ * CD changes were clear there, then we'd know the card was gone.
+ */
static void
+cbb_func_intr(void *arg)
+{
+ struct cbb_intrhand *ih = (struct cbb_intrhand *)arg;
+ struct cbb_softc *sc = ih->sc;
+
+ /*
+ * Make sure that the card is really there.
+ */
+ if ((sc->flags & CBB_CARD_OK) == 0)
+ return;
+ if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
+ sc->flags &= ~CBB_CARD_OK;
+ return;
+ }
+
+ /*
+ * nb: don't have to check for giant or not, since that's done
+ * in the ISR dispatch
+ */
+ (*ih->intr)(ih->arg);
+}
+
+void
cbb_intr(void *arg)
{
struct cbb_softc *sc = arg;
uint32_t sockevent;
- struct cbb_intrhand *ih;
/*
* This ISR needs work XXX
@@ -1158,20 +665,7 @@ cbb_intr(void *arg)
* We have to call this unconditionally because some bridges deliver
* the even independent of the CBB_SOCKET_EVENT_CD above.
*/
- exca_getb(&sc->exca, EXCA_CSC);
-
- /*
- * If the card is OK, call all the interrupt handlers.
- */
- if (sc->flags & CBB_CARD_OK) {
- STAILQ_FOREACH(ih, &sc->intr_handlers, entries) {
- if ((ih->flags & INTR_MPSAFE) == 0)
- mtx_lock(&Giant);
- (*ih->intr)(ih->arg);
- if ((ih->flags & INTR_MPSAFE) == 0)
- mtx_unlock(&Giant);
- }
- }
+ exca_getb(&sc->exca[0], EXCA_CSC);
}
/************************************************************************/
@@ -1228,8 +722,8 @@ cbb_o2micro_power_hack(struct cbb_softc *sc)
* (because IRQ1 is selected), and IRQ1 won't be asserted
* because our controllers don't generate IRQ1.
*/
- reg = exca_getb(&sc->exca, EXCA_INTR);
- exca_putb(&sc->exca, EXCA_INTR, (reg & 0xf0) | 1);
+ reg = exca_getb(&sc->exca[0], EXCA_INTR);
+ exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1);
return (reg);
}
@@ -1241,10 +735,10 @@ cbb_o2micro_power_hack(struct cbb_softc *sc)
static void
cbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg)
{
- exca_putb(&sc->exca, EXCA_INTR, reg);
+ exca_putb(&sc->exca[0], EXCA_INTR, reg);
}
-static int
+int
cbb_power(device_t brdev, int volts)
{
uint32_t status, sock_ctrl;
@@ -1346,7 +840,7 @@ cbb_do_power(device_t brdev)
int voltage;
/* Don't enable OE */
- exca_clrb(&sc->exca, EXCA_PWRCTL, EXCA_PWRCTL_OE);
+ exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE);
/* Prefer lowest voltage supported */
voltage = cbb_detect_voltage(brdev);
@@ -1693,7 +1187,7 @@ cbb_pcic_power_enable_socket(device_t brdev, device_t child)
err = cbb_do_power(brdev);
if (err)
return (err);
- exca_reset(&sc->exca, child);
+ exca_reset(&sc->exca[0], child);
return (0);
}
@@ -1706,12 +1200,12 @@ cbb_pcic_power_disable_socket(device_t brdev, device_t child)
DPRINTF(("cbb_pcic_socket_disable\n"));
/* reset signal asserting... */
- exca_clrb(&sc->exca, EXCA_INTR, EXCA_INTR_RESET);
+ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
DELAY(2*1000);
/* power down the socket */
cbb_power(brdev, CARD_OFF);
- exca_clrb(&sc->exca, EXCA_PWRCTL, EXCA_PWRCTL_OE);
+ exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE);
/* wait 300ms until power fails (Tpf). */
DELAY(300 * 1000);
@@ -1721,7 +1215,7 @@ cbb_pcic_power_disable_socket(device_t brdev, device_t child)
/* POWER methods */
/************************************************************************/
-static int
+int
cbb_power_enable_socket(device_t brdev, device_t child)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -1732,7 +1226,7 @@ cbb_power_enable_socket(device_t brdev, device_t child)
return (cbb_cardbus_power_enable_socket(brdev, child));
}
-static void
+void
cbb_power_disable_socket(device_t brdev, device_t child)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -1747,7 +1241,7 @@ cbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid,
struct resource *res)
{
struct cbb_softc *sc = device_get_softc(brdev);
- return (exca_activate_resource(&sc->exca, child, type, rid, res));
+ return (exca_activate_resource(&sc->exca[0], child, type, rid, res));
}
static int
@@ -1755,7 +1249,7 @@ cbb_pcic_deactivate_resource(device_t brdev, device_t child, int type,
int rid, struct resource *res)
{
struct cbb_softc *sc = device_get_softc(brdev);
- return (exca_deactivate_resource(&sc->exca, child, type, rid, res));
+ return (exca_deactivate_resource(&sc->exca[0], child, type, rid, res));
}
static struct resource *
@@ -1835,7 +1329,7 @@ cbb_pcic_release_resource(device_t brdev, device_t child, int type,
/* PC Card methods */
/************************************************************************/
-static int
+int
cbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid,
uint32_t flags)
{
@@ -1850,10 +1344,10 @@ cbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid,
"set_res_flags: specified rid not found\n");
return (ENOENT);
}
- return (exca_mem_set_flags(&sc->exca, res, flags));
+ return (exca_mem_set_flags(&sc->exca[0], res, flags));
}
-static int
+int
cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
uint32_t cardaddr, uint32_t *deltap)
{
@@ -1866,7 +1360,7 @@ cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
"set_memory_offset: specified rid not found\n");
return (ENOENT);
}
- return (exca_mem_set_offset(&sc->exca, res, cardaddr, deltap));
+ return (exca_mem_set_offset(&sc->exca[0], res, cardaddr, deltap));
}
/************************************************************************/
@@ -1874,7 +1368,7 @@ cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
/************************************************************************/
-static int
+int
cbb_activate_resource(device_t brdev, device_t child, int type, int rid,
struct resource *r)
{
@@ -1887,7 +1381,7 @@ cbb_activate_resource(device_t brdev, device_t child, int type, int rid,
r));
}
-static int
+int
cbb_deactivate_resource(device_t brdev, device_t child, int type,
int rid, struct resource *r)
{
@@ -1901,7 +1395,7 @@ cbb_deactivate_resource(device_t brdev, device_t child, int type,
rid, r));
}
-static struct resource *
+struct resource *
cbb_alloc_resource(device_t brdev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
@@ -1915,7 +1409,7 @@ cbb_alloc_resource(device_t brdev, device_t child, int type, int *rid,
start, end, count, flags));
}
-static int
+int
cbb_release_resource(device_t brdev, device_t child, int type, int rid,
struct resource *r)
{
@@ -1929,7 +1423,7 @@ cbb_release_resource(device_t brdev, device_t child, int type, int rid,
rid, r));
}
-static int
+int
cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -1942,7 +1436,7 @@ cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
return (ENOENT);
}
-static int
+int
cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
{
struct cbb_softc *sc = device_get_softc(brdev);
@@ -1959,23 +1453,26 @@ cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
/* PCI compat methods */
/************************************************************************/
-static int
+int
cbb_maxslots(device_t brdev)
{
return (0);
}
-static uint32_t
+uint32_t
cbb_read_config(device_t brdev, int b, int s, int f, int reg, int width)
{
+ uint32_t rv;
+
/*
* Pass through to the next ppb up the chain (i.e. our grandparent).
*/
- return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)),
- b, s, f, reg, width));
+ rv = PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)),
+ b, s, f, reg, width);
+ return (rv);
}
-static void
+void
cbb_write_config(device_t brdev, int b, int s, int f, int reg, uint32_t val,
int width)
{
@@ -1986,7 +1483,7 @@ cbb_write_config(device_t brdev, int b, int s, int f, int reg, uint32_t val,
b, s, f, reg, val, width);
}
-static int
+int
cbb_suspend(device_t self)
{
int error = 0;
@@ -1999,7 +1496,7 @@ cbb_suspend(device_t self)
return (error);
}
-static int
+int
cbb_resume(device_t self)
{
int error = 0;
@@ -2019,7 +1516,7 @@ cbb_resume(device_t self)
DEVPRINTF((self, "PCI Memory allocated: %08lx\n",
rman_get_start(sc->base_res)));
- cbb_chipinit(sc);
+ sc->chipinit(sc);
/* reset interrupt -- Do we really need to do this? */
tmp = cbb_get(sc, CBB_SOCKET_EVENT);
@@ -2050,7 +1547,7 @@ cbb_resume(device_t self)
return (error);
}
-static int
+int
cbb_child_present(device_t self)
{
struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
@@ -2060,53 +1557,3 @@ cbb_child_present(device_t self)
return (CBB_CARD_PRESENT(sockstate) &&
(sc->flags & CBB_CARD_OK) == CBB_CARD_OK);
}
-
-static device_method_t cbb_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, cbb_probe),
- DEVMETHOD(device_attach, cbb_attach),
- DEVMETHOD(device_detach, cbb_detach),
- DEVMETHOD(device_shutdown, cbb_shutdown),
- DEVMETHOD(device_suspend, cbb_suspend),
- DEVMETHOD(device_resume, cbb_resume),
-
- /* bus methods */
- DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_read_ivar, cbb_read_ivar),
- DEVMETHOD(bus_write_ivar, cbb_write_ivar),
- DEVMETHOD(bus_alloc_resource, cbb_alloc_resource),
- DEVMETHOD(bus_release_resource, cbb_release_resource),
- DEVMETHOD(bus_activate_resource, cbb_activate_resource),
- DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource),
- DEVMETHOD(bus_driver_added, cbb_driver_added),
- DEVMETHOD(bus_child_detached, cbb_child_detached),
- DEVMETHOD(bus_setup_intr, cbb_setup_intr),
- DEVMETHOD(bus_teardown_intr, cbb_teardown_intr),
- DEVMETHOD(bus_child_present, cbb_child_present),
-
- /* 16-bit card interface */
- DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags),
- DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset),
-
- /* power interface */
- DEVMETHOD(power_enable_socket, cbb_power_enable_socket),
- DEVMETHOD(power_disable_socket, cbb_power_disable_socket),
-
- /* pcib compatibility interface */
- DEVMETHOD(pcib_maxslots, cbb_maxslots),
- DEVMETHOD(pcib_read_config, cbb_read_config),
- DEVMETHOD(pcib_write_config, cbb_write_config),
- {0,0}
-};
-
-static driver_t cbb_driver = {
- "cbb",
- cbb_methods,
- sizeof(struct cbb_softc)
-};
-
-static devclass_t cbb_devclass;
-
-DRIVER_MODULE(cbb, pci, cbb_driver, cbb_devclass, 0, 0);
-MODULE_VERSION(cbb, 1);
-MODULE_DEPEND(cbb, exca, 1, 1, 1);
diff --git a/sys/dev/pccbb/pccbb_isa.c b/sys/dev/pccbb/pccbb_isa.c
new file mode 100644
index 0000000..594dc8c
--- /dev/null
+++ b/sys/dev/pccbb/pccbb_isa.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2002-2004 M. Warner Losh.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Driver for ISA to PCMCIA bridges compliant with the Intel ExCA
+ * specification.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/kthread.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <isa/isavar.h>
+
+#include <dev/pccard/pccardreg.h>
+#include <dev/pccard/pccardvar.h>
+
+#include <dev/exca/excareg.h>
+#include <dev/exca/excavar.h>
+
+#include <dev/pccbb/pccbbreg.h>
+#include <dev/pccbb/pccbbvar.h>
+
+#include "power_if.h"
+#include "card_if.h"
+
+/*****************************************************************************
+ * Configurable parameters.
+ *****************************************************************************/
+
+/* sysctl vars */
+SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters");
+
+static int isa_intr_mask = EXCA_INT_MASK_ALLOWED;
+TUNABLE_INT("hw.cbb.intr_mask", &isa_intr_mask);
+SYSCTL_INT(_hw_pcic, OID_AUTO, intr_mask, CTLFLAG_RD, &isa_intr_mask, 0,
+ "Mask of allowable interrupts for this laptop. The default is generally\n\
+correct, but some laptops do not route all the IRQ pins to the bridge to\n\
+save wires. Sometimes you need a more restrictive mask because some of the\n\
+hardware in your laptop may not have a driver so its IRQ might not be\n\
+allocated.");
+
+/*****************************************************************************
+ * End of configurable parameters.
+ *****************************************************************************/
+
+#define DPRINTF(x) do { if (cbb_debug) printf x; } while (0)
+#define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
+
+static struct isa_pnp_id pcic_ids[] = {
+ {EXCA_PNP_ACTIONTEC, NULL}, /* AEI0218 */
+ {EXCA_PNP_IBM3765, NULL}, /* IBM3765 */
+ {EXCA_PNP_82365, NULL}, /* PNP0E00 */
+ {EXCA_PNP_CL_PD6720, NULL}, /* PNP0E01 */
+ {EXCA_PNP_VLSI_82C146, NULL}, /* PNP0E02 */
+ {EXCA_PNP_82365_CARDBUS, NULL}, /* PNP0E03 */
+ {EXCA_PNP_SCM_SWAPBOX, NULL}, /* SCM0469 */
+ {0}
+};
+
+/************************************************************************/
+/* Probe/Attach */
+/************************************************************************/
+
+#if 0
+ struct resource *res;
+ int rid;
+ int i;
+
+ /* A little bogus, but go ahead and get the irq for CSC events */
+ rid = 0;
+ res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+ if (res == NULL) {
+ /*
+ * No IRQ specified, find one. This can be due to the PnP
+ * data not specifying any IRQ, or the default kernel not
+ * assinging an IRQ.
+ */
+ for (i = 0; i < 16; i++) {
+ if (((1 << i) & isa_intr_mask) == 0)
+ continue;
+ res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, i, i,
+ 1, RF_ACTIVE);
+ if (res != NULL)
+ break;
+ }
+ if (res == NULL)
+ return (ENXIO);
+ bus_release_resource(dev, SYS_RES_IRQ, rid, res);
+ bus_set_resource(dev, SYS_RES_IRQ, 0, i, 1);
+ } else {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, res);
+ }
+ if (res == NULL) {
+ device_printf(dev, "Cannot allocate mem\n");
+ return (ENOMEM);
+ }
+#endif
+
+static int
+cbb_isa_activate(device_t dev)
+{
+ return (ENOMEM);
+}
+
+static void
+cbb_isa_deactivate(device_t dev)
+{
+}
+
+static int
+cbb_isa_probe(device_t dev)
+{
+ int error;
+ struct cbb_softc *sc = device_get_softc(dev);
+
+ /* Check isapnp ids */
+ error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids);
+ if (error != 0 && error != ENOENT)
+ return (error);
+
+ error = cbb_isa_activate(dev);
+ if (error != 0)
+ return (error);
+
+ /* Check to make sure that we have actual hardware */
+ error = exca_probe_slots(dev, &sc->exca[0], sc->bst, sc->bsh);
+ cbb_isa_deactivate(dev);
+ return (error);
+}
+
+static int
+cbb_isa_attach(device_t dev)
+{
+ return (ENOMEM);
+}
+
+static device_method_t cbb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cbb_isa_probe),
+ DEVMETHOD(device_attach, cbb_isa_attach),
+ DEVMETHOD(device_detach, cbb_detach),
+ DEVMETHOD(device_shutdown, cbb_shutdown),
+ DEVMETHOD(device_suspend, cbb_suspend),
+ DEVMETHOD(device_resume, cbb_resume),
+
+ /* bus methods */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, cbb_read_ivar),
+ DEVMETHOD(bus_write_ivar, cbb_write_ivar),
+ DEVMETHOD(bus_alloc_resource, cbb_alloc_resource),
+ DEVMETHOD(bus_release_resource, cbb_release_resource),
+ DEVMETHOD(bus_activate_resource, cbb_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource),
+ DEVMETHOD(bus_driver_added, cbb_driver_added),
+ DEVMETHOD(bus_child_detached, cbb_child_detached),
+ DEVMETHOD(bus_setup_intr, cbb_setup_intr),
+ DEVMETHOD(bus_teardown_intr, cbb_teardown_intr),
+ DEVMETHOD(bus_child_present, cbb_child_present),
+
+ /* 16-bit card interface */
+ DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags),
+ DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset),
+
+ /* power interface */
+ DEVMETHOD(power_enable_socket, cbb_power_enable_socket),
+ DEVMETHOD(power_disable_socket, cbb_power_disable_socket),
+
+ {0,0}
+};
+
+static driver_t cbb_isa_driver = {
+ "cbb",
+ cbb_methods,
+ sizeof(struct cbb_softc)
+};
+
+DRIVER_MODULE(cbb, isa, cbb_isa_driver, cbb_devclass, 0, 0);
+MODULE_VERSION(cbb, 1);
+MODULE_DEPEND(cbb, exca, 1, 1, 1);
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
new file mode 100644
index 0000000..4155935
--- /dev/null
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2002-2004 M. Warner Losh.
+ * Copyright (c) 2000-2001 Jonathan Chen.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1998, 1999 and 2000
+ * HAYAKAWA Koichi. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by HAYAKAWA Koichi.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for PCI to CardBus Bridge chips
+ *
+ * References:
+ * TI Datasheets:
+ * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS
+ *
+ * Written by Jonathan Chen <jon@freebsd.org>
+ * The author would like to acknowledge:
+ * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing
+ * * Warner Losh: Newbus/newcard guru and author of the pccard side of things
+ * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver
+ * * David Cross: Author of the initial ugly hack for a specific cardbus card
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/kthread.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <sys/module.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <machine/clock.h>
+
+#include <dev/pccard/pccardreg.h>
+#include <dev/pccard/pccardvar.h>
+
+#include <dev/exca/excareg.h>
+#include <dev/exca/excavar.h>
+
+#include <dev/pccbb/pccbbreg.h>
+#include <dev/pccbb/pccbbvar.h>
+
+#include "power_if.h"
+#include "card_if.h"
+#include "pcib_if.h"
+
+#define DPRINTF(x) do { if (cbb_debug) printf x; } while (0)
+#define DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
+
+#define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \
+ pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE)
+#define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \
+ pci_write_config(DEV, REG, ( \
+ pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE)
+
+static void cbb_chipinit(struct cbb_softc *sc);
+
+static struct yenta_chipinfo {
+ uint32_t yc_id;
+ const char *yc_name;
+ int yc_chiptype;
+} yc_chipsets[] = {
+ /* Texas Instruments chips */
+ {PCIC_ID_TI1031, "TI1031 PCI-PC Card Bridge", CB_TI113X},
+ {PCIC_ID_TI1130, "TI1130 PCI-CardBus Bridge", CB_TI113X},
+ {PCIC_ID_TI1131, "TI1131 PCI-CardBus Bridge", CB_TI113X},
+
+ {PCIC_ID_TI1210, "TI1210 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1211, "TI1211 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1220, "TI1220 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1221, "TI1221 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1225, "TI1225 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1250, "TI1250 PCI-CardBus Bridge", CB_TI125X},
+ {PCIC_ID_TI1251, "TI1251 PCI-CardBus Bridge", CB_TI125X},
+ {PCIC_ID_TI1251B,"TI1251B PCI-CardBus Bridge",CB_TI125X},
+ {PCIC_ID_TI1260, "TI1260 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1260B,"TI1260B PCI-CardBus Bridge",CB_TI12XX},
+ {PCIC_ID_TI1410, "TI1410 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1420, "TI1420 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1421, "TI1421 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1450, "TI1450 PCI-CardBus Bridge", CB_TI125X}, /*SIC!*/
+ {PCIC_ID_TI1451, "TI1451 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1510, "TI1510 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI1520, "TI1520 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI4410, "TI4410 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI4450, "TI4450 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI4451, "TI4451 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_TI4510, "TI4510 PCI-CardBus Bridge", CB_TI12XX},
+
+ /* ENE */
+ {PCIC_ID_ENE_CB710, "ENE CB710 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_ENE_CB720, "ENE CB720 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_ENE_CB1211, "ENE CB1211 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_ENE_CB1225, "ENE CB1225 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_ENE_CB1410, "ENE CB1410 PCI-CardBus Bridge", CB_TI12XX},
+ {PCIC_ID_ENE_CB1420, "ENE CB1420 PCI-CardBus Bridge", CB_TI12XX},
+
+ /* Ricoh chips */
+ {PCIC_ID_RICOH_RL5C465, "RF5C465 PCI-CardBus Bridge", CB_RF5C46X},
+ {PCIC_ID_RICOH_RL5C466, "RF5C466 PCI-CardBus Bridge", CB_RF5C46X},
+ {PCIC_ID_RICOH_RL5C475, "RF5C475 PCI-CardBus Bridge", CB_RF5C47X},
+ {PCIC_ID_RICOH_RL5C476, "RF5C476 PCI-CardBus Bridge", CB_RF5C47X},
+ {PCIC_ID_RICOH_RL5C477, "RF5C477 PCI-CardBus Bridge", CB_RF5C47X},
+ {PCIC_ID_RICOH_RL5C478, "RF5C478 PCI-CardBus Bridge", CB_RF5C47X},
+
+ /* Toshiba products */
+ {PCIC_ID_TOPIC95, "ToPIC95 PCI-CardBus Bridge", CB_TOPIC95},
+ {PCIC_ID_TOPIC95B, "ToPIC95B PCI-CardBus Bridge", CB_TOPIC95},
+ {PCIC_ID_TOPIC97, "ToPIC97 PCI-CardBus Bridge", CB_TOPIC97},
+ {PCIC_ID_TOPIC100, "ToPIC100 PCI-CardBus Bridge", CB_TOPIC97},
+
+ /* Cirrus Logic */
+ {PCIC_ID_CLPD6832, "CLPD6832 PCI-CardBus Bridge", CB_CIRRUS},
+ {PCIC_ID_CLPD6833, "CLPD6833 PCI-CardBus Bridge", CB_CIRRUS},
+ {PCIC_ID_CLPD6834, "CLPD6834 PCI-CardBus Bridge", CB_CIRRUS},
+
+ /* 02Micro */
+ {PCIC_ID_OZ6832, "O2Micro OZ6832/6833 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ6860, "O2Micro OZ6836/6860 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ6872, "O2Micro OZ6812/6872 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ6912, "O2Micro OZ6912/6972 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ6922, "O2Micro OZ6922 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ6933, "O2Micro OZ6933 PCI-CardBus Bridge", CB_O2MICRO},
+ {PCIC_ID_OZ711E1, "O2Micro OZ711E1 PCI-CardBus Bridge", CB_O2MICRO},
+
+ /* sentinel */
+ {0 /* null id */, "unknown", CB_UNKNOWN},
+};
+
+/************************************************************************/
+/* Probe/Attach */
+/************************************************************************/
+
+static int
+cbb_chipset(uint32_t pci_id, const char **namep)
+{
+ struct yenta_chipinfo *ycp;
+
+ for (ycp = yc_chipsets; ycp->yc_id != 0 && pci_id != ycp->yc_id; ++ycp)
+ continue;
+ if (namep != NULL)
+ *namep = ycp->yc_name;
+ return (ycp->yc_chiptype);
+}
+
+static int
+cbb_pci_probe(device_t brdev)
+{
+ const char *name;
+ uint32_t progif;
+ uint32_t subclass;
+
+ /*
+ * Do we know that we support the chipset? If so, then we
+ * accept the device.
+ */
+ if (cbb_chipset(pci_get_devid(brdev), &name) != CB_UNKNOWN) {
+ device_set_desc(brdev, name);
+ return (0);
+ }
+
+ /*
+ * We do support generic CardBus bridges. All that we've seen
+ * to date have progif 0 (the Yenta spec, and successors mandate
+ * this). We do not support PCI PCMCIA bridges (with one exception)
+ * with this driver since they generally are I/O mapped. Those
+ * are supported by the pcic driver. This should help us be more
+ * future proof.
+ */
+ subclass = pci_get_subclass(brdev);
+ progif = pci_get_progif(brdev);
+ if (subclass == PCIS_BRIDGE_CARDBUS && progif == 0) {
+ device_set_desc(brdev, "PCI-CardBus Bridge");
+ return (0);
+ }
+ return (ENXIO);
+}
+
+#ifndef BURN_BRIDGES
+/*
+ * Still need this because the pci code only does power for type 0
+ * header devices.
+ */
+static void
+cbb_powerstate_d0(device_t dev)
+{
+ u_int32_t membase, irq;
+
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ /* Save important PCI config data. */
+ membase = pci_read_config(dev, CBBR_SOCKBASE, 4);
+ irq = pci_read_config(dev, PCIR_INTLINE, 4);
+
+ /* Reset the power state. */
+ device_printf(dev, "chip is in D%d power mode "
+ "-- setting to D0\n", pci_get_powerstate(dev));
+
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, CBBR_SOCKBASE, membase, 4);
+ pci_write_config(dev, PCIR_INTLINE, irq, 4);
+ }
+}
+#endif
+
+/*
+ * Print out the config space
+ */
+static void
+cbb_print_config(device_t dev)
+{
+ int i;
+
+ device_printf(dev, "PCI Configuration space:");
+ for (i = 0; i < 256; i += 4) {
+ if (i % 16 == 0)
+ printf("\n 0x%02x: ", i);
+ printf("0x%08x ", pci_read_config(dev, i, 4));
+ }
+ printf("\n");
+}
+
+static int
+cbb_pci_attach(device_t brdev)
+{
+ static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
+ struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
+ int rid, bus, pribus;
+ device_t parent;
+
+ parent = device_get_parent(brdev);
+ mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
+ cv_init(&sc->cv, "cbb cv");
+ sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL);
+ sc->dev = brdev;
+ sc->cbdev = NULL;
+ sc->exca[0].pccarddev = NULL;
+ sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
+ sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
+ SLIST_INIT(&sc->rl);
+ STAILQ_INIT(&sc->intr_handlers);
+#ifndef BURN_BRIDGES
+ cbb_powerstate_d0(brdev);
+#endif
+
+ rid = CBBR_SOCKBASE;
+ sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->base_res) {
+ device_printf(brdev, "Could not map register memory\n");
+ mtx_destroy(&sc->mtx);
+ cv_destroy(&sc->cv);
+ return (ENOMEM);
+ } else {
+ DEVPRINTF((brdev, "Found memory at %08lx\n",
+ rman_get_start(sc->base_res)));
+ }
+
+ sc->bst = rman_get_bustag(sc->base_res);
+ sc->bsh = rman_get_bushandle(sc->base_res);
+ exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
+ sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN;
+ sc->exca[0].chipset = EXCA_CARDBUS;
+ sc->chipinit = cbb_chipinit;
+ sc->chipinit(sc);
+
+ /*
+ * This is a gross hack. We should be scanning the entire pci
+ * tree, assigning bus numbers in a way such that we (1) can
+ * reserve 1 extra bus just in case and (2) all sub busses
+ * are in an appropriate range.
+ */
+ bus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
+ pribus = pcib_get_bus(parent);
+ DEVPRINTF((brdev, "Secondary bus is %d\n", bus));
+ if (bus == 0) {
+ if (curr_bus_number <= pribus)
+ curr_bus_number = pribus + 1;
+ if (pci_read_config(brdev, PCIR_PRIBUS_2, 1) != pribus) {
+ DEVPRINTF((brdev, "Setting primary bus to %d\n", pribus));
+ pci_write_config(brdev, PCIR_PRIBUS_2, pribus, 1);
+ }
+ bus = curr_bus_number;
+ DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", bus,
+ bus + 1));
+ sc->secbus = bus;
+ sc->subbus = bus + 1;
+ pci_write_config(brdev, PCIR_SECBUS_2, bus, 1);
+ pci_write_config(brdev, PCIR_SUBBUS_2, bus + 1, 1);
+ curr_bus_number += 2;
+ }
+
+ /* attach children */
+ sc->cbdev = device_add_child(brdev, "cardbus", -1);
+ if (sc->cbdev == NULL)
+ DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n"));
+ else if (device_probe_and_attach(sc->cbdev) != 0)
+ DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n"));
+
+ sc->exca[0].pccarddev = device_add_child(brdev, "pccard", -1);
+ if (sc->exca[0].pccarddev == NULL)
+ DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n"));
+ else if (device_probe_and_attach(sc->exca[0].pccarddev) != 0)
+ DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n"));
+
+ /* Map and establish the interrupt. */
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ printf("cbb: Unable to map IRQ...\n");
+ goto err;
+ }
+
+ if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE,
+ cbb_intr, sc, &sc->intrhand)) {
+ device_printf(brdev, "couldn't establish interrupt");
+ goto err;
+ }
+
+ /* reset 16-bit pcmcia bus */
+ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
+
+ /* turn off power */
+ cbb_power(brdev, CARD_OFF);
+
+ /* CSC Interrupt: Card detect interrupt on */
+ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
+
+ /* reset interrupt */
+ cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));
+
+ if (bootverbose)
+ cbb_print_config(brdev);
+
+ /* Start the thread */
+ if (kthread_create(cbb_event_thread, sc, &sc->event_thread, 0, 0,
+ "%s", device_get_nameunit(brdev))) {
+ device_printf(brdev, "unable to create event thread.\n");
+ panic("cbb_create_event_thread");
+ }
+ return (0);
+err:
+ if (sc->irq_res)
+ bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->base_res) {
+ bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
+ sc->base_res);
+ }
+ mtx_destroy(&sc->mtx);
+ cv_destroy(&sc->cv);
+ return (ENOMEM);
+}
+
+static void
+cbb_chipinit(struct cbb_softc *sc)
+{
+ uint32_t mux, sysctrl, reg;
+
+ /* Set CardBus latency timer */
+ if (pci_read_config(sc->dev, PCIR_SECLAT_1, 1) < 0x20)
+ pci_write_config(sc->dev, PCIR_SECLAT_1, 0x20, 1);
+
+ /* Set PCI latency timer */
+ if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20)
+ pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1);
+
+ /* Enable memory access */
+ PCI_MASK_CONFIG(sc->dev, PCIR_COMMAND,
+ | PCIM_CMD_MEMEN
+ | PCIM_CMD_PORTEN
+ | PCIM_CMD_BUSMASTEREN, 2);
+
+ /* disable Legacy IO */
+ switch (sc->chipset) {
+ case CB_RF5C46X:
+ PCI_MASK_CONFIG(sc->dev, CBBR_BRIDGECTRL,
+ & ~(CBBM_BRIDGECTRL_RL_3E0_EN |
+ CBBM_BRIDGECTRL_RL_3E2_EN), 2);
+ break;
+ default:
+ pci_write_config(sc->dev, CBBR_LEGACY, 0x0, 4);
+ break;
+ }
+
+ /* Use PCI interrupt for interrupt routing */
+ PCI_MASK2_CONFIG(sc->dev, CBBR_BRIDGECTRL,
+ & ~(CBBM_BRIDGECTRL_MASTER_ABORT |
+ CBBM_BRIDGECTRL_INTR_IREQ_EN),
+ | CBBM_BRIDGECTRL_WRITE_POST_EN,
+ 2);
+
+ /*
+ * XXX this should be a function table, ala OLDCARD. This means
+ * that we could more easily support ISA interrupts for pccard
+ * cards if we had to.
+ */
+ switch (sc->chipset) {
+ case CB_TI113X:
+ /*
+ * The TI 1031, TI 1130 and TI 1131 all require another bit
+ * be set to enable PCI routing of interrupts, and then
+ * a bit for each of the CSC and Function interrupts we
+ * want routed.
+ */
+ PCI_MASK_CONFIG(sc->dev, CBBR_CBCTRL,
+ | CBBM_CBCTRL_113X_PCI_INTR |
+ CBBM_CBCTRL_113X_PCI_CSC | CBBM_CBCTRL_113X_PCI_IRQ_EN,
+ 1);
+ PCI_MASK_CONFIG(sc->dev, CBBR_DEVCTRL,
+ & ~(CBBM_DEVCTRL_INT_SERIAL |
+ CBBM_DEVCTRL_INT_PCI), 1);
+ break;
+ case CB_TI12XX:
+ /*
+ * Some TI 12xx (and [14][45]xx) based pci cards
+ * sometimes have issues with the MFUNC register not
+ * being initialized due to a bad EEPROM on board.
+ * Laptops that this matters on have this register
+ * properly initialized.
+ *
+ * The TI125X parts have a different register.
+ */
+ mux = pci_read_config(sc->dev, CBBR_MFUNC, 4);
+ sysctrl = pci_read_config(sc->dev, CBBR_SYSCTRL, 4);
+ if (mux == 0) {
+ mux = (mux & ~CBBM_MFUNC_PIN0) |
+ CBBM_MFUNC_PIN0_INTA;
+ if ((sysctrl & CBBM_SYSCTRL_INTRTIE) == 0)
+ mux = (mux & ~CBBM_MFUNC_PIN1) |
+ CBBM_MFUNC_PIN1_INTB;
+ pci_write_config(sc->dev, CBBR_MFUNC, mux, 4);
+ }
+ /*FALLTHROUGH*/
+ case CB_TI125X:
+ /*
+ * Disable zoom video. Some machines initialize this
+ * improperly and exerpience has shown that this helps
+ * prevent strange behavior.
+ */
+ pci_write_config(sc->dev, CBBR_MMCTRL, 0, 4);
+ break;
+ case CB_O2MICRO:
+ /*
+ * Issue #1: INT# generated at the same time as
+ * selected ISA IRQ. When IREQ# or STSCHG# is active,
+ * in addition to the ISA IRQ being generated, INT#
+ * will also be generated at the same time.
+ *
+ * Some of the older controllers have an issue in
+ * which the slot's PCI INT# will be asserted whenever
+ * IREQ# or STSCGH# is asserted even if ExCA registers
+ * 03h or 05h have an ISA IRQ selected.
+ *
+ * The fix for this issue, which will work for any
+ * controller (old or new), is to set ExCA registers
+ * 3Ah (slot 0) & 7Ah (slot 1) bits 7:4 = 1010b.
+ * These bits are undocumented. By setting this
+ * register (of each slot) to '1010xxxxb' a routing of
+ * IREQ# to INTC# and STSCHG# to INTC# is selected.
+ * Since INTC# isn't connected there will be no
+ * unexpected PCI INT when IREQ# or STSCHG# is active.
+ * However, INTA# (slot 0) or INTB# (slot 1) will
+ * still be correctly generated if NO ISA IRQ is
+ * selected (ExCA regs 03h or 05h are cleared).
+ */
+ reg = exca_getb(&sc->exca[0], EXCA_O2MICRO_CTRL_C);
+ reg = (reg & 0x0f) |
+ EXCA_O2CC_IREQ_INTC | EXCA_O2CC_STSCHG_INTC;
+ exca_putb(&sc->exca[0], EXCA_O2MICRO_CTRL_C, reg);
+
+ break;
+ case CB_TOPIC97:
+ /*
+ * Disable Zoom Video, ToPIC 97, 100.
+ */
+ pci_write_config(sc->dev, CBBR_TOPIC_ZV_CONTROL, 0, 1);
+ /*
+ * ToPIC 97, 100
+ * At offset 0xa1: INTERRUPT CONTROL register
+ * 0x1: Turn on INT interrupts.
+ */
+ PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_INTCTRL,
+ | CBBM_TOPIC_INTCTRL_INTIRQSEL, 1);
+ goto topic_common;
+ case CB_TOPIC95:
+ /*
+ * SOCKETCTRL appears to be TOPIC 95/B specific
+ */
+ PCI_MASK_CONFIG(sc->dev, CBBR_TOPIC_SOCKETCTRL,
+ | CBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL, 4);
+
+ topic_common:;
+ /*
+ * At offset 0xa0: SLOT CONTROL
+ * 0x80 Enable CardBus Functionality
+ * 0x40 Enable CardBus and PC Card registers
+ * 0x20 Lock ID in exca regs
+ * 0x10 Write protect ID in config regs
+ * Clear the rest of the bits, which defaults the slot
+ * in legacy mode to 0x3e0 and offset 0. (legacy
+ * mode is determined elsewhere)
+ */
+ pci_write_config(sc->dev, CBBR_TOPIC_SLOTCTRL,
+ CBBM_TOPIC_SLOTCTRL_SLOTON |
+ CBBM_TOPIC_SLOTCTRL_SLOTEN |
+ CBBM_TOPIC_SLOTCTRL_ID_LOCK |
+ CBBM_TOPIC_SLOTCTRL_ID_WP, 1);
+
+ /*
+ * At offset 0xa3 Card Detect Control Register
+ * 0x80 CARDBUS enbale
+ * 0x01 Cleared for hardware change detect
+ */
+ PCI_MASK2_CONFIG(sc->dev, CBBR_TOPIC_CDC,
+ | CBBM_TOPIC_CDC_CARDBUS,
+ & ~CBBM_TOPIC_CDC_SWDETECT, 4);
+ break;
+ }
+
+ /*
+ * 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[0], EXCA_INTR, EXCA_INTR_ENABLE);
+ exca_putb(&sc->exca[0], 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);
+ pci_write_config(sc->dev, CBBR_MEMBASE1, 0xffffffff, 4);
+ pci_write_config(sc->dev, CBBR_MEMLIMIT1, 0, 4);
+ pci_write_config(sc->dev, CBBR_IOBASE0, 0xffffffff, 4);
+ pci_write_config(sc->dev, CBBR_IOLIMIT0, 0, 4);
+ pci_write_config(sc->dev, CBBR_IOBASE1, 0xffffffff, 4);
+ pci_write_config(sc->dev, CBBR_IOLIMIT1, 0, 4);
+}
+
+static device_method_t cbb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cbb_pci_probe),
+ DEVMETHOD(device_attach, cbb_pci_attach),
+ DEVMETHOD(device_detach, cbb_detach),
+ DEVMETHOD(device_shutdown, cbb_shutdown),
+ DEVMETHOD(device_suspend, cbb_suspend),
+ DEVMETHOD(device_resume, cbb_resume),
+
+ /* bus methods */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, cbb_read_ivar),
+ DEVMETHOD(bus_write_ivar, cbb_write_ivar),
+ DEVMETHOD(bus_alloc_resource, cbb_alloc_resource),
+ DEVMETHOD(bus_release_resource, cbb_release_resource),
+ DEVMETHOD(bus_activate_resource, cbb_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource),
+ DEVMETHOD(bus_driver_added, cbb_driver_added),
+ DEVMETHOD(bus_child_detached, cbb_child_detached),
+ DEVMETHOD(bus_setup_intr, cbb_setup_intr),
+ DEVMETHOD(bus_teardown_intr, cbb_teardown_intr),
+ DEVMETHOD(bus_child_present, cbb_child_present),
+
+ /* 16-bit card interface */
+ DEVMETHOD(card_set_res_flags, cbb_pcic_set_res_flags),
+ DEVMETHOD(card_set_memory_offset, cbb_pcic_set_memory_offset),
+
+ /* power interface */
+ DEVMETHOD(power_enable_socket, cbb_power_enable_socket),
+ DEVMETHOD(power_disable_socket, cbb_power_disable_socket),
+
+ /* pcib compatibility interface */
+ DEVMETHOD(pcib_maxslots, cbb_maxslots),
+ DEVMETHOD(pcib_read_config, cbb_read_config),
+ DEVMETHOD(pcib_write_config, cbb_write_config),
+ {0,0}
+};
+
+static driver_t cbb_driver = {
+ "cbb",
+ cbb_methods,
+ sizeof(struct cbb_softc)
+};
+
+DRIVER_MODULE(cbb, pci, cbb_driver, cbb_devclass, 0, 0);
+MODULE_VERSION(cbb, 1);
+MODULE_DEPEND(cbb, exca, 1, 1, 1);
diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h
index 85baddb..75458af 100644
--- a/sys/dev/pccbb/pccbbvar.h
+++ b/sys/dev/pccbb/pccbbvar.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003-2004 Warner Losh.
* Copyright (c) 2000,2001 Jonathan Chen.
* All rights reserved.
*
@@ -35,7 +36,8 @@
struct cbb_intrhand {
driver_intr_t *intr;
void *arg;
- uint32_t flags;
+ struct cbb_softc *sc;
+ void *cookie;
STAILQ_ENTRY(cbb_intrhand) entries;
};
@@ -52,10 +54,11 @@ struct cbb_reslist {
};
#define CBB_AUTO_OPEN_SMALLHOLE 0x100
+#define CBB_NSLOTS 4
struct cbb_softc {
device_t dev;
- struct exca_softc exca;
+ struct exca_softc exca[CBB_NSLOTS];
struct resource *base_res;
struct resource *irq_res;
void *intrhand;
@@ -86,6 +89,7 @@ struct cbb_softc {
device_t cbdev;
struct proc *event_thread;
+ void (*chipinit)(struct cbb_softc *);
};
/* result of detect_card */
@@ -104,3 +108,72 @@ struct cbb_softc {
#define YV 1
#define CARD_OFF (CARD_VCC(0))
+
+extern int cbb_debug;
+extern devclass_t cbb_devclass;
+
+int cbb_activate_resource(device_t brdev, device_t child,
+ int type, int rid, struct resource *r);
+struct resource *cbb_alloc_resource(device_t brdev, device_t child,
+ int type, int *rid, u_long start, u_long end, u_long count,
+ u_int flags);
+void cbb_child_detached(device_t brdev, device_t child);
+int cbb_child_present(device_t self);
+int cbb_deactivate_resource(device_t brdev, device_t child,
+ int type, int rid, struct resource *r);
+int cbb_detach(device_t brdev);
+void cbb_disable_func_intr(struct cbb_softc *sc);
+void cbb_driver_added(device_t brdev, driver_t *driver);
+void cbb_event_thread(void *arg);
+void cbb_intr(void *arg);
+int cbb_maxslots(device_t brdev);
+int cbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
+ uint32_t cardaddr, uint32_t *deltap);
+int cbb_pcic_set_res_flags(device_t brdev, device_t child, int type,
+ int rid, uint32_t flags);
+int cbb_power(device_t brdev, int volts);
+int cbb_power_enable_socket(device_t brdev, device_t child);
+void cbb_power_disable_socket(device_t brdev, device_t child);
+uint32_t cbb_read_config(device_t brdev, int b, int s, int f,
+ int reg, int width);
+int cbb_read_ivar(device_t brdev, device_t child, int which,
+ uintptr_t *result);
+int cbb_release_resource(device_t brdev, device_t child,
+ int type, int rid, struct resource *r);
+int cbb_resume(device_t self);
+int cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
+ int flags, driver_intr_t *intr, void *arg, void **cookiep);
+int cbb_shutdown(device_t brdev);
+int cbb_suspend(device_t self);
+int cbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
+ void *cookie);
+void cbb_write_config(device_t brdev, int b, int s, int f,
+ int reg, uint32_t val, int width);
+int cbb_write_ivar(device_t brdev, device_t child, int which,
+ uintptr_t value);
+
+/*
+ */
+static __inline void
+cbb_set(struct cbb_softc *sc, uint32_t reg, uint32_t val)
+{
+ bus_space_write_4(sc->bst, sc->bsh, reg, val);
+}
+
+static __inline uint32_t
+cbb_get(struct cbb_softc *sc, uint32_t reg)
+{
+ return (bus_space_read_4(sc->bst, sc->bsh, reg));
+}
+
+static __inline void
+cbb_setb(struct cbb_softc *sc, uint32_t reg, uint32_t bits)
+{
+ cbb_set(sc, reg, cbb_get(sc, reg) | bits);
+}
+
+static __inline void
+cbb_clrb(struct cbb_softc *sc, uint32_t reg, uint32_t bits)
+{
+ cbb_set(sc, reg, cbb_get(sc, reg) & ~bits);
+}
OpenPOWER on IntegriCloud