aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>1999-11-18 07:14:54 +0000
committerWarner Losh <imp@FreeBSD.org>1999-11-18 07:14:54 +0000
commit64369dfb59039150ace5ba8fb67ae1cfcde07550 (patch)
tree2b5eb53a878d577543d2d55a1fce0915dd3a7a89 /sys
parent10534a60e8a62e6e70320bfa2e7fbe5ffe5ee4ba (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/pci/pccbb.c2374
-rw-r--r--sys/pci/pccbbreg.h228
-rw-r--r--sys/pci/pccbbvar.h99
3 files changed, 2701 insertions, 0 deletions
diff --git a/sys/pci/pccbb.c b/sys/pci/pccbb.c
new file mode 100644
index 000000000000..ac51e7058c7b
--- /dev/null
+++ b/sys/pci/pccbb.c
@@ -0,0 +1,2374 @@
+/*
+ * Copyright (c) 1998 and 1999 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.
+ */
+/* $Id: pccbb.c,v 1.12 1999/09/07 17:38:17 gehenna Exp $ */
+/* FreeBSD/newconfig version UCHIYAMA Yasushi 1999 */
+/* $FreeBSD$ */
+
+#define CBB_DEBUG
+#undef SHOW_REGS
+#undef PCCBB_PCMCIA_POLL
+
+#define CB_PCMCIA_POLL
+#define CB_PCMCIA_POLL_ONLY
+#define LEVEL2
+#undef CB_PCMCIA_POLL
+#undef CB_PCMCIA_POLL_ONLY
+#undef LEVEL2
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <vm/vm.h>
+
+#include <machine/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#define delay(arg) DELAY(arg)
+#include <machine/clock.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/cardbus/cardbusreg.h>
+#include <dev/cardbus/cardbusvar.h>
+
+#include <dev/pcmcia/pcmciareg.h>
+#include <dev/pcmcia/pcmciavar.h>
+
+#include <dev/ic/i82365reg.h>
+#include <dev/ic/i82365reg.h>
+
+#include <dev/pci/pccbbreg.h>
+#include <dev/pci/pccbbvar.h>
+
+#define PCIC_FLAG_SOCKETP 0x0001
+#define PCIC_FLAG_CARDP 0x0002
+
+/* Chipset ID */
+#define CB_UNKNOWN 0 /* NOT Cardbus-PCI bridge */
+#define CB_TI113X 1 /* TI PCI1130/1131 */
+#define CB_TI12XX 2 /* TI PCI1250/1220 */
+#define CB_RF5C47X 3 /* RICOH RF5C475/476/477 */
+#define CB_RF5C46X 4 /* RICOH RF5C465/466/467 */
+#define CB_TOPIC95 5 /* Toshiba ToPIC95 */
+#define CB_TOPIC95B 6 /* Toshiba ToPIC95B */
+#define CB_TOPIC97 7 /* Toshiba ToPIC97 */
+#define CB_CHIPS_LAST 8 /* Sentinel */
+
+#if defined CBB_DEBUG
+#define DPRINTF(x) printf x
+#define STATIC
+#else
+#define DPRINTF(x)
+#define STATIC static
+#endif
+
+void
+pccbb_event_thread (void *arg)
+{
+ struct pccbb_softc *sc = arg;
+ bus_space_tag_t memt = sc->sc_base_memt;
+ bus_space_handle_t memh = sc->sc_base_memh;
+ u_int32_t sockstate;
+
+ int s;
+
+ while (1) {
+ s = splhigh();
+ if (!sc->sc_queued) {
+ splx (s);
+ tsleep (&sc->events, PWAIT, "pccbbev", 0);
+ } else {
+ sockstate = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
+ if (sc->sc_flags & CBB_CARDEXIST) {
+ DPRINTF(("%s: card removed\n", sc->sc_dev.dv_xname));
+ sc->sc_flags &= ~CBB_CARDEXIST;
+ if (sockstate & CB_SOCKET_STAT_16BIT) {
+ struct cbb_pcic_handle *ph = &sc->sc_pcmcia_h;
+ struct pcmcia_softc *psc = (void*)ph->pcmcia;
+ if (!(ph->flags & PCIC_FLAG_CARDP)) {
+ panic("pccbbintr: already detached");
+ }
+ psc->sc_if.if_card_deactivate(ph->pcmcia);
+ pccbb_pcmcia_socket_disable(ph);
+ pccbb_pcmcia_detach_card(ph, DETACH_FORCE);
+ } else {
+ if (sc->sc_cbdev)
+ config_detach (sc->sc_cbdev, DETACH_FORCE);
+ else
+ printf ("no corresponding device instance.\n"); /* XXX should panic */
+ }
+ } else {
+ DPRINTF(("%s: card inserted\n", sc->sc_dev.dv_xname));
+ pccbb_insert (sc);
+ }
+ sc->sc_queued = 0;
+ sc->sc_flags &= ~CBB_CARDSTATUS_BUSY;
+ splx (s);
+ }
+ }
+ kthread_exit(0);
+
+}
+void
+pccbb_create_event_thread (void *arg)
+{
+ struct pccbb_softc *sc = arg;
+ if (kthread_create1(pccbb_event_thread, sc, &sc->event_thread,
+ "%s,%s", sc->sc_dev.dv_xname, "cardbus")) {
+ printf ("%s: unable to create event thread.\n",
+ sc->sc_dev.dv_xname);
+ panic ("pccbb_create_event_thread");
+ } else
+ printf("%s: create event thread\n", sc->sc_dev.dv_xname);
+}
+
+void
+pccbb_kthread_init (struct pccbb_softc *sc)
+{
+ kthread_create(pccbb_create_event_thread, sc);
+}
+
+
+int pccbbmatch __P((struct device *, struct cfdata *, void *));
+void pccbbattach __P((struct device *, struct device *, void *));
+int pccbbintr __P((void *));
+
+static void pccbb_insert __P((void *));
+static int pccbb_detect_card __P((struct pccbb_softc *));
+static void pccbb_pcmcia_write __P((struct cbb_pcic_handle *, int, u_int8_t));
+static u_int8_t pccbb_pcmcia_read __P((struct cbb_pcic_handle *, int));
+#define Pcic_read(ph, reg) ((ph)->ph_read((ph), (reg)))
+#define Pcic_write(ph, reg, val) ((ph)->ph_write((ph), (reg), (val)))
+
+STATIC int cb_reset __P((struct pccbb_softc *));
+STATIC int cb_detect_voltage __P((struct pccbb_softc *));
+STATIC int cbbprint __P((void *, const char *));
+
+static int cb_chipset __P((u_int32_t, char const **, int *));
+static void pccbb_chipinit __P((struct pci_attach_args *, struct pccbb_softc *));
+STATIC void pccbb_pcmcia_attach __P((struct pccbb_softc *));
+STATIC void pccbb_pcmcia_attach_card __P((struct cbb_pcic_handle *));
+STATIC void pccbb_pcmcia_detach_card __P((struct cbb_pcic_handle *, int));
+STATIC void pccbb_pcmcia_deactivate_card __P((struct cbb_pcic_handle *));
+
+STATIC int pccbb_ctrl __P((cardbus_chipset_tag_t, int));
+STATIC int pccbb_power __P((cardbus_chipset_tag_t, int));
+STATIC int pccbb_cardenable __P((struct pccbb_softc *sc, int function));
+static int pccbb_io_open __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t));
+static int pccbb_io_close __P((cardbus_chipset_tag_t, int));
+static int pccbb_mem_open __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t));
+static int pccbb_mem_close __P((cardbus_chipset_tag_t, int));
+static void *pccbb_intr_establish __P((cardbus_chipset_tag_t, int irq, int level, int (* ih)(void *), void *sc));
+static void pccbb_intr_disestablish __P((cardbus_chipset_tag_t ct, void *ih));
+static cardbustag_t pccbb_make_tag __P((cardbus_chipset_tag_t, int, int, int));
+static void pccbb_free_tag __P((cardbus_chipset_tag_t, cardbustag_t));
+static cardbusreg_t pccbb_conf_read __P((cardbus_chipset_tag_t, cardbustag_t, int));
+static void pccbb_conf_write __P((cardbus_chipset_tag_t, cardbustag_t, int, cardbusreg_t));
+
+STATIC int pccbb_pcmcia_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
+ struct pcmcia_mem_handle *));
+STATIC void pccbb_pcmcia_mem_free __P((pcmcia_chipset_handle_t,
+ struct pcmcia_mem_handle *));
+STATIC int pccbb_pcmcia_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
+ bus_size_t, struct pcmcia_mem_handle *, bus_addr_t *, int *));
+STATIC void pccbb_pcmcia_mem_unmap __P((pcmcia_chipset_handle_t, int));
+STATIC int pccbb_pcmcia_io_alloc __P((pcmcia_chipset_handle_t, bus_addr_t,
+ bus_size_t, bus_size_t, struct pcmcia_io_handle *));
+STATIC void pccbb_pcmcia_io_free __P((pcmcia_chipset_handle_t,
+ struct pcmcia_io_handle *));
+STATIC int pccbb_pcmcia_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
+ bus_size_t, struct pcmcia_io_handle *, int *));
+STATIC void pccbb_pcmcia_io_unmap __P((pcmcia_chipset_handle_t, int));
+STATIC void *pccbb_pcmcia_intr_establish __P((pcmcia_chipset_handle_t,
+ struct pcmcia_function *, int, int (*) (void *), void *));
+STATIC void pccbb_pcmcia_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
+STATIC void pccbb_pcmcia_socket_enable __P((pcmcia_chipset_handle_t));
+STATIC void pccbb_pcmcia_socket_disable __P((pcmcia_chipset_handle_t));
+
+static void pccbb_pcmcia_do_io_map __P((struct cbb_pcic_handle *, int));
+static void pccbb_pcmcia_wait_ready __P((struct cbb_pcic_handle *));
+static void pccbb_pcmcia_do_mem_map __P((struct cbb_pcic_handle *, int));
+static int pccbb_pcmcia_print __P((void *, const char *));
+static int pccbb_pcmcia_submatch __P((struct device *, struct cfdata *, void *));
+
+static int pccbb_cardbus_submatch __P((struct device *, struct cfdata *, void *));
+
+#if defined SHOW_REGS
+static void cb_show_regs __P((pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt, bus_space_handle_t memh));
+#endif
+
+struct cfattach cbb_pci_ca = {
+ sizeof(struct pccbb_softc), pccbbmatch, pccbbattach
+};
+
+static struct pcmcia_chip_functions pccbb_pcmcia_funcs = {
+ pccbb_pcmcia_mem_alloc,
+ pccbb_pcmcia_mem_free,
+ pccbb_pcmcia_mem_map,
+ pccbb_pcmcia_mem_unmap,
+ pccbb_pcmcia_io_alloc,
+ pccbb_pcmcia_io_free,
+ pccbb_pcmcia_io_map,
+ pccbb_pcmcia_io_unmap,
+ pccbb_pcmcia_intr_establish,
+ pccbb_pcmcia_intr_disestablish,
+ pccbb_pcmcia_socket_enable,
+ pccbb_pcmcia_socket_disable,
+};
+
+static struct cardbus_functions pccbb_funcs = {
+ pccbb_ctrl,
+ pccbb_power,
+ pccbb_mem_open,
+ pccbb_mem_close,
+ pccbb_io_open,
+ pccbb_io_close,
+ pccbb_intr_establish,
+ pccbb_intr_disestablish,
+ pccbb_make_tag,
+ pccbb_free_tag,
+ pccbb_conf_read,
+ pccbb_conf_write,
+};
+
+
+int
+pccbbmatch(parent, match, aux)
+ struct device *parent;
+ struct cfdata *match;
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if ((pa->pa_class & PCI_CLASS_INTERFACE_MASK) == PCI_CLASS_INTERFACE_YENTA) {
+ /* OK, It must be YENTA PCI-CardBus bridge */
+ return 2; /* beat chipset_match */
+ }
+
+ return 0;
+}
+
+
+#define MAKEID(vendor, prod) (((vendor) << PCI_VENDOR_SHIFT) \
+ | ((prod) << PCI_PRODUCT_SHIFT))
+
+struct yenta_chipinfo {
+ pcireg_t yc_id; /* vendor tag | product tag */
+ const char *yc_name;
+ int yc_chiptype;
+ int yc_flags;
+} yc_chipsets[] = {
+ /* Texas Instruments chips */
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1130), "TI1130", CB_TI113X,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1131), "TI1131", CB_TI113X,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1250), "TI1250", CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1220), "TI1220", CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1221), "TI1221", CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1225), "TI1225", CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI2030), "TI2030", CB_UNKNOWN,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+
+ /* Ricoh chips */
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C475), "RF5C475",
+ CB_RF5C47X, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C476), "RF5C476",
+ CB_RF5C47X, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C477), "RF5C477",
+ CB_RF5C47X, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C477), "RF5C478",
+ CB_RF5C47X, PCCBB_PCMCIA_MEM_32},
+
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C465), "RF5C465",
+ CB_RF5C46X, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C466), "RF5C466",
+ CB_RF5C46X, PCCBB_PCMCIA_MEM_32},
+
+ /* Toshiba products */
+ {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95), "ToPIC95",
+ CB_TOPIC95, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B), "ToPIC95B",
+ CB_TOPIC95B, PCCBB_PCMCIA_MEM_32},
+ {MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B), "ToPIC97",
+ CB_TOPIC97, PCCBB_PCMCIA_MEM_32},
+
+ /* sentinel */
+ {0 /* null id */, "unknown",
+ CB_UNKNOWN, 0},
+};
+
+
+static int
+cb_chipset(pci_id, namep, flagp)
+ u_int32_t pci_id;
+ char const **namep;
+ int *flagp;
+{
+ int loopend = sizeof(yc_chipsets)/sizeof(yc_chipsets[0]);
+ struct yenta_chipinfo *ycp, *ycend;
+
+ ycend = yc_chipsets + loopend;
+
+ for (ycp =yc_chipsets; ycp < ycend && pci_id != ycp->yc_id; ++ycp);
+
+ if (ycp == ycend) {
+ /* not found */
+ ycp = yc_chipsets + loopend - 1; /* to point the sentinel */
+ }
+
+ if (namep != NULL) {
+ *namep = ycp->yc_name;
+ }
+
+ if (flagp != NULL) {
+ *flagp = ycp->yc_flags;
+ }
+
+ return ycp->yc_chiptype;
+}
+
+void
+pccbbattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct pccbb_softc *sc = (void *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcireg_t sock_base, cbctrl;
+ bus_addr_t sockbase;
+ bus_space_tag_t base_memt;
+ bus_space_handle_t base_memh;
+ u_int32_t maskreg;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ char const *name;
+ int flags;
+
+ sc->sc_chipset = cb_chipset(pa->pa_id, &name, &flags);
+ printf(" (%s), flags %d\n", name, flags);
+
+ /* pccbb_machdep.c start */
+#if 0
+ pcbb_attach_machdef(pa, sc);
+#endif
+
+ /* MAP socket registers and ExCA registers on memory-space
+ When no valid address is set on socket base registers (on pci
+ config space), get it not polite way */
+ sock_base = pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE);
+
+ if (PCI_MAPREG_MEM_ADDR(sock_base) <= 0x100000 ||
+ PCI_MAPREG_MEM_ADDR(sock_base) == 0xfffffff0) {
+ /* The address may be invalid. */
+ sc->sc_base_memt = pa->pa_memt;
+#if !defined CBB_PCI_BASE
+#define CBB_PCI_BASE 0x20000000
+#endif
+ if (bus_space_alloc(sc->sc_base_memt, CBB_PCI_BASE, 0xffffffff,
+ 0x1000, /* size */
+ (sc->sc_chipset == CB_RF5C47X || sc->sc_chipset == CB_TI113X) ? 0x10000 : 0x1000, /* alignment */
+ 0, /* boundary */
+ 0, /* flags */
+ &sockbase, &sc->sc_base_memh)) {
+ /* cannot allocate memory space */
+ return;
+ }
+ pci_conf_write(pc, pa->pa_tag, PCI_SOCKBASE, sockbase);
+ DPRINTF(("%s: CardBus resister address 0x%x -> 0x%lx\n",sc->sc_dev.dv_xname,
+ sock_base, pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE)));
+ } else {
+ /* The address must be valid. */
+ if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_base_memt, &sc->sc_base_memh, &sockbase,
+ NULL)) {
+ printf("%s: can't map socket base address 0x%x\n", sc->sc_dev.dv_xname,
+ sock_base);
+ /* I think it's funny: socket base registers must be mapped on
+ memory space, but ... */
+ if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_IO, 0,
+ &sc->sc_base_memt, &sc->sc_base_memh,
+ &sockbase, NULL)) {
+ printf("%s: can't map socket base address 0x%lx: io mode\n",
+ sc->sc_dev.dv_xname, (u_long)sockbase);
+ return;
+ }
+ } else {
+ DPRINTF(("%s: socket base address 0x%lx",sc->sc_dev.dv_xname, (u_long)sockbase));
+ }
+ }
+
+ sc->sc_mem_start = CBB_PCI_BASE; /* XXX */
+ sc->sc_mem_end = 0xffffffff; /* XXX */
+
+ /* pccbb_machdep.c end */
+
+#if defined CBB_DEBUG
+ {
+ static char *intrname[5] = {"NON", "A", "B", "C", "D"};
+ printf(" intrpin %s, intrtag %d\n", intrname[pa->pa_intrpin],
+ pa->pa_intrline);
+ }
+#endif
+
+ /****** setup softc ******/
+ sc->sc_pc = pc;
+ sc->sc_iot = pa->pa_iot;
+ sc->sc_memt = pa->pa_memt;
+ sc->sc_tag = pa->pa_tag;
+ sc->sc_function = pa->pa_function;
+
+ sc->sc_intrline = pa->pa_intrline;
+ sc->sc_intrtag = pa->pa_intrtag;
+ sc->sc_intrpin = pa->pa_intrpin;
+
+ pccbb_chipinit(pa, sc);
+
+ base_memt = sc->sc_base_memt; /* socket regs memory tag */
+ base_memh = sc->sc_base_memh; /* socket regs memory handle */
+
+ /* CSC Interrupt: Card detect interrupt on */
+ maskreg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_MASK);
+ maskreg |= CB_SOCKET_MASK_CD; /* Card detect intr is turned on. */
+ bus_space_write_4(base_memt, base_memh, CB_SOCKET_MASK, maskreg);
+ /* reset interrupt */
+ bus_space_write_4(base_memt, base_memh, CB_SOCKET_EVENT,
+ bus_space_read_4(base_memt, base_memh, CB_SOCKET_EVENT));
+
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, (void(*)(void*))pccbbintr, sc);
+ /*
+ * queue creation of a kernel thread to handle insert/removal events.
+ */
+ pccbb_kthread_init (sc);
+
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname);
+ if (intrstr != NULL) {
+ printf(" at %s", intrstr);
+ }
+ printf("\n");
+ return;
+ }
+
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ /* Check card exists or not. if exists, cb_reset will reset card */
+ {
+ u_int32_t sockstat = bus_space_read_4(base_memt,base_memh, CB_SOCKET_STAT);
+ if (0 == (sockstat & CB_SOCKET_STAT_CD)) { /* card exist */
+ sc->sc_flags |= CBB_CARDEXIST;
+ }
+ }
+ /****** attach cardbus ******/
+ {
+ struct cbslot_attach_args cba;
+ struct cardbus_softc *csc; /* child softc */
+ u_int32_t busreg = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM);
+
+ /* initialise cbslot_attach */
+ cba.cba_busname = "cardbus";
+ cba.cba_iot = pa->pa_iot;
+ cba.cba_memt = pa->pa_memt;
+ cba.cba_dmat = pa->pa_dmat;
+#if 1 /* XXX */
+ cba.cba_function = pa->pa_function;
+#else
+ cba.cba_function = 0;
+#endif
+ cba.cba_bus = (busreg >> 8) & 0x0ff;
+ cba.cba_cc = (void *)sc;
+ cba.cba_cf = &pccbb_funcs;
+ cba.cba_intrline = pci_intr_line (pa, ih);
+#if defined SHOW_REGS
+ cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt, sc->sc_base_memh);
+#endif
+ if (NULL != (csc = (void *)config_found(self, &cba, cbbprint))) {
+ DPRINTF(("pccbbattach: found cardbus\n"));
+ sc->sc_csc = csc;
+ }
+ }
+
+ /****** attach pccard bus ******/
+ pccbb_pcmcia_attach(sc);
+
+ return;
+}
+
+static void
+pccbb_chipinit(pa, sc)
+ struct pci_attach_args *pa;
+ struct pccbb_softc *sc;
+{
+ pci_chipset_tag_t pc = pa->pa_pc;
+ bus_space_tag_t base_memt = sc->sc_base_memt; /* socket regs memory tag */
+ bus_space_handle_t base_memh = sc->sc_base_memh; /* socket regs memory handle */
+ pcireg_t cbctrl;
+
+ /*
+ Set CardBus latency timer
+ */
+ {
+ pcireg_t pci_lscp = pci_conf_read(pc, pa->pa_tag, PCI_CB_LSCP_REG);
+ if (PCI_CB_LATENCY(pci_lscp) < 0x20) {
+ pci_lscp &= ~(PCI_CB_LATENCY_MASK << PCI_CB_LATENCY_SHIFT);
+ pci_lscp |= (0x20 << PCI_CB_LATENCY_SHIFT);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_LSCP_REG, pci_lscp);
+ }
+ printf("CardBus latency time 0x%x\n", PCI_CB_LATENCY(pci_lscp));
+ }
+
+ /*
+ Set PCI latency timer
+ */
+ {
+ pcireg_t pci_bhlc = pci_conf_read(pc, pa->pa_tag, PCI_BHLC_REG);
+ if (PCI_LATTIMER(pci_bhlc) < 0x20) {
+ pci_bhlc &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
+ pci_bhlc |= (0x20 << PCI_LATTIMER_SHIFT);
+ pci_conf_write(pc, pa->pa_tag, PCI_BHLC_REG, pci_bhlc);
+ }
+ printf("PCI latency time 0x%x\n", PCI_LATTIMER(pci_bhlc));
+ }
+
+ /* disable Legacy IO */
+
+ switch (sc->sc_chipset) {
+ case CB_RF5C46X:
+ {
+ pcireg_t bcri = pci_conf_read(pc, pa->pa_tag, PCI_BCR_INTR);
+ bcri &= ~(CB_BCRI_RL_3E0_ENA | CB_BCRI_RL_3E2_ENA);
+ pci_conf_write(pc, pa->pa_tag, PCI_BCR_INTR, bcri);
+ }
+ break;
+ default:
+ /* XXX: I don't know how to kill Legacy IO properly. */
+ pci_conf_write(pc, pa->pa_tag, PCI_LEGACY, 0x0);
+ break;
+ }
+
+ /****** Interrupt routing ******/
+
+ /* use PCI interrupt */
+ {
+ u_int32_t bcr = pci_conf_read(pc, pa->pa_tag, PCI_BCR_INTR);
+ bcr &= ~CB_BCR_INTR_IREQ_ENABLE; /* use PCI Intr */
+ bcr |= CB_BCR_WRITE_POST_ENABLE; /* enable write post */
+ pci_conf_write(pc, pa->pa_tag, PCI_BCR_INTR, bcr);
+ }
+
+ if (CB_TI113X == sc->sc_chipset) {
+ cbctrl = pci_conf_read(pc, pa->pa_tag, PCI_CBCTRL);
+ if (0 == pa->pa_function) {
+ cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA;
+ }
+ cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA; /* XXX: bug in PCI113X */
+ cbctrl |= PCI113X_CBCTRL_PCI_CSC; /* CSC intr enable */
+ cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr prohibit */
+ cbctrl &= ~PCI113X_CBCTRL_INT_MASK; /* prohibit ISA routing */
+ pci_conf_write(pc, pa->pa_tag, PCI_CBCTRL, cbctrl);
+
+ /* set ExCA regs: PCI113X required to be set bit 4 at Interrupt
+ and General Register, which is IRQ Enable Register, and clear
+ bit 3:0 to zero in order to route CSC interrupt to PCI
+ interrupt pin. */
+ bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
+ /* set ExCA regs: prohibit all pcmcia-style CSC intr. */
+ bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
+#if 1
+ DPRINTF(("ExCA regs:"));
+ DPRINTF((" 0x803: %02x", bus_space_read_1(base_memt, base_memh, 0x803)));
+ DPRINTF((" 0x805: %02x", bus_space_read_1(base_memt, base_memh, 0x805)));
+ DPRINTF((" 0x81e: %02x\n", bus_space_read_1(base_memt,base_memh,0x81e)));
+#endif
+ } else if (sc->sc_chipset == CB_TI12XX) {
+ cbctrl = pci_conf_read(pc, pa->pa_tag, PCI_CBCTRL);
+ cbctrl &= ~PCI12XX_CBCTRL_INT_MASK; /* intr routing reset */
+ cbctrl |= PCI12XX_CBCTRL_INT_PCI; /* PCI intr */
+ pci_conf_write(pc, pa->pa_tag, PCI_CBCTRL, cbctrl);
+ bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
+ bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
+ } else if (sc->sc_chipset == CB_TOPIC95B) {
+ cardbusreg_t sock_ctrl, slot_ctrl;
+
+ sock_ctrl = pci_conf_read(pc, pa->pa_tag, TOPIC_SOCKET_CTRL);
+ pci_conf_write(pc, pa->pa_tag, TOPIC_SOCKET_CTRL,
+ sock_ctrl | TOPIC_SOCKET_CTRL_SCR_IRQSEL);
+
+ slot_ctrl = pci_conf_read(pc, pa->pa_tag, TOPIC_SLOT_CTRL);
+ DPRINTF(("%s: topic slot ctrl reg 0x%x -> ", sc->sc_dev.dv_xname,
+ slot_ctrl));
+/* slot_ctrl &= ~TOPIC_SLOT_CTRL_CLOCK_MASK;*/
+ slot_ctrl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
+ TOPIC_SLOT_CTRL_ID_LOCK);
+ slot_ctrl |= TOPIC_SLOT_CTRL_CARDBUS;
+ slot_ctrl &= ~TOPIC_SLOT_CTRL_SWDETECT;
+ pci_conf_write(pc, pa->pa_tag, TOPIC_SLOT_CTRL, slot_ctrl);
+ DPRINTF(("0x%x\n", slot_ctrl));
+ }
+
+ /* close all memory and io windows */
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMBASE0, 0xffffffff);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMLIMIT0, 0);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMBASE1, 0xffffffff);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_MEMLIMIT1, 0);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_IOBASE0, 0xffffffff);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_IOLIMIT0, 0);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_IOBASE1, 0xffffffff);
+ pci_conf_write(pc, pa->pa_tag, PCI_CB_IOLIMIT1, 0);
+
+}
+
+
+/****** attach pccard bus ******/
+STATIC void
+pccbb_pcmcia_attach(sc)
+ struct pccbb_softc *sc;
+{
+ struct cbb_pcic_handle *ph = &sc->sc_pcmcia_h;
+ struct pcmciabus_attach_args paa;
+
+ sc->sc_pcmcia_flags |= (PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32);
+
+ /* initialise pcmcia part in pccbb_softc */
+ ph->sc = sc;
+ ph->sock = sc->sc_function;
+ ph->flags = 0;
+ ph->shutdown = 0;
+ ph->ih_irq = sc->sc_intrline;
+ ph->ph_iot = sc->sc_base_memt;
+ ph->ph_ioh = sc->sc_base_memh;
+ ph->ph_read = pccbb_pcmcia_read;
+ ph->ph_write = pccbb_pcmcia_write;
+ sc->sc_pct = &pccbb_pcmcia_funcs;
+
+ Pcic_write(ph, PCIC_CSC_INTR, 0);
+ Pcic_read(ph, PCIC_CSC);
+
+ /* initialise pcmcia bus attachment */
+ paa.paa_busname = "pcmcia";
+ paa.pct = sc->sc_pct;
+ paa.pch = ph;
+ paa.iobase = 0; /* I don't use them */
+ paa.iosize = 0;
+
+ ph->pcmcia = config_found_sm(&ph->sc->sc_dev, &paa, pccbb_pcmcia_print,
+ pccbb_pcmcia_submatch);
+ if (ph->pcmcia != NULL) {
+ if (1 == pccbb_detect_card(sc)) {
+ printf("%s: a 16-bit pcmcia card found.\n", sc->sc_dev.dv_xname); /*XXX*/
+ pccbb_pcmcia_attach_card(ph);
+ }
+ }
+ return;
+}
+
+
+
+STATIC void
+pccbb_pcmcia_attach_card(ph)
+ struct cbb_pcic_handle *ph;
+{
+ struct pcmcia_softc *psc = (void*)ph->pcmcia;
+ if (ph->flags & PCIC_FLAG_CARDP) {
+ panic("pccbb_pcmcia_attach_card: already attached");
+ }
+
+ /* call the MI attach function */
+ psc->sc_if.if_card_attach(ph->pcmcia);
+ ph->flags |= PCIC_FLAG_CARDP;
+}
+
+
+STATIC void
+pccbb_pcmcia_detach_card(ph, flags)
+ struct cbb_pcic_handle *ph;
+ int flags;
+{
+ struct pcmcia_softc *psc = (void*)ph->pcmcia;
+ if (!(ph->flags & PCIC_FLAG_CARDP)) {
+ panic("pccbb_pcmcia_detach_card: already detached");
+ }
+
+ ph->flags &= ~PCIC_FLAG_CARDP;
+
+ /* call the MI detach function */
+ psc->sc_if.if_card_detach (ph->pcmcia, flags);
+}
+
+/**********************************************************************
+* int pccbbintr(arg)
+* void *arg;
+* This routine handles the interrupt from Yenta PCI-CardBus bridge
+* itself.
+**********************************************************************/
+int
+pccbbintr(arg)
+ void *arg;
+{
+ struct pccbb_softc *sc = arg;
+ bus_space_tag_t memt = sc->sc_base_memt;
+ bus_space_handle_t memh = sc->sc_base_memh;
+ u_int32_t sockevent, sockstate;
+ int s;
+
+ if (!(sockevent = bus_space_read_4 (memt, memh, CB_SOCKET_EVENT)))
+ return 0; /* not for me */
+ /* reset bit */
+ bus_space_write_4 (memt, memh, CB_SOCKET_EVENT, sockevent);
+
+ if (sockevent & CB_SOCKET_EVENT_CD) {
+ if (!(sc->sc_flags & CBB_CARDSTATUS_BUSY)) {
+ s = splhigh (); /* lock softc */
+ sc->sc_queued = 1;
+ sc->sc_flags |= CBB_CARDSTATUS_BUSY;
+ splx (s); /* unlock softc */
+ wakeup (&sc->events);
+ } else {
+ DPRINTF(("%s (pccbbintr): busy", sc->sc_dev.dv_xname));
+ sc->sc_flags &= ~CBB_CARDSTATUS_BUSY; /* XXX chatterling interrupts. Should change code like as i82365.c */
+ }
+ } else {
+ sockstate = bus_space_read_4 (memt, memh, CB_SOCKET_STAT);
+ DPRINTF(("%s (pccbbintr): 0x%08x", sc->sc_dev.dv_xname, sockevent));
+ if (sockevent & CB_SOCKET_EVENT_CSTS) {
+ DPRINTF((" cstsevent occures, 0x%08x\n", sockstate));
+ } else if (sockevent & CB_SOCKET_EVENT_POWER) {
+ DPRINTF((" pwrevent occures, 0x%08x\n", sockstate));
+ } else {
+ DPRINTF((" unknown event, 0x%08x\n", sockstate));
+ }
+ }
+
+ return 1;
+}
+
+static void
+pccbb_insert(arg)
+ void *arg;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)arg;
+ u_int32_t sockevent, sockstate;
+ int timeout = 30;
+ do {
+ sockevent = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
+ CB_SOCKET_EVENT);
+ sockstate = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
+ CB_SOCKET_STAT);
+ } while (sockstate & CB_SOCKET_STAT_CD && --timeout > 0);
+ if (timeout < 0) {
+ printf ("%s: insert timeout", sc->sc_dev.dv_xname);
+ return;
+ }
+ DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname, sockevent));
+ DPRINTF((" card inserted, 0x%08x\n", sockstate));
+ sc->sc_flags |= CBB_CARDEXIST;
+ /* call pccard intterupt handler here */
+ if (sockstate & CB_SOCKET_STAT_16BIT) {
+ /* 16-bit card */
+ pccbb_pcmcia_attach_card(&sc->sc_pcmcia_h);
+ } else if (sockstate & CB_SOCKET_STAT_CB) {
+ /* 32-bit card */
+ sc->sc_cbdev = sc->sc_csc->sc_if.if_card_attach (sc->sc_csc);
+ } else {
+ printf ("unknown card type.\n");
+ }
+}
+
+#define PCCBB_PCMCIA_OFFSET 0x800
+static u_int8_t
+pccbb_pcmcia_read(ph, reg)
+ struct cbb_pcic_handle *ph;
+ int reg;
+{
+ return bus_space_read_1(ph->ph_iot, ph->ph_ioh, PCCBB_PCMCIA_OFFSET + reg);
+}
+
+static void
+pccbb_pcmcia_write(ph, reg, val)
+ struct cbb_pcic_handle *ph;
+ int reg;
+ u_int8_t val;
+{
+ bus_space_write_1(ph->ph_iot, ph->ph_ioh, PCCBB_PCMCIA_OFFSET + reg, val);
+
+ return;
+}
+
+/**********************************************************************
+* STATIC int pccbb_ctrl(cardbus_chipset_tag_t, int)
+**********************************************************************/
+STATIC int
+pccbb_ctrl(ct, command)
+ cardbus_chipset_tag_t ct;
+ int command;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ switch(command) {
+ case CARDBUS_CD:
+ if (2 == pccbb_detect_card(sc)) {
+ int retval = 0;
+ int status = cb_detect_voltage(sc);
+ if (PCCARD_VCC_5V & status) {
+ retval |= CARDBUS_5V_CARD;
+ }
+ if (PCCARD_VCC_3V & status) {
+ retval |= CARDBUS_3V_CARD;
+ }
+ if (PCCARD_VCC_XV & status) {
+ retval |= CARDBUS_XV_CARD;
+ }
+ if (PCCARD_VCC_YV & status) {
+ retval |= CARDBUS_YV_CARD;
+ }
+ return retval;
+ } else {
+ return 0;
+ }
+ break;
+ case CARDBUS_RESET:
+ return cb_reset(sc);
+ break;
+ case CARDBUS_IO_ENABLE: /* fallthrough */
+ case CARDBUS_IO_DISABLE: /* fallthrough */
+ case CARDBUS_MEM_ENABLE: /* fallthrough */
+ case CARDBUS_MEM_DISABLE: /* fallthrough */
+ case CARDBUS_BM_ENABLE: /* fallthrough */
+ case CARDBUS_BM_DISABLE: /* fallthrough */
+ return pccbb_cardenable(sc, command);
+ break;
+ }
+
+ return 0;
+}
+
+
+
+/**********************************************************************
+* STATIC int pccbb_power(cardbus_chipset_tag_t, int)
+* This function returns true when it succeeds and returns false when
+* it fails.
+**********************************************************************/
+STATIC int
+pccbb_power(ct, command)
+ cardbus_chipset_tag_t ct;
+ int command;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ u_int32_t status, sock_ctrl;
+ bus_space_tag_t memt = sc->sc_base_memt;
+ bus_space_handle_t memh = sc->sc_base_memh;
+
+ DPRINTF(("pccbb_power: %s and %s [%x]\n",
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_UC ? "CARDBUS_VCC_UC" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_5V ? "CARDBUS_VCC_5V" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_3V ? "CARDBUS_VCC_3V" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_XV ? "CARDBUS_VCC_XV" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_YV ? "CARDBUS_VCC_YV" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V ? "CARDBUS_VCC_0V" :
+ "UNKNOWN",
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_UC ? "CARDBUS_VPP_UC" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_12V ? "CARDBUS_VPP_12V" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_VCC ? "CARDBUS_VPP_VCC" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_0V ? "CARDBUS_VPP_0V" :
+ "UNKNOWN",
+ command));
+
+ status = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
+ sock_ctrl = bus_space_read_4(memt, memh, CB_SOCKET_CTRL);
+
+ switch (command & CARDBUS_VCCMASK) {
+ case CARDBUS_VCC_UC:
+ break;
+ case CARDBUS_VCC_5V:
+ if (CB_SOCKET_STAT_5VCARD & status) { /* check 5 V card */
+ sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
+ sock_ctrl |= CB_SOCKET_CTRL_VCC_5V;
+ } else {
+ printf("%s: BAD voltage request: no 5 V card\n", sc->sc_dev.dv_xname);
+ }
+ break;
+ case CARDBUS_VCC_3V:
+ if (CB_SOCKET_STAT_3VCARD & status) {
+ sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
+ sock_ctrl |= CB_SOCKET_CTRL_VCC_3V;
+ } else {
+ printf("%s: BAD voltage request: no 3.3 V card\n", sc->sc_dev.dv_xname);
+ }
+ break;
+ case CARDBUS_VCC_0V:
+ sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
+ break;
+ default:
+ return 0; /* power NEVER changed */
+ break;
+ }
+
+ switch (command & CARDBUS_VPPMASK) {
+ case CARDBUS_VPP_UC:
+ break;
+ case CARDBUS_VPP_0V:
+ sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
+ break;
+ case CARDBUS_VPP_VCC:
+ sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
+ sock_ctrl |= ((sock_ctrl >> 4) & 0x07);
+ break;
+ case CARDBUS_VPP_12V:
+ sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
+ sock_ctrl |= CB_SOCKET_CTRL_VPP_12V;
+ break;
+ }
+
+#if 0
+ DPRINTF(("sock_ctrl: %x\n", sock_ctrl));
+#endif
+ bus_space_write_4(memt, memh, CB_SOCKET_CTRL, sock_ctrl);
+ status = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
+
+ {
+ int timeout = 20;
+ u_int32_t sockevent;
+ do {
+ delay(20*1000); /* wait 20 ms: Vcc setup time */
+ sockevent = bus_space_read_4 (memt, memh, CB_SOCKET_EVENT);
+ } while (!(sockevent & CB_SOCKET_EVENT_POWER) && --timeout > 0);
+ /* reset event status */
+ bus_space_write_4 (memt, memh, CB_SOCKET_EVENT, sockevent);
+ if ( timeout < 0 ) {
+ printf ("VCC supply failed.\n");
+ return 0;
+ }
+ }
+ /* XXX
+ delay 400 ms: thgough the standard defines that the Vcc set-up time
+ is 20 ms, some PC-Card bridge requires longer duration.
+ */
+ delay(400*1000);
+
+ if (status & CB_SOCKET_STAT_BADVCC) { /* bad Vcc request */
+ printf("%s: bad Vcc request. sock_ctrl 0x%x, sock_status 0x%x\n",
+ sc->sc_dev.dv_xname, sock_ctrl ,status);
+ printf("pccbb_power: %s and %s [%x]\n",
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_UC ? "CARDBUS_VCC_UC" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_5V ? "CARDBUS_VCC_5V" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_3V ? "CARDBUS_VCC_3V" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_XV ? "CARDBUS_VCC_XV" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_YV ? "CARDBUS_VCC_YV" :
+ (command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V ? "CARDBUS_VCC_0V" :
+ "UNKNOWN",
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_UC ? "CARDBUS_VPP_UC" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_12V ? "CARDBUS_VPP_12V" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_VCC ? "CARDBUS_VPP_VCC" :
+ (command & CARDBUS_VPPMASK) == CARDBUS_VPP_0V ? "CARDBUS_VPP_0V" :
+ "UNKNOWN",
+ command);
+#if defined DIAGNOSTIC
+ if (command == (CARDBUS_VCC_0V | CARDBUS_VPP_0V)) {
+ u_int32_t force = bus_space_read_4(memt, memh, CB_SOCKET_FORCE);
+ /* Reset Bad Vcc request */
+ force &= ~CB_SOCKET_FORCE_BADVCC;
+ bus_space_write_4(memt, memh, CB_SOCKET_FORCE, force);
+ printf("new status 0x%x\n", bus_space_read_4(memt, memh,CB_SOCKET_STAT));
+ return 1;
+ }
+#endif
+ return 0;
+ }
+ return 1; /* power changed correctly */
+}
+
+/**********************************************************************
+* static int pccbb_detect_card(struct pccbb_softc *sc)
+* return value: 0 if no card exists.
+* 1 if 16-bit card exists.
+* 2 if cardbus card exists.
+**********************************************************************/
+static int
+pccbb_detect_card(sc)
+ struct pccbb_softc *sc;
+{
+ bus_space_handle_t base_memh = sc->sc_base_memh;
+ bus_space_tag_t base_memt = sc->sc_base_memt;
+ u_int32_t sockstat = bus_space_read_4(base_memt,base_memh, CB_SOCKET_STAT);
+ int retval = 0;
+
+ if (0x00 == (sockstat & CB_SOCKET_STAT_CD)) { /* CD1 and CD2 asserted */
+ /* card must be present */
+ if (!(CB_SOCKET_STAT_NOTCARD & sockstat)) { /* NOTACARD DEASSERTED */
+ if (CB_SOCKET_STAT_CB & sockstat) { /* CardBus mode */
+ retval = 2;
+ } else if (CB_SOCKET_STAT_16BIT & sockstat) { /* 16-bit mode */
+ retval = 1;
+ }
+ }
+ }
+ return retval;
+}
+
+
+
+
+/**********************************************************************
+* STATIC int cb_reset(struct pccbb_softc *sc)
+* This function resets the card.
+**********************************************************************/
+STATIC int
+cb_reset(sc)
+ struct pccbb_softc *sc;
+{
+ u_int32_t bcr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR);
+ int delay_us;
+ delay_us = sc->sc_chipset == CB_RF5C47X ? 400*1000 : 20*1000;
+
+ bcr |= (0x40 << 16); /* Reset bit Assert (bit 6 at 0x3E) */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR, bcr);
+ /* Reset Assert at least 20 ms */
+ delay(delay_us);
+
+ if (CBB_CARDEXIST & sc->sc_flags) { /* A card exists. Reset it! */
+ bcr &= ~(0x40 << 16); /* Reset bit Deassert (bit 6 at 0x3E) */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR, bcr);
+ delay(delay_us);
+ }
+ /* No card found on the slot. Keep Reset. */
+ return 1;
+}
+
+/**********************************************************************
+* STATIC int cb_detect_voltage(struct pccbb_softc *sc)
+* This function detect card Voltage.
+**********************************************************************/
+STATIC int
+cb_detect_voltage(sc)
+ struct pccbb_softc *sc;
+{
+ u_int32_t psr; /* socket present-state reg */
+ bus_space_tag_t iot = sc->sc_base_memt;
+ bus_space_handle_t ioh = sc->sc_base_memh;
+ int vol = PCCARD_VCC_UKN; /* set 0 */
+
+ psr = bus_space_read_4(iot, ioh, CB_SOCKET_STAT);
+
+ if (0x400u & psr) {
+ vol |= PCCARD_VCC_5V;
+ }
+ if (0x800u & psr) {
+ vol |= PCCARD_VCC_3V;
+ }
+
+ return vol;
+}
+
+/**********************************************************************
+* STATIC int pccbb_cardenable(struct pccbb_softc *sc, int function)
+* This function enables and disables the card
+**********************************************************************/
+STATIC int
+pccbb_cardenable(sc, function)
+ struct pccbb_softc *sc;
+ int function;
+{
+ u_int32_t command = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
+
+ DPRINTF(("pccbb_cardenable:"));
+ switch (function) {
+ case CARDBUS_IO_ENABLE:
+ command |= PCI_COMMAND_IO_ENABLE;
+ break;
+ case CARDBUS_IO_DISABLE:
+ command &= ~PCI_COMMAND_IO_ENABLE;
+ break;
+ case CARDBUS_MEM_ENABLE:
+ command |= PCI_COMMAND_MEM_ENABLE;
+ break;
+ case CARDBUS_MEM_DISABLE:
+ command &= ~PCI_COMMAND_MEM_ENABLE;
+ break;
+ case CARDBUS_BM_ENABLE:
+ command |= PCI_COMMAND_MASTER_ENABLE;
+ break;
+ case CARDBUS_BM_DISABLE:
+ command &= ~PCI_COMMAND_MASTER_ENABLE;
+ break;
+ default:
+ return 0;
+ }
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, command);
+ DPRINTF((" command reg 0x%x\n", command));
+ return 1;
+}
+
+
+
+
+
+
+
+/**********************************************************************
+* int pccbb_io_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)
+**********************************************************************/
+static int
+pccbb_io_open(ct, win, start, end)
+ cardbus_chipset_tag_t ct;
+ int win;
+ u_int32_t start, end;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+ int basereg;
+ int limitreg;
+
+ if ((win < 0) || (win > 2)) {
+#if defined DIAGNOSTIC
+ printf("cardbus_io_open: window out of range %d\n", win);
+#endif
+ return 0;
+ }
+
+ basereg = win*8 + 0x2c;
+ limitreg = win*8 + 0x30;
+
+ DPRINTF(("pccbb_io_open: 0x%x[0x%x] - 0x%x[0x%x]\n",
+ start, basereg, end, limitreg));
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end);
+ return 1;
+}
+
+/**********************************************************************
+* int pccbb_io_close(cardbus_chipset_tag_t, int)
+**********************************************************************/
+static int
+pccbb_io_close(ct, win)
+ cardbus_chipset_tag_t ct;
+ int win;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+ int basereg;
+ int limitreg;
+
+ if ((win < 0) || (win > 2)) {
+#if defined DIAGNOSTIC
+ printf("cardbus_io_close: window out of range %d\n", win);
+#endif
+ return 0;
+ }
+
+ basereg = win*8 + 0x2c;
+ limitreg = win*8 + 0x30;
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0);
+ return 1;
+}
+
+/**********************************************************************
+* int pccbb_mem_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)
+**********************************************************************/
+static int
+pccbb_mem_open(ct, win, start, end)
+ cardbus_chipset_tag_t ct;
+ int win;
+ u_int32_t start, end;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+ int basereg;
+ int limitreg;
+
+ if ((win < 0) || (win > 2)) {
+#if defined DIAGNOSTIC
+ printf("cardbus_mem_open: window out of range %d\n", win);
+#endif
+ return 0;
+ }
+
+ basereg = win*8 + 0x1c;
+ limitreg = win*8 + 0x20;
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end);
+ return 1;
+}
+
+
+/**********************************************************************
+* int pccbb_mem_close(cardbus_chipset_tag_t, int);
+**********************************************************************/
+static int
+pccbb_mem_close(ct, win)
+ cardbus_chipset_tag_t ct;
+ int win;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+ int basereg;
+ int limitreg;
+
+ if ((win < 0) || (win > 2)) {
+#if defined DIAGNOSTIC
+ printf("cardbus_mem_close: window out of range %d\n", win);
+#endif
+ return 0;
+ }
+
+ basereg = win*8 + 0x1c;
+ limitreg = win*8 + 0x20;
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0);
+ return 1;
+}
+
+
+
+
+
+static void *
+pccbb_intr_establish(ct, irq, level, func, arg)
+ cardbus_chipset_tag_t ct;
+ int irq, level;
+ int (* func) __P((void *));
+ void *arg;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ switch (sc->sc_chipset) {
+ case CB_TI113X:
+ {
+ pcireg_t cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL);
+ cbctrl |= PCI113X_CBCTRL_PCI_INTR; /* functional intr enabled */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return pci_intr_establish(sc->sc_pc, irq, level, (void(*)(void*))func, arg);
+}
+
+
+
+
+static void
+pccbb_intr_disestablish(ct, ih)
+ cardbus_chipset_tag_t ct;
+ void *ih;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ switch (sc->sc_chipset) {
+ case CB_TI113X:
+ {
+ pcireg_t cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL);
+ cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr disabled */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl);
+ }
+ break;
+ default:
+ break;
+ }
+
+ pci_intr_disestablish(sc->sc_pc, ih);
+}
+
+
+
+
+
+#if defined SHOW_REGS
+static void
+cb_show_regs(pc, tag, memt, memh)
+ pci_chipset_tag_t pc;
+ pcitag_t tag;
+ bus_space_tag_t memt;
+ bus_space_handle_t memh;
+{
+ int i;
+ printf("PCI config regs:");
+ for (i = 0; i < 0x50; i += 4) {
+ if (i % 16 == 0) {
+ printf("\n 0x%02x:", i);
+ }
+ printf(" %08lx", pci_conf_read(pc, tag, i));
+ }
+ for (i = 0x80; i < 0xb0; i += 4) {
+ if (i % 16 == 0) {
+ printf("\n 0x%02x:", i);
+ }
+ printf(" %08lx", pci_conf_read(pc, tag, i));
+ }
+
+ if (memh.addr == 0) {/* XXX */
+ printf("\n");
+ return;
+ }
+
+ printf("\nsocket regs:");
+ for (i = 0; i <= 0x10; i += 0x04) {
+ printf(" %08x", bus_space_read_4(memt, memh, i));
+ }
+ printf("\nExCA regs:");
+ for (i = 0; i < 0x08; ++i) {
+ printf(" %02x", bus_space_read_1(memt, memh, 0x800 + i));
+ }
+ printf("\n");
+ return;
+}
+#endif
+
+
+/**********************************************************************
+* static cardbustag_t pccbb_make_tag(cardbus_chipset_tag_t cc,
+* int busno, int devno, int function);
+* This is the function to make a tag to access config space of
+* a CardBus Card. It works same as pci_conf_read.
+**********************************************************************/
+static cardbustag_t
+pccbb_make_tag(cc, busno, devno, function)
+ cardbus_chipset_tag_t cc;
+ int busno, devno, function;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)cc;
+
+ return pci_make_tag(sc->sc_pc, busno, devno, function);
+}
+static void
+pccbb_free_tag (cardbus_chipset_tag_t cc, cardbustag_t tag)
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)cc;
+ pci_free_tag (tag);
+ return;
+}
+
+/**********************************************************************
+* static cardbusreg_t pccbb_conf_read(cardbus_chipset_tag_t cc,
+* cardbustag_t tag, int offset)
+* This is the function to read the config space of a CardBus Card.
+* It works same as pci_conf_read.
+**********************************************************************/
+static cardbusreg_t
+pccbb_conf_read(ct, tag, offset)
+ cardbus_chipset_tag_t ct;
+ cardbustag_t tag;
+ int offset; /* register offset */
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ return pci_conf_read(sc->sc_pc, tag, offset);
+}
+
+
+
+/**********************************************************************
+* static void pccbb_conf_write(cardbus_chipset_tag_t cc, cardbustag_t tag,
+* int offs, cardbusreg_t val)
+* This is the function to write the config space of a CardBus Card.
+* It works same as pci_conf_write.
+**********************************************************************/
+static void
+pccbb_conf_write(ct, tag, reg, val)
+ cardbus_chipset_tag_t ct;
+ cardbustag_t tag;
+ int reg; /* register offset */
+ cardbusreg_t val;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ pci_conf_write(sc->sc_pc, tag, reg, val);
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_io_alloc(pcmcia_chipset_handle_t pch,
+* bus_addr_t start, bus_size_t size,
+* bus_size_t align,
+* struct pcmcia_io_handle *pcihp
+*
+* This function only allocates I/O region for pccard. This function
+* never maps the allcated region to pccard I/O area.
+*
+* XXX: The interface of this function is not very good, I believe.
+**********************************************************************/
+ STATIC int
+pccbb_pcmcia_io_alloc(pch, start, size, align, pcihp)
+ pcmcia_chipset_handle_t pch;
+ bus_addr_t start; /* start address */
+ bus_size_t size;
+ bus_size_t align;
+ struct pcmcia_io_handle *pcihp;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ bus_addr_t ioaddr;
+ int flags = 0;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+
+ /*
+ * Allocate some arbitrary I/O space.
+ */
+
+ iot = ph->sc->sc_iot;
+
+ if (start) {
+ ioaddr = start;
+ if (bus_space_map(iot, start, size, 0, &ioh)) {
+ return 1;
+ }
+ DPRINTF(("pccbb_pcmcia_io_alloc map port %lx+%lx\n",
+ (u_long) ioaddr, (u_long) size));
+ } else {
+ flags |= PCMCIA_IO_ALLOCATED;
+ if (bus_space_alloc(iot, 0x700/* ph->sc->sc_iobase */,
+ 0x800/* ph->sc->sc_iobase + ph->sc->sc_iosize*/,
+ size, align, 0, 0, &ioaddr, &ioh)) {
+ /* No room be able to be get. */
+ return 1;
+ }
+ DPRINTF(("pccbb_pcmmcia_io_alloc alloc port 0x%lx+0x%lx\n",
+ (u_long) ioaddr, (u_long) size));
+ }
+
+ pcihp->iot = iot;
+ pcihp->ioh = ioh;
+ pcihp->addr = ioaddr;
+ pcihp->size = size;
+ pcihp->flags = flags;
+
+ return 0;
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_io_free(pcmcia_chipset_handle_t pch,
+* struct pcmcia_io_handle *pcihp)
+*
+* This function only frees I/O region for pccard.
+*
+* XXX: The interface of this function is not very good, I believe.
+**********************************************************************/
+void
+pccbb_pcmcia_io_free(pch, pcihp)
+ pcmcia_chipset_handle_t pch;
+ struct pcmcia_io_handle *pcihp;
+{
+ bus_space_tag_t iot = pcihp->iot;
+ bus_space_handle_t ioh = pcihp->ioh;
+ bus_size_t size = pcihp->size;
+
+ if (pcihp->flags & PCMCIA_IO_ALLOCATED)
+ bus_space_free(iot, ioh, size);
+ else
+ bus_space_unmap(iot, ioh, size);
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_io_map(pcmcia_chipset_handle_t pch, int width,
+* bus_addr_t offset, bus_size_t size,
+* struct pcmcia_io_handle *pcihp,
+* int *windowp)
+*
+* This function maps the allocated I/O region to pccard. This function
+* never allocates any I/O region for pccard I/O area. I don't
+* understand why the original authors of pcmciabus separated alloc and
+* map. I believe the two must be unite.
+*
+* XXX: no wait timing control?
+**********************************************************************/
+int
+pccbb_pcmcia_io_map(pch, width, offset, size, pcihp, windowp)
+ pcmcia_chipset_handle_t pch;
+ int width;
+ bus_addr_t offset;
+ bus_size_t size;
+ struct pcmcia_io_handle *pcihp;
+ int *windowp;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *) pch;
+ bus_addr_t ioaddr = pcihp->addr + offset;
+ int i, win;
+#if defined CBB_DEBUG
+ static char *width_names[] = { "dynamic", "io8", "io16" };
+#endif
+
+ /* Sanity check I/O handle. */
+
+ if (ph->sc->sc_iot != pcihp->iot) {
+ panic("pccbb_pcmcia_io_map iot is bogus");
+ }
+
+ /* XXX Sanity check offset/size. */
+
+ win = -1;
+ for (i = 0; i < PCIC_IO_WINS; i++) {
+ if ((ph->ioalloc & (1 << i)) == 0) {
+ win = i;
+ ph->ioalloc |= (1 << i);
+ break;
+ }
+ }
+
+ if (win == -1) {
+ return 1;
+ }
+
+ *windowp = win;
+
+ /* XXX this is pretty gross */
+
+ DPRINTF(("pccbb_pcmcia_io_map window %d %s port %lx+%lx\n",
+ win, width_names[width], (u_long) ioaddr, (u_long) size));
+
+ /* XXX wtf is this doing here? */
+
+#if 0
+ printf(" port 0x%lx", (u_long) ioaddr);
+ if (size > 1) {
+ printf("-0x%lx", (u_long) ioaddr + (u_long) size - 1);
+ }
+#endif
+
+ ph->io[win].addr = ioaddr;
+ ph->io[win].size = size;
+ ph->io[win].width = width;
+
+ /* actual dirty register-value changing in the function below. */
+ pccbb_pcmcia_do_io_map(ph, win);
+
+ return 0;
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_do_io_map(struct pcic_handle *h, int win)
+*
+* This function changes register-value to map I/O region for pccard.
+**********************************************************************/
+static void
+pccbb_pcmcia_do_io_map(ph, win)
+ struct cbb_pcic_handle *ph;
+ int win;
+{
+ static u_int8_t pcic_iowidth[3] = {
+ PCIC_IOCTL_IO0_IOCS16SRC_CARD,
+ PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE | PCIC_IOCTL_IO0_DATASIZE_8BIT,
+ PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE | PCIC_IOCTL_IO0_DATASIZE_16BIT,
+ };
+
+#define PCIC_SIA_START_LOW 0
+#define PCIC_SIA_START_HIGH 1
+#define PCIC_SIA_STOP_LOW 2
+#define PCIC_SIA_STOP_HIGH 3
+
+ int regbase_win = 0x8 + win*0x04;
+ u_int8_t ioctl, enable;
+
+ DPRINTF(("pccbb_pcmcia_do_io_map win %d addr 0x%lx size 0x%lx width %d\n",
+ win, (long) ph->io[win].addr, (long) ph->io[win].size,
+ ph->io[win].width * 8));
+
+ Pcic_write(ph, regbase_win + PCIC_SIA_START_LOW,
+ ph->io[win].addr & 0xff);
+ Pcic_write(ph, regbase_win + PCIC_SIA_START_HIGH,
+ (ph->io[win].addr >> 8) & 0xff);
+
+ Pcic_write(ph, regbase_win + PCIC_SIA_STOP_LOW,
+ (ph->io[win].addr + ph->io[win].size - 1) & 0xff);
+ Pcic_write(ph, regbase_win + PCIC_SIA_STOP_HIGH,
+ ((ph->io[win].addr + ph->io[win].size - 1) >> 8) & 0xff);
+
+ ioctl = Pcic_read(ph, PCIC_IOCTL);
+ enable = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
+ switch (win) {
+ case 0:
+ ioctl &= ~(PCIC_IOCTL_IO0_WAITSTATE | PCIC_IOCTL_IO0_ZEROWAIT |
+ PCIC_IOCTL_IO0_IOCS16SRC_MASK | PCIC_IOCTL_IO0_DATASIZE_MASK);
+ ioctl |= pcic_iowidth[ph->io[win].width];
+ enable |= PCIC_ADDRWIN_ENABLE_IO0;
+ break;
+ case 1:
+ ioctl &= ~(PCIC_IOCTL_IO1_WAITSTATE | PCIC_IOCTL_IO1_ZEROWAIT |
+ PCIC_IOCTL_IO1_IOCS16SRC_MASK | PCIC_IOCTL_IO1_DATASIZE_MASK);
+ ioctl |= (pcic_iowidth[ph->io[win].width] << 4);
+ enable |= PCIC_ADDRWIN_ENABLE_IO1;
+ break;
+ }
+ Pcic_write(ph, PCIC_IOCTL, ioctl);
+ Pcic_write(ph, PCIC_ADDRWIN_ENABLE, enable);
+#if defined CBB_DEBUG
+ {
+ u_int8_t start_low = Pcic_read(ph, regbase_win + PCIC_SIA_START_LOW);
+ u_int8_t start_high = Pcic_read(ph, regbase_win + PCIC_SIA_START_HIGH);
+ u_int8_t stop_low = Pcic_read(ph, regbase_win + PCIC_SIA_STOP_LOW);
+ u_int8_t stop_high = Pcic_read(ph, regbase_win + PCIC_SIA_STOP_HIGH);
+ printf(" start %02x %02x, stop %02x %02x, ioctl %02x enable %02x\n",
+ start_low, start_high, stop_low, stop_high, ioctl, enable);
+ }
+#endif
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_io_unmap(pcmcia_chipset_handle_t *h, int win)
+*
+* This function unmapss I/O region. No return value.
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_io_unmap(pch, win)
+ pcmcia_chipset_handle_t pch;
+ int win;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ int reg;
+
+ if (win >= PCIC_IO_WINS || win < 0) {
+ panic("pccbb_pcmcia_io_unmap: window out of range");
+ }
+
+ reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
+ switch (win) {
+ case 0:
+ reg &= ~PCIC_ADDRWIN_ENABLE_IO0;
+ break;
+ case 1:
+ reg &= ~PCIC_ADDRWIN_ENABLE_IO1;
+ break;
+ }
+ Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
+
+ ph->ioalloc &= ~(1 << win);
+}
+
+/**********************************************************************
+* static void pccbb_pcmcia_wait_ready(struct cbb_pcic_handle *ph)
+*
+* This function enables the card. All information is stored in
+* the first argument, pcmcia_chipset_handle_t.
+**********************************************************************/
+static void
+pccbb_pcmcia_wait_ready(ph)
+ struct cbb_pcic_handle *ph;
+{
+ int i;
+
+ DPRINTF(("pccbb_pcmcia_wait_ready: status 0x%02x\n",
+ Pcic_read(ph, PCIC_IF_STATUS)));
+
+ for (i = 0; i < 10000; i++) {
+ if (Pcic_read(ph, PCIC_IF_STATUS) & PCIC_IF_STATUS_READY) {
+ return;
+ }
+ delay(500);
+#ifdef CBB_DEBUG
+ if ((i > 5000) && (i%100 == 99))
+ printf(".");
+#endif
+ }
+
+#ifdef DIAGNOSTIC
+ printf("pcic_wait_ready: ready never happened, status = %02x\n",
+ Pcic_read(ph, PCIC_IF_STATUS));
+#endif
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_socket_enable(pcmcia_chipset_handle_t pch)
+*
+* This function enables the card. All information is stored in
+* the first argument, pcmcia_chipset_handle_t.
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_socket_enable(pch)
+ pcmcia_chipset_handle_t pch;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ struct pccbb_softc *sc = ph->sc;
+ struct pcmcia_softc *psc = (void*)ph->pcmcia;
+ int cardtype, win;
+ u_int8_t power, intr;
+ pcireg_t spsr;
+ int voltage;
+#define PCIC_INTR_PCI PCIC_INTR_ENABLE
+
+ /* this bit is mostly stolen from pcic_attach_card */
+
+ DPRINTF(("pccbb_pcmcia_socket_enable:\n"));
+
+ /* get card Vcc info */
+
+ spsr = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_STAT);
+ if (spsr & CB_SOCKET_STAT_5VCARD) {
+ printf("5V card\n"); /* XXX */
+ voltage = CARDBUS_VCC_5V | CARDBUS_VPP_VCC;
+ } else if (spsr & CB_SOCKET_STAT_3VCARD) {
+ printf("3V card\n"); /* XXX */
+ voltage = CARDBUS_VCC_3V | CARDBUS_VPP_VCC;
+ } else {
+ printf("?V card, 0x%x\n", spsr); /* XXX */
+ return;
+ }
+
+ /* assert reset bit */
+
+ intr = Pcic_read(ph, PCIC_INTR);
+ intr &= ~PCIC_INTR_RESET;
+ intr |= PCIC_INTR_PCI; /* XXX */
+ Pcic_write(ph, PCIC_INTR, intr);
+
+ /* disable socket i/o: negate output enable bit */
+
+ power = Pcic_read(ph, PCIC_PWRCTL);
+ power &= ~PCIC_PWRCTL_OE;
+ Pcic_write(ph, PCIC_PWRCTL, power);
+
+ /* power down the socket to reset it, clear the card reset pin */
+
+ pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
+
+ /*
+ * wait 300ms until power fails (Tpf). Then, wait 100ms since
+ * we are changing Vcc (Toff).
+ */
+ delay((300 + 100)*1000);
+
+ /* power up the socket */
+ pccbb_power(sc, voltage);
+
+ /*
+ * wait 100ms until power raise (Tpr) and 20ms to become
+ * stable (Tsu(Vcc)).
+ *
+ * some machines require some more time to be settled
+ * (another 200ms is added here).
+ */
+ delay((100 + 20 + 200)*1000);
+
+ power = Pcic_read(ph, PCIC_PWRCTL);
+ Pcic_write(ph, PCIC_PWRCTL, power | PCIC_PWRCTL_OE);
+
+ /*
+ * hold RESET at least 10us.
+ */
+ delay(10);
+ delay(2*1000); /* XXX: TI1130 requires it. */
+
+ /* clear the reset flag */
+
+ intr = Pcic_read(ph, PCIC_INTR);
+ Pcic_write(ph, PCIC_INTR, intr | PCIC_INTR_RESET);
+
+ /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
+
+ delay(20000);
+
+ /* wait for the chip to finish initializing */
+
+ pccbb_pcmcia_wait_ready(ph);
+
+ /* zero out the address windows */
+
+ Pcic_write(ph, PCIC_ADDRWIN_ENABLE, 0);
+
+ /* set the card type */
+
+ cardtype = psc->sc_if.if_card_gettype(ph->pcmcia);
+
+ intr = Pcic_read(ph, PCIC_INTR);
+ intr &= ~PCIC_INTR_CARDTYPE_MASK;
+ intr |= ((cardtype == PCMCIA_IFTYPE_IO) ?
+ PCIC_INTR_CARDTYPE_IO :
+ PCIC_INTR_CARDTYPE_MEM);
+ Pcic_write(ph, PCIC_INTR, intr);
+
+ DPRINTF(("%s: pccbb_pcmcia_socket_enable %02x cardtype %s %02x\n",
+ ph->sc->sc_dev.dv_xname, ph->sock,
+ ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"), intr));
+
+ /* reinstall all the memory and io mappings */
+
+ for (win = 0; win < PCIC_MEM_WINS; ++win) {
+ if (ph->memalloc & (1 << win)) {
+ pccbb_pcmcia_do_mem_map(ph, win);
+ }
+ }
+
+ for (win = 0; win < PCIC_IO_WINS; ++win) {
+ if (ph->ioalloc & (1 << win)) {
+ pccbb_pcmcia_do_io_map(ph, win);
+ }
+ }
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_socket_disable(pcmcia_chipset_handle_t *ph)
+*
+* This function disables the card. All information is stored in
+* the first argument, pcmcia_chipset_handle_t.
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_socket_disable(pch)
+ pcmcia_chipset_handle_t pch;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ struct pccbb_softc *sc = ph->sc;
+ u_int8_t power, intr;
+
+ DPRINTF(("pccbb_pcmcia_socket_disable\n"));
+
+ /* reset signal asserting... */
+
+ intr = Pcic_read(ph, PCIC_INTR);
+ intr &= ~PCIC_INTR_RESET;
+ Pcic_write(ph, PCIC_INTR, intr);
+ delay(2*1000);
+
+ /* power down the socket */
+ power = Pcic_read(ph, PCIC_PWRCTL);
+ power &= ~PCIC_PWRCTL_OE;
+ Pcic_write(ph, PCIC_PWRCTL, power);
+ pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
+
+ /*
+ * wait 300ms until power fails (Tpf).
+ */
+ delay(300 * 1000);
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch,
+* bus_size_t size,
+* struct pcmcia_mem_handle *pcmhp)
+*
+* This function only allocates memory region for pccard. This
+* function never maps the allcated region to pccard memory area.
+*
+* XXX: Why the argument of start address is not in?
+**********************************************************************/
+STATIC int
+pccbb_pcmcia_mem_alloc(pch, size, pcmhp)
+ pcmcia_chipset_handle_t pch;
+ bus_size_t size;
+ struct pcmcia_mem_handle *pcmhp;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ bus_space_handle_t memh;
+ bus_addr_t addr;
+ bus_size_t sizepg;
+ struct pccbb_softc *sc = ph->sc;
+
+ /* out of sc->memh, allocate as many pages as necessary */
+
+ /* convert size to PCIC pages */
+ /*
+ This is not enough; when the requested region is on the
+ page boundaries, this may calculate wrong result.
+ */
+ sizepg = (size + (PCIC_MEM_PAGESIZE - 1)) / PCIC_MEM_PAGESIZE;
+#if 0
+ if (sizepg > PCIC_MAX_MEM_PAGES) {
+ return 1;
+ }
+#endif
+
+ if (!(sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32)) {
+ return 1;
+ }
+
+ addr = 0; /* XXX gcc -Wuninitialized */
+
+ if (bus_space_alloc(sc->sc_memt, sc->sc_mem_start, sc->sc_mem_end,
+ sizepg*PCIC_MEM_PAGESIZE, PCIC_MEM_PAGESIZE,
+ 0 /* boundary */, 0 /* flags */,
+ &addr, &memh)) {
+ return 1;
+ }
+
+ DPRINTF(("pccbb_pcmcia_alloc_mem: addr 0x%lx size 0x%lx, realsize 0x%lx\n",
+ (u_long)addr, (u_long)size, (u_long)sizepg*PCIC_MEM_PAGESIZE));
+
+ pcmhp->memt = sc->sc_memt;
+ pcmhp->memh = memh;
+ pcmhp->addr = addr;
+ pcmhp->size = size;
+ pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE;
+ /* What is mhandle? I feel it is very dirty and it must go trush. */
+ pcmhp->mhandle = 0;
+ /* No offset??? Funny. */
+
+ return 0;
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_mem_free(pcmcia_chipset_handle_t pch,
+* struct pcmcia_mem_handle *pcmhp)
+*
+* This function release the memory space allocated by the fuction
+* pccbb_pcmcia_mem_alloc().
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_mem_free(pch, pcmhp)
+ pcmcia_chipset_handle_t pch;
+ struct pcmcia_mem_handle *pcmhp;
+{
+ bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->realsize);
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_do_mem_map(struct cbb_pcic_handle *ph,
+* int win)
+*
+* This function release the memory space allocated by the fuction
+* pccbb_pcmcia_mem_alloc().
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_do_mem_map(ph, win)
+ struct cbb_pcic_handle *ph;
+ int win;
+{
+ int regbase_win;
+ bus_addr_t phys_addr;
+ bus_addr_t phys_end;
+
+#define PCIC_SMM_START_LOW 0
+#define PCIC_SMM_START_HIGH 1
+#define PCIC_SMM_STOP_LOW 2
+#define PCIC_SMM_STOP_HIGH 3
+#define PCIC_CMA_LOW 4
+#define PCIC_CMA_HIGH 5
+
+ u_int8_t start_low, start_high = 0;
+ u_int8_t stop_low, stop_high;
+ u_int8_t off_low, off_high;
+ u_int8_t mem_window;
+ int reg;
+
+ regbase_win = 0x10 + win*0x08;
+
+ phys_addr = ph->mem[win].addr;
+ phys_end = phys_addr + ph->mem[win].size;
+
+ DPRINTF(("pccbb_pcmcia_do_mem_map: start 0x%lx end 0x%lx off 0x%lx\n",
+ (u_long)phys_addr, (u_long)phys_end, ph->mem[win].offset));
+
+#define PCIC_MEMREG_LSB_SHIFT PCIC_SYSMEM_ADDRX_SHIFT
+#define PCIC_MEMREG_MSB_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 8)
+#define PCIC_MEMREG_WIN_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 12)
+
+ start_low = (phys_addr >> PCIC_MEMREG_LSB_SHIFT) & 0xff; /* bit 19:12 */
+ start_high = ((phys_addr >> PCIC_MEMREG_MSB_SHIFT) & 0x0f) /* bit 23:20 */
+ | PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT; /* bit 7 on */
+ /* bit 31:24, for 32-bit address */
+ mem_window = (phys_addr >> PCIC_MEMREG_WIN_SHIFT) & 0xff; /* bit 31:24 */
+
+ Pcic_write(ph, regbase_win + PCIC_SMM_START_LOW, start_low);
+ Pcic_write(ph, regbase_win + PCIC_SMM_START_HIGH, start_high);
+
+ if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
+ Pcic_write(ph, 0x40 + win, mem_window);
+ }
+
+
+#if 0
+ /* XXX do I want 16 bit all the time? */
+ PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT;
+#endif
+
+
+ stop_low = (phys_end >> PCIC_MEMREG_LSB_SHIFT) & 0xff;
+ stop_high = ((phys_end >> PCIC_MEMREG_MSB_SHIFT) & 0x0f)
+ | PCIC_SYSMEM_ADDRX_STOP_MSB_WAIT2; /* wait 2 cycles */
+ /* XXX Geee, WAIT2!! Crazy!! I must rewrite this routine. */
+
+ Pcic_write(ph, regbase_win + PCIC_SMM_STOP_LOW, stop_low);
+ Pcic_write(ph, regbase_win + PCIC_SMM_STOP_HIGH, stop_high);
+
+ off_low = (ph->mem[win].offset >> PCIC_CARDMEM_ADDRX_SHIFT) & 0xff;
+ off_high = ((ph->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8))
+ & PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK)
+ | ((ph->mem[win].kind == PCMCIA_MEM_ATTR) ?
+ PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0);
+
+ Pcic_write(ph, regbase_win + PCIC_CMA_LOW, off_low);
+ Pcic_write(ph, regbase_win + PCIC_CMA_HIGH, off_high);
+
+ reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
+ reg |= ((1 << win) | PCIC_ADDRWIN_ENABLE_MEMCS16);
+ Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
+
+#if defined CBB_DEBUG
+ {
+ int r1, r2, r3, r4, r5, r6, r7 = 0;
+
+ r1 = Pcic_read(ph, regbase_win + PCIC_SMM_START_LOW);
+ r2 = Pcic_read(ph, regbase_win + PCIC_SMM_START_HIGH);
+ r3 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_LOW);
+ r4 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_HIGH);
+ r5 = Pcic_read(ph, regbase_win + PCIC_CMA_LOW);
+ r6 = Pcic_read(ph, regbase_win + PCIC_CMA_HIGH);
+ if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
+ r7 = Pcic_read(ph, 0x40 + win);
+ }
+
+ DPRINTF(("pccbb_pcmcia_do_mem_map window %d: %02x%02x %02x%02x "
+ "%02x%02x", win, r1, r2, r3, r4, r5, r6));
+ if (ph->sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
+ DPRINTF((" %02x",r7));
+ }
+ DPRINTF(("\n"));
+ }
+#endif
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_mem_map(pcmcia_chipset_handle_t pch, int kind,
+* bus_addr_t card_addr, bus_size_t size,
+* struct pcmcia_mem_handle *pcmhp,
+* bus_addr_t *offsetp, int *windowp)
+*
+* This function maps memory space allocated by the fuction
+* pccbb_pcmcia_mem_alloc().
+**********************************************************************/
+STATIC int
+pccbb_pcmcia_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
+ pcmcia_chipset_handle_t pch;
+ int kind;
+ bus_addr_t card_addr;
+ bus_size_t size;
+ struct pcmcia_mem_handle *pcmhp;
+ bus_addr_t *offsetp;
+ int *windowp;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ bus_addr_t busaddr;
+ long card_offset;
+ int win;
+
+ for (win = 0; win < PCIC_MEM_WINS; ++win) {
+ if ((ph->memalloc & (1 << win)) == 0) {
+ ph->memalloc |= (1 << win);
+ break;
+ }
+ }
+
+ if (win == PCIC_MEM_WINS) {
+ return 1;
+ }
+
+ *windowp = win;
+
+ /* XXX this is pretty gross */
+
+ if (ph->sc->sc_memt != pcmhp->memt) {
+ panic("pccbb_pcmcia_mem_map memt is bogus");
+ }
+
+ busaddr = pcmhp->addr;
+
+ /*
+ * compute the address offset to the pcmcia address space for the
+ * pcic. this is intentionally signed. The masks and shifts below
+ * will cause TRT to happen in the pcic registers. Deal with making
+ * sure the address is aligned, and return the alignment offset.
+ */
+
+ *offsetp = card_addr % PCIC_MEM_PAGESIZE;
+ card_addr -= *offsetp;
+
+ DPRINTF(("pccbb_pcmcia_mem_map window %d bus %lx+%lx+%lx at card addr "
+ "%lx\n", win, (u_long)busaddr, (u_long)*offsetp, (u_long)size,
+ (u_long)card_addr));
+
+ /*
+ * include the offset in the size, and decrement size by one, since
+ * the hw wants start/stop
+ */
+ size += *offsetp - 1;
+
+ card_offset = (((long) card_addr) - ((long) busaddr));
+
+ ph->mem[win].addr = busaddr;
+ ph->mem[win].size = size;
+ ph->mem[win].offset = card_offset;
+ ph->mem[win].kind = kind;
+
+ pccbb_pcmcia_do_mem_map(ph, win);
+
+ return 0;
+}
+
+/**********************************************************************
+* STATIC int pccbb_pcmcia_mem_unmap(pcmcia_chipset_handle_t pch,
+* int window)
+*
+* This function unmaps memory space which mapped by the fuction
+* pccbb_pcmcia_mem_map().
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_mem_unmap(pch, window)
+ pcmcia_chipset_handle_t pch;
+ int window;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ int reg;
+
+ if (window >= PCIC_MEM_WINS) {
+ panic("pccbb_pcmcia_mem_unmap: window out of range");
+ }
+
+ reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
+ reg &= ~(1 << window);
+ Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
+
+ ph->memalloc &= ~(1 << window);
+}
+
+
+
+#if defined PCCBB_PCMCIA_POLL
+struct pccbb_poll_str {
+ void *arg;
+ int (* func) __P((void *));
+ int level;
+ struct cbb_pcic_handle *ph;
+ int count;
+ int num;
+};
+
+static struct pccbb_poll_str pccbb_poll[10];
+static int pccbb_poll_n = 0;
+
+static void pccbb_pcmcia_poll __P((void *arg));
+
+static void
+pccbb_pcmcia_poll(arg)
+ void *arg;
+{
+ struct pccbb_poll_str *poll = arg;
+ struct cbb_pcic_handle *ph = poll->ph;
+ struct pccbb_softc *sc = ph->sc;
+ int s;
+ u_int32_t spsr; /* socket present-state reg */
+
+ timeout(pccbb_pcmcia_poll, arg, hz*2);
+ switch (poll->level) {
+ case IPL_NET:
+ s = splnet();
+ break;
+ case IPL_BIO:
+ s = splbio();
+ break;
+ case IPL_TTY: /* fallthrough */
+ default:
+ s = spltty();
+ break;
+ }
+
+ spsr = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_STAT);
+// printf("pccbb_pcmcia_poll: socket 0x%08x\n", spsr);
+
+#if defined PCCBB_PCMCIA_POLL_ONLY && defined LEVEL2
+ if (!(spsr & 0x40)) /* CINT low */
+#else
+ if (1)
+#endif
+ {
+ if ((*poll->func)(poll->arg) > 0) {
+ ++poll->count;
+// printf("intr: reported from poller, 0x%x\n", spsr);
+#if defined LEVEL2
+ } else {
+ printf("intr: miss! 0x%x\n", spsr);
+#endif
+ }
+ }
+ splx(s);
+}
+#endif /* defined CB_PCMCIA_POLL */
+
+/**********************************************************************
+* STATIC void *pccbb_pcmcia_intr_establish(pcmcia_chipset_handle_t pch,
+* struct pcmcia_function *pf,
+* int ipl,
+* int (*func)(void *),
+* void *arg);
+*
+* This function enables PC-Card interrupt. PCCBB uses PCI interrupt line.
+**********************************************************************/
+STATIC void *
+pccbb_pcmcia_intr_establish(pch, pf, ipl, func, arg)
+ pcmcia_chipset_handle_t pch;
+ struct pcmcia_function *pf;
+ int ipl;
+ int (*func) __P((void *));
+ void *arg;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ struct pccbb_softc *sc = ph->sc;
+ pci_intr_handle_t handle;
+ void *ih;
+
+ if (!(pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) {
+ /* what should I do? */
+ if ((pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) {
+ DPRINTF(("%s does not provide edge nor pulse interrupt\n",
+ sc->sc_dev.dv_xname));
+ return NULL;
+ }
+ /* XXX Noooooo! The interrupt flag must set properly!! */
+ /* dumb pcmcia driver!! */
+ }
+
+ if (pci_intr_map(sc->sc_pc, sc->sc_intrtag, sc->sc_intrpin,
+ sc->sc_intrline, &handle)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ return NULL;
+ }
+
+ DPRINTF(("pccbb_pcmcia_intr_establish: line %d, handle %d\n",
+ sc->sc_intrline, handle));
+
+ if (NULL != (ih = pci_intr_establish(sc->sc_pc, handle, ipl, (void(*)(void*))func, arg)))
+ {
+ u_int32_t cbctrl;
+
+ if ((CB_TI113X == sc->sc_chipset)) {
+ cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL);
+ cbctrl |= PCI113X_CBCTRL_PCI_INTR; /* PCI functional intr req */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl);
+ }
+ }
+#if defined PCCBB_PCMCIA_POLL
+ if (pccbb_poll_n < 10) {
+ pccbb_poll[pccbb_poll_n].arg = arg;
+ pccbb_poll[pccbb_poll_n].func = func;
+ pccbb_poll[pccbb_poll_n].level = ipl;
+ pccbb_poll[pccbb_poll_n].count = 0;
+ pccbb_poll[pccbb_poll_n].num = pccbb_poll_n;
+ pccbb_poll[pccbb_poll_n].ph = ph;
+ timeout(pccbb_pcmcia_poll, &pccbb_poll[pccbb_poll_n++], hz*2);
+ printf("polling set\n");
+ }
+#endif
+#if defined SHOW_REGS
+ cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt, sc->sc_base_memh);
+#endif
+
+ return ih;
+}
+
+/**********************************************************************
+* STATIC void pccbb_pcmcia_intr_disestablish(pcmcia_chipset_handle_t pch,
+* void *ih)
+*
+* This function disables PC-Card interrupt.
+**********************************************************************/
+STATIC void
+pccbb_pcmcia_intr_disestablish(pch, ih)
+ pcmcia_chipset_handle_t pch;
+ void *ih;
+{
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)pch;
+ struct pccbb_softc *sc = ph->sc;
+
+ pci_intr_disestablish(sc->sc_pc, ih);
+}
+
+static int
+pccbb_pcmcia_submatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct pcmciabus_attach_args *paa = aux;
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)paa->pch;
+
+ if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != PCMCIABUSCF_CONTROLLER_DEFAULT
+ && cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) {
+ return 0;
+ }
+
+ if ((cf->cf_loc[PCMCIABUSCF_CONTROLLER] == PCMCIABUSCF_CONTROLLER_DEFAULT)
+ || cf->cf_loc[PCMCIABUSCF_CONTROLLER] != ph->sock) {
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+ }
+
+ return 0;
+}
+
+static int
+pccbb_pcmcia_print(arg, pnp)
+ void *arg;
+ const char *pnp;
+{
+ struct pcmciabus_attach_args *paa = arg;
+ struct cbb_pcic_handle *ph = (struct cbb_pcic_handle *)paa->pch;
+
+ if (pnp) {
+ printf("pcmcia at %s", pnp);
+ }
+
+ printf(" slot %d", ph->sock);
+
+ return UNCONF;
+}
+STATIC int
+cbbprint(aux, pcic)
+ void *aux;
+ const char *pcic;
+{
+/*
+ struct cbslot_attach_args *cba = aux;
+
+ if (cba->cba_slot >= 0) {
+ printf(" slot %d", cba->cba_slot);
+ }
+*/
+ return UNCONF;
+}
diff --git a/sys/pci/pccbbreg.h b/sys/pci/pccbbreg.h
new file mode 100644
index 000000000000..9dad13ae8fcb
--- /dev/null
+++ b/sys/pci/pccbbreg.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1999 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.
+ */
+
+/* $Id: pccbbreg.h,v 1.4 1999/08/02 01:35:50 kanaoka Exp $ */
+/* $FreeBSD$ */
+
+#ifndef _DEV_PCI_PCCBBREG_H_
+#define _DEV_PCI_PCCBBREG_H_
+
+#define PCI_SOCKBASE 0x10 /* Socket Base Address Register */
+#define PCI_BUSNUM 0x18 /* latency timer, Subordinate bus number */
+#define PCI_BCR_INTR 0x3C /* intr line, intr pin, bridge control regs */
+#define PCI_LEGACY 0x44 /* legacy IO register address (32 bits) */
+#define PCI_CBCTRL 0x90 /* Retry status, Card ctrl, Device ctrl */
+
+#define PCI_CLASS_INTERFACE_MASK 0xffffff00
+#define PCI_CLASS_INTERFACE_YENTA 0x06070000
+
+#define PCI_BHLC_REG 0x0c
+
+#define PCI_LATTIMER_SHIFT 8
+#define PCI_LATTIMER_MASK 0xff
+#define PCI_LATTIMER(bhlcr) \
+ (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK)
+
+
+#define PCI_SOCKBASE 0x10 /* Socket Base Address Register */
+#define PCI_BUSNUM 0x18 /* latency timer, Subordinate bus number */
+#define PCI_BCR_INTR 0x3C /* intr line, intr pin, bridge control regs */
+#define PCI_LEGACY 0x44 /* legacy IO register address (32 bits) */
+#define PCI_CBCTRL 0x90 /* Retry status, Card ctrl, Device ctrl */
+#define CB_SOCKET_EVENT 0x00 /* offset of cardbus socket event reg */
+#define CB_SOCKET_MASK 0x04 /* offset of cardbus socket mask register */
+#define CB_SOCKET_STAT 0x08 /* offset of cardbus socket present-state */
+#define CB_SOCKET_FORCE 0x0c /* offset of cardbus socket force event */
+#define CB_SOCKET_CTRL 0x10 /* offset of cardbus socket control reg */
+
+
+/* CardBus latency timer, Subordinate bus no, CardBus bus no and PCI bus no */
+#define PCI_CB_LSCP_REG 0x18
+/* CardBus memory and io windows */
+#define PCI_CB_MEMBASE0 0x1c
+#define PCI_CB_MEMLIMIT0 0x20
+#define PCI_CB_MEMBASE1 0x24
+#define PCI_CB_MEMLIMIT1 0x28
+#define PCI_CB_IOBASE0 0x2c
+#define PCI_CB_IOLIMIT0 0x30
+#define PCI_CB_IOBASE1 0x34
+#define PCI_CB_IOLIMIT1 0x38
+
+/* PCI_CB_LSCP_REG */
+#define PCI_CB_LATENCY_SHIFT 24
+#define PCI_CB_LATENCY_MASK 0xff
+#define PCI_CB_LATENCY(x) (((x) >> PCI_CB_LATENCY_SHIFT) & PCI_CB_LATENCY_MASK)
+
+
+
+/* PCI_BCR_INTR bits for generic PCI-CardBus bridge */
+#define CB_BCR_INTR_IREQ_ENABLE 0x0800000
+#define CB_BCR_WRITE_POST_ENABLE 0x4000000
+
+/* PCI_CBCTRL bits for TI PCI113X */
+#define PCI113X_CBCTRL_INT_SERIAL 0x040000
+#define PCI113X_CBCTRL_INT_ISA 0x020000
+#define PCI113X_CBCTRL_INT_MASK 0x060000
+#define PCI113X_CBCTRL_RIENB 0x8000 /* Ring indicate output enable */
+#define PCI113X_CBCTRL_ZVENAB 0x4000 /* ZV mode enable */
+#define PCI113X_CBCTRL_PCI_IRQ_ENA 0x2000 /* PCI intr enable (funct and CSC) */
+#define PCI113X_CBCTRL_PCI_INTR 0x1000 /* PCI functional intr req */
+#define PCI113X_CBCTRL_PCI_CSC 0x0800 /* CSC intr route to PCI */
+#define PCI113X_CBCTRL_PCI_CSC_D 0x0400 /* unknown */
+#define PCI113X_CBCTRL_SPK_ENA 0x0200 /* Speaker enable */
+#define PCI113X_CBCTRL_INTR_DET 0x0100 /* functional interrupt detect */
+
+/* PCI_CBCTRL bits for TI PCI12XX */
+#define PCI12XX_CBCTRL_INT_SERIAL 0x040000
+#define PCI12XX_CBCTRL_INT_ISA 0x020000
+#define PCI12XX_CBCTRL_INT_PCI 0x000000
+#define PCI12XX_CBCTRL_INT_MASK 0x060000
+#define PCI12XX_CBCTRL_RIENB 0x8000 /* Ring indicate output enable */
+#define PCI12XX_CBCTRL_ZVENAB 0x4000 /* ZV mode enable */
+#define PCI12XX_CBCTRL_AUD2MUX 0x0400 /* unknown */
+#define PCI12XX_CBCTRL_SPK_ENA 0x0200 /* Speaker enable */
+#define PCI12XX_CBCTRL_INTR_DET 0x0100 /* functional interrupt detect */
+
+/* PCI_BCR_INTR additional bit for RF5C46[567] */
+#define CB_BCRI_RL_3E0_ENA 0x08000000
+#define CB_BCRI_RL_3E2_ENA 0x10000000
+
+/*
+ * Special resister definition for Toshiba ToPIC95/97
+ * These values are borrowed from pcmcia-cs/Linux.
+ */
+#define TOPIC_SOCKET_CTRL 0x90
+# define TOPIC_SOCKET_CTRL_SCR_IRQSEL 0x00000001 /* PCI intr */
+
+#define TOPIC_SLOT_CTRL 0xa0
+# define TOPIC_SLOT_CTRL_SLOTON 0x00000080
+# define TOPIC_SLOT_CTRL_SLOTEN 0x00000040
+# define TOPIC_SLOT_CTRL_ID_LOCK 0x00000020
+# define TOPIC_SLOT_CTRL_ID_WP 0x00000010
+# define TOPIC_SLOT_CTRL_PORT_MASK 0x0000000c
+# define TOPIC_SLOT_CTRL_PORT_SHIFT 2
+# define TOPIC_SLOT_CTRL_OSF_MASK 0x00000003
+# define TOPIC_SLOT_CTRL_OSF_SHIFT 0
+
+# define TOPIC_SLOT_CTRL_INTB 0x00002000
+# define TOPIC_SLOT_CTRL_INTA 0x00001000
+# define TOPIC_SLOT_CTRL_INT_MASK 0x00003000
+# define TOPIC_SLOT_CTRL_CLOCK_MASK 0x00000c00
+# define TOPIC_SLOT_CTRL_CLOCK_2 0x00000800 /* PCI Clock/2 */
+# define TOPIC_SLOT_CTRL_CLOCK_1 0x00000400 /* PCI Clock */
+# define TOPIC_SLOT_CTRL_CLOCK_0 0x00000000 /* no clock */
+
+# define TOPIC_SLOT_CTRL_CARDBUS 0x80000000
+# define TOPIC_SLOT_CTRL_VS1 0x04000000
+# define TOPIC_SLOT_CTRL_VS2 0x02000000
+# define TOPIC_SLOT_CTRL_SWDETECT 0x01000000
+
+#define TOPIC_REG_CTRL 0x00a4
+# define TOPIC_REG_CTRL_RESUME_RESET 0x80000000
+# define TOPIC_REG_CTRL_REMOVE_RESET 0x40000000
+# define TOPIC97_REG_CTRL_CLKRUN_ENA 0x20000000
+# define TOPIC97_REG_CTRL_TESTMODE 0x10000000
+# define TOPIC97_REG_CTRL_IOPLUP 0x08000000
+# define TOPIC_REG_CTRL_BUFOFF_PWROFF 0x02000000
+# define TOPIC_REG_CTRL_BUFOFF_SIGOFF 0x01000000
+# define TOPIC97_REG_CTRL_CB_DEV_MASK 0x0000f800
+# define TOPIC97_REG_CTRL_CB_DEV_SHIFT 11
+# define TOPIC97_REG_CTRL_RI_DISABLE 0x00000004
+# define TOPIC97_REG_CTRL_CAUDIO_OFF 0x00000002
+# define TOPIC_REG_CTRL_CAUDIO_INVERT 0x00000001
+
+
+
+/* socket event register (CB_SOCKET_EVENT) elements */
+#define CB_SOCKET_EVENT_CSTS 0x01 /* CARDSTS event occurs */
+#define CB_SOCKET_EVENT_CD 0x06 /* CD event occurs */
+#define CB_SOCKET_EVENT_CD1 0x02 /* CD1 event occurs */
+#define CB_SOCKET_EVENT_CD2 0x04 /* CD2 event occurs */
+#define CB_SOCKET_EVENT_POWER 0x08 /* Power cycle event occurs */
+
+
+/* socket mask register (CB_SOCKET_MASK) elements */
+#define CB_SOCKET_MASK_CSTS 0x01 /* CARDSTS event mask */
+#define CB_SOCKET_MASK_CD 0x06 /* CD event mask */
+#define CB_SOCKET_MASK_POWER 0x08 /* Power cycle event mask */
+
+/* socket present-state register (CB_SOCKET_STAT) elements */
+#define CB_SOCKET_STAT_CARDSTS 0x01 /* card status change bit */
+#define CB_SOCKET_STAT_CD1 0x02 /* card detect 1 */
+#define CB_SOCKET_STAT_CD2 0x04 /* card detect 2 */
+#define CB_SOCKET_STAT_CD 0x06 /* card detect 1 and 2 */
+#define CB_SOCKET_STAT_PWRCYCLE 0x08 /* power cycle */
+#define CB_SOCKET_STAT_16BIT 0x010 /* 16-bit card */
+#define CB_SOCKET_STAT_CB 0x020 /* cardbus card */
+#define CB_SOCKET_STAT_IREQ 0x040 /* READY(~IREQ)//(~CINT) bit */
+#define CB_SOCKET_STAT_NOTCARD 0x080 /* Inserted card is unrecognisable */
+#define CB_SOCKET_STAT_DATALOST 0x0100 /* data lost */
+#define CB_SOCKET_STAT_BADVCC 0x0200 /* Bad Vcc Request */
+#define CB_SOCKET_STAT_5VCARD 0x0400 /* 5 V Card */
+#define CB_SOCKET_STAT_3VCARD 0x0800 /* 3.3 V Card */
+#define CB_SOCKET_STAT_XVCARD 0x01000 /* X.X V Card */
+#define CB_SOCKET_STAT_YVCARD 0x02000 /* Y.Y V Card */
+#define CB_SOCKET_STAT_5VSOCK 0x10000000 /* 5 V Socket */
+#define CB_SOCKET_STAT_3VSOCK 0x20000000 /* 3.3 V Socket */
+#define CB_SOCKET_STAT_XVSOCK 0x20000000 /* X.X V Socket */
+#define CB_SOCKET_STAT_YVSOCK 0x20000000 /* Y.Y V Socket */
+
+/* socket force event register (CB_SOCKET_FORCE) elements */
+#define CB_SOCKET_FORCE_BADVCC 0x0200 /* Bad Vcc Request */
+
+
+/* socket control register (CB_SOCKET_CTRL) elements */
+#define CB_SOCKET_CTRL_VPPMASK 0x07
+#define CB_SOCKET_CTRL_VPP_OFF 0x00
+#define CB_SOCKET_CTRL_VPP_12V 0x01
+#define CB_SOCKET_CTRL_VPP_5V 0x02
+#define CB_SOCKET_CTRL_VPP_3V 0x03
+#define CB_SOCKET_CTRL_VPP_XV 0x04
+#define CB_SOCKET_CTRL_VPP_YV 0x05
+
+#define CB_SOCKET_CTRL_VCCMASK 0x070
+#define CB_SOCKET_CTRL_VCC_OFF 0x000
+#define CB_SOCKET_CTRL_VCC_5V 0x020
+#define CB_SOCKET_CTRL_VCC_3V 0x030
+#define CB_SOCKET_CTRL_VCC_XV 0x040
+#define CB_SOCKET_CTRL_VCC_YV 0x050
+
+#define CB_SOCKET_CTRL_STOPCLK 0x080
+
+
+
+/* PCCARD VOLTAGE */
+#define PCCARD_VCC_UKN 0x00 /* unknown */
+#define PCCARD_VCC_5V 0x01
+#define PCCARD_VCC_3V 0x02
+#define PCCARD_VCC_XV 0x04
+#define PCCARD_VCC_YV 0x08
+
+
+#endif /* _DEV_PCI_PCCBBREG_H_ */
diff --git a/sys/pci/pccbbvar.h b/sys/pci/pccbbvar.h
new file mode 100644
index 000000000000..20a3ea7ab125
--- /dev/null
+++ b/sys/pci/pccbbvar.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1999 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.
+ */
+/* $FreeBSD$ */
+
+struct pccbb_softc;
+
+struct cbb_pcic_handle {
+ struct pccbb_softc *sc;
+ bus_space_tag_t ph_iot;
+ bus_space_handle_t ph_ioh;
+ u_int8_t (* ph_read) __P((struct cbb_pcic_handle *, int));
+ void (* ph_write) __P((struct cbb_pcic_handle *, int, u_int8_t));
+ int sock;
+
+ int vendor;
+ int flags;
+ int memalloc;
+ struct {
+ bus_addr_t addr;
+ bus_size_t size;
+ long offset;
+ int kind;
+ } mem[PCIC_MEM_WINS];
+ int ioalloc;
+ struct {
+ bus_addr_t addr;
+ bus_size_t size;
+ int width;
+ } io[PCIC_IO_WINS];
+ int ih_irq;
+ struct device *pcmcia;
+
+ int shutdown;
+ struct proc *event_thread;
+ SIMPLEQ_HEAD(, pcic_event) events;
+};
+
+struct pccbb_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+
+ bus_space_tag_t sc_base_memt;
+ bus_space_handle_t sc_base_memh;
+ void *sc_ih; /* interrupt handler */
+ int sc_intrline; /* interrupt line */
+ pcitag_t sc_intrtag; /* copy of pa->pa_intrtag */
+ pci_intr_pin_t sc_intrpin; /* copy of pa->pa_intrpin */
+ int sc_function;
+ u_int32_t sc_flags;
+#define CBB_CARDEXIST 0x01
+#define CBB_CARDSTATUS_BUSY 0x01000000
+ pci_chipset_tag_t sc_pc;
+ pcitag_t sc_tag;
+ int sc_chipset; /* chipset id */
+
+ bus_addr_t sc_mem_start; /* CardBus/PCMCIA memory start */
+ bus_addr_t sc_mem_end; /* CardBus/PCMCIA memory end */
+
+ /* CardBus stuff */
+ struct cardbus_softc *sc_csc;
+ struct device *sc_cbdev; /* Device which attached to the slot XXX mfc */
+ /* pcmcia stuff */
+ struct cbb_pcic_handle sc_pcmcia_h;
+ pcmcia_chipset_tag_t sc_pct;
+ int sc_pcmcia_flags;
+#define PCCBB_PCMCIA_IO_RELOC 0x01 /* IO address relocatable stuff exists */
+#define PCCBB_PCMCIA_MEM_32 0x02 /* 32-bit memory address ready */
+ /* kthread staff */
+ int sc_queued;
+ struct proc *event_thread;
+ SIMPLEQ_HEAD(, pcic_event) events;
+};