summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/i386/conf/GENERIC9
-rw-r--r--sys/arch/i386/conf/files.i38610
-rw-r--r--sys/arch/i386/i386/machdep.c25
-rw-r--r--sys/arch/i386/i386/rbus_machdep.c163
-rw-r--r--sys/arch/i386/include/bus.h5
-rw-r--r--sys/arch/i386/include/rbus_machdep.h53
-rw-r--r--sys/conf/files9
-rw-r--r--sys/dev/cardbus/cardbus.c934
-rw-r--r--sys/dev/cardbus/cardbus_exrom.c183
-rw-r--r--sys/dev/cardbus/cardbus_exrom.h73
-rw-r--r--sys/dev/cardbus/cardbus_map.c442
-rw-r--r--sys/dev/cardbus/cardbusvar.h450
-rw-r--r--sys/dev/cardbus/cardslot.c439
-rw-r--r--sys/dev/cardbus/cardslotvar.h125
-rw-r--r--sys/dev/cardbus/files.cardbus51
-rw-r--r--sys/dev/cardbus/if_xl_cardbus.c426
-rw-r--r--sys/dev/cardbus/rbus.c387
-rw-r--r--sys/dev/cardbus/rbus.h166
-rw-r--r--sys/dev/ic/i82365.c157
-rw-r--r--sys/dev/ic/i82365var.h43
-rw-r--r--sys/dev/ic/xl.c (renamed from sys/dev/pci/if_xl.c)239
-rw-r--r--sys/dev/ic/xlreg.h (renamed from sys/dev/pci/if_xlreg.h)14
-rw-r--r--sys/dev/isa/i82365_isasubr.c10
-rw-r--r--sys/dev/pci/files.pci13
-rw-r--r--sys/dev/pci/if_xl_pci.c225
-rw-r--r--sys/dev/pci/pccbb.c3100
-rw-r--r--sys/dev/pci/pccbbreg.h225
-rw-r--r--sys/dev/pci/pccbbvar.h174
-rw-r--r--sys/dev/pcmcia/files.pcmcia4
-rw-r--r--sys/dev/pcmcia/pcmcia.c8
-rw-r--r--sys/dev/pcmcia/pcmciachip.h13
-rw-r--r--sys/kern/Makefile6
32 files changed, 7897 insertions, 284 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 8e2b6c63234..d1d635cbfa4 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.174 2000/04/07 22:25:43 aaron Exp $
+# $OpenBSD: GENERIC,v 1.175 2000/04/08 05:50:49 aaron Exp $
# $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $
#
# GENERIC -- everything that's currently supported
@@ -64,6 +64,12 @@ pcic2 at isa? port 0x3e4 iomem 0xe0000 iosiz 0x4000
# PCMCIA bus support
pcmcia* at pcic? controller ? socket ?
+# CardBus bus support
+#cardbus* at cardslot?
+#pcmcia* at cardslot?
+#cbb* at pci? dev ? function ?
+#cardslot* at cbb?
+
# PCI USB Controllers
#uhci* at pci? # Universal Host Controller (Intel)
#ohci* at pci? # Open Host Controller
@@ -260,6 +266,7 @@ sm* at pcmcia? function ? # PCMCIA based sm ethernet
xe* at pcmcia? function ? # Xircom ethernet
fpa* at pci? dev ? function ? # DEC DEFPA FDDI
xl* at pci? dev ? function ? # 3c9xx ethernet
+#xl* at cardbus? dev ? function ? # 3c575 ethernet
rl* at pci? dev ? function ? # RealTek 81[23]9 ethernet
tx* at pci? dev ? function ? # SMC 83C170 EPIC ethernet
tl* at pci? dev ? function ? # Compaq Thunderlan ethernet
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 809930770b0..778c72658c1 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.63 2000/03/26 22:38:32 mickey Exp $
+# $OpenBSD: files.i386,v 1.64 2000/04/08 05:50:49 aaron Exp $
# $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $
#
# new style config file for i386 architecture
@@ -255,6 +255,12 @@ file arch/i386/i386/apmcall.S apm
file arch/i386/i386/bios32.c bios32
+#
+# CARDBUS
+#
+include "dev/cardbus/files.cardbus"
+file arch/i386/i386/rbus_machdep.c cardbus
+
# XXXX pcic here because it needs to be late. The catch: pcic needs
# to be late, so devices which attach to it are attached late. But it
# needs to be before its isa and pci attachments. This answer is
@@ -264,7 +270,7 @@ file arch/i386/i386/bios32.c bios32
# XXX this needs to be done very late, so it's done here. This feels
# like a kludge, but it might be for the best.
-device pcic {[controller = -1], [socket = -1]}
+device pcic: pcmciabus
file dev/ic/i82365.c pcic
# PCIC pcmcia controller on ISA bus.
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 7835c4c89d5..6dc18b614a0 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.128 2000/03/23 09:59:54 art Exp $ */
+/* $OpenBSD: machdep.c,v 1.129 2000/04/08 05:50:50 aaron Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -2387,6 +2387,29 @@ bus_space_map(t, bpa, size, cacheable, bshp)
}
int
+_bus_space_map(t, bpa, size, cacheable, bshp)
+ bus_space_tag_t t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int cacheable;
+ bus_space_handle_t *bshp;
+{
+ /*
+ * For I/O space, that's all she wrote.
+ */
+ if (t == I386_BUS_SPACE_IO) {
+ *bshp = bpa;
+ return (0);
+ }
+
+ /*
+ * For memory space, map the bus physical address to
+ * a kernel virtual address.
+ */
+ return (bus_mem_add_mapping(bpa, size, cacheable, bshp));
+}
+
+int
bus_space_alloc(t, rstart, rend, size, alignment, boundary, cacheable,
bpap, bshp)
bus_space_tag_t t;
diff --git a/sys/arch/i386/i386/rbus_machdep.c b/sys/arch/i386/i386/rbus_machdep.c
new file mode 100644
index 00000000000..d38072ea295
--- /dev/null
+++ b/sys/arch/i386/i386/rbus_machdep.c
@@ -0,0 +1,163 @@
+/* $OpenBSD: rbus_machdep.c,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
+/* $NetBSD: rbus_machdep.c,v 1.2 1999/10/15 06:43:06 haya Exp $ */
+
+/*
+ * 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: rbus_machdep.c,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <dev/cardbus/rbus.h>
+
+#include <sys/device.h>
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <dev/pci/pcivar.h>
+
+
+
+/**********************************************************************
+ * void _bus_space_unmap(bus_space_tag bst, bus_space_handle bsh,
+ * bus_size_t size, bus_addr_t *adrp)
+ *
+ * This function unmaps memory- or io-space mapped by the function
+ * _bus_space_map(). This function works nearly as same as
+ * bus_space_map(), but this function does not ask kernel
+ * built-in extents and returns physical address of the bus space,
+ * for the convenience of the extra extent manager.
+ *
+ * I suppose this function should be in arch/i386/i386/machdep.c,
+ * but it is not.
+ **********************************************************************/
+void
+_bus_space_unmap(t, bsh, size, adrp)
+ bus_space_tag_t t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+ bus_addr_t *adrp;
+{
+ u_long va, endva;
+ bus_addr_t bpa;
+
+ /*
+ * Find the correct extent and bus physical address.
+ */
+ if (t == I386_BUS_SPACE_IO) {
+ bpa = bsh;
+ } else if (t == I386_BUS_SPACE_MEM) {
+ if (bsh >= atdevbase && (bsh + size) <= (atdevbase + IOM_SIZE)) {
+ bpa = (bus_addr_t)ISA_PHYSADDR(bsh);
+ } else {
+
+ va = i386_trunc_page(bsh);
+ endva = i386_round_page(bsh + size);
+
+#ifdef DIAGNOSTIC
+ if (endva <= va) {
+ panic("_i386_memio_unmap: overflow");
+ }
+#endif
+
+#if __NetBSD_Version__ > 104050000
+ if (pmap_extract(pmap_kernel(), va, &bpa) == FALSE) {
+ panic("_i386_memio_unmap:i386/rbus_machdep.c wrong virtual address");
+ }
+ bpa += (bsh & PGOFSET);
+#else
+ bpa = pmap_extract(pmap_kernel(), va) + (bsh & PGOFSET);
+#endif
+
+ /*
+ * Free the kernel virtual mapping.
+ */
+ uvm_km_free(kernel_map, va, endva - va);
+ }
+ } else {
+ panic("_i386_memio_unmap: bad bus space tag");
+ }
+
+ if (adrp != NULL) {
+ *adrp = bpa;
+ }
+}
+
+
+
+
+/**********************************************************************
+ * rbus_tag_t rbus_fakeparent_mem(struct pci_attach_args *pa)
+ *
+ * This function allocates a memory space from 1 GB to 1.25 GB.
+ **********************************************************************/
+rbus_tag_t
+rbus_pccbb_parent_mem(pa)
+ struct pci_attach_args *pa;
+{
+ bus_addr_t start = 0x40000000; /* 1 GB */
+ bus_size_t size = 0x08000000; /* 128 MB */
+ bus_space_handle_t memh; /* fake */
+
+ start += pa->pa_function * size;
+
+ bus_space_map(pa->pa_memt, start, size, 0, &memh);
+
+ return rbus_new_root_delegate(pa->pa_memt, start, size, 0);
+}
+
+
+/**********************************************************************
+ * rbus_tag_t rbus_pccbb_parent_io(struct pci_attach_args *pa)
+ **********************************************************************/
+rbus_tag_t
+rbus_pccbb_parent_io(pa)
+ struct pci_attach_args *pa;
+{
+ bus_addr_t start = 0x2000;
+ bus_size_t size = 0x0800;
+ bus_space_handle_t ioh;
+
+ start += pa->pa_function * size;
+
+ bus_space_map(pa->pa_iot, start, size, 0, &ioh);
+
+ return rbus_new_root_delegate(pa->pa_iot, start, size, 0);
+}
diff --git a/sys/arch/i386/include/bus.h b/sys/arch/i386/include/bus.h
index 0ee26b6ad18..99df8f1dd0a 100644
--- a/sys/arch/i386/include/bus.h
+++ b/sys/arch/i386/include/bus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus.h,v 1.19 2000/03/15 03:56:49 todd Exp $ */
+/* $OpenBSD: bus.h,v 1.20 2000/04/08 05:50:50 aaron Exp $ */
/* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */
/*-
@@ -95,6 +95,9 @@ typedef u_long bus_space_handle_t;
int bus_space_map __P((bus_space_tag_t t, bus_addr_t addr,
bus_size_t size, int cacheable, bus_space_handle_t *bshp));
+/* like bus_space_map(), but without extent map checking/allocation */
+int _bus_space_map __P((bus_space_tag_t t, bus_addr_t addr,
+ bus_size_t size, int cacheable, bus_space_handle_t *bshp));
void bus_space_unmap __P((bus_space_tag_t t, bus_space_handle_t bsh,
bus_size_t size));
int bus_space_subregion __P((bus_space_tag_t t, bus_space_handle_t bsh,
diff --git a/sys/arch/i386/include/rbus_machdep.h b/sys/arch/i386/include/rbus_machdep.h
new file mode 100644
index 00000000000..7bb855d1589
--- /dev/null
+++ b/sys/arch/i386/include/rbus_machdep.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: rbus_machdep.h,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
+/* $NetBSD: rbus_machdep.h,v 1.2 1999/10/15 06:43:05 haya Exp $ */
+
+/*
+ * 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.
+ */
+
+
+#if !defined _ARCH_I386_I386_RBUS_MACHDEP_H_
+#define _ARCH_I386_I386_RBUS_MACHDEP_H_
+
+struct pci_attach_args; /* XXX */
+
+void _bus_space_unmap __P((bus_space_tag_t, bus_space_handle_t,
+ bus_size_t, bus_addr_t *));
+
+#define md_space_map(bt, physaddr, size, flags, bshp) \
+ _bus_space_map((bt), (physaddr), (size), (flags), (bshp))
+
+#define md_space_unmap(bt, bsh, size, adrp) \
+ _bus_space_unmap((bt), (bsh), (size), (adrp))
+
+
+rbus_tag_t rbus_pccbb_parent_io __P((struct pci_attach_args *pa));
+rbus_tag_t rbus_pccbb_parent_mem __P((struct pci_attach_args *pa));
+
+#endif /* _ARCH_I386_I386_RBUS_MACHDEP_H_ */
diff --git a/sys/conf/files b/sys/conf/files
index 2bad87b3bd6..6715a328cd8 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.156 2000/04/03 01:02:00 mickey Exp $
+# $OpenBSD: files,v 1.157 2000/04/08 05:50:50 aaron Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -116,6 +116,9 @@ file dev/ic/rlnsubr.c rln
device le: ether, ifnet, ifmedia
file dev/ic/am7990.c le
+device xl: ether, ifnet, ifmedia, mii
+file dev/ic/xl.c xl
+
# SMC 91Cxx Ethernet Controller
device sm: ether, ifnet, ifmedia
file dev/ic/smc91cxx.c sm
@@ -170,9 +173,11 @@ file dev/ic/font_8x16.c vgafb & (vgafb_isa | vgafb_pci)
define isabus { } # ISA attachment
define eisabus { } # EISA attachment
define pcibus {[bus = -1]} # PCI attachment
-define pcmciabus { } # PCMCIA attachment
define tcbus { } # TurboChannel attachment
define usbus { } # USB attachment
+define pcmciabus { [controller = -1], [socket = -1]} # PCMCIA attachment
+define cbbus {[slot = -1]} # CardBus attachment
+define pcmciaslot {[slot = -1]} # PCMCIA slot itself
# UHCI USB controller
device uhci: usbus
diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c
new file mode 100644
index 00000000000..20546bf90de
--- /dev/null
+++ b/sys/dev/cardbus/cardbus.c
@@ -0,0 +1,934 @@
+/* $OpenBSD: cardbus.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardbus.c,v 1.24 2000/04/02 19:11:37 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1997, 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+
+#include <dev/cardbus/cardbusvar.h>
+#include <dev/cardbus/cardbusdevs.h>
+
+#include <dev/cardbus/cardbus_exrom.h>
+
+#include <dev/pci/pcivar.h> /* XXX */
+#include <dev/pci/pcireg.h> /* XXX */
+
+#include <dev/pcmcia/pcmciareg.h>
+
+#if defined CARDBUS_DEBUG
+#define STATIC
+#define DPRINTF(a) printf a
+#else
+#define STATIC static
+#define DPRINTF(a)
+#endif
+
+extern int cold;
+
+STATIC void cardbusattach __P((struct device *, struct device *, void *));
+/* STATIC int cardbusprint __P((void *, const char *)); */
+int cardbus_attach_card __P((struct cardbus_softc *));
+
+STATIC int cardbusmatch __P((struct device *, void *, void *));
+static int cardbussubmatch __P((struct device *, void *, void *));
+static int cardbusprint __P((void *, const char *));
+
+typedef void (*tuple_decode_func)(u_int8_t*, int, void*);
+
+static int decode_tuples __P((u_int8_t *, int, tuple_decode_func, void*));
+#ifdef CARDBUS_DEBUG
+static void print_tuple __P((u_int8_t*, int, void*));
+#endif
+
+static int cardbus_read_tuples __P((struct cardbus_attach_args *,
+ cardbusreg_t, u_int8_t *, size_t));
+
+static void enable_function __P((struct cardbus_softc *, int, int));
+static void disable_function __P((struct cardbus_softc *, int));
+
+
+struct cfattach cardbus_ca = {
+ sizeof(struct cardbus_softc), cardbusmatch, cardbusattach
+};
+
+#ifndef __NetBSD_Version__
+struct cfdriver cardbus_cd = {
+ NULL, "cardbus", DV_DULL
+};
+#endif
+
+
+STATIC int
+cardbusmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct cbslot_attach_args *cba = aux;
+
+ if (strcmp(cba->cba_busname, cf->cf_driver->cd_name)) {
+ DPRINTF(("cardbusmatch: busname differs %s <=> %s\n",
+ cba->cba_busname, cf->cf_driver->cd_name));
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+STATIC void
+cardbusattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct cardbus_softc *sc = (void *)self;
+ struct cbslot_attach_args *cba = aux;
+ int cdstatus;
+
+ sc->sc_bus = cba->cba_bus;
+ sc->sc_device = 0;
+ sc->sc_intrline = cba->cba_intrline;
+ sc->sc_cacheline = cba->cba_cacheline;
+ sc->sc_lattimer = cba->cba_lattimer;
+
+ printf(": bus %d device %d", sc->sc_bus, sc->sc_device);
+ printf(" cacheline 0x%x, lattimer 0x%x\n", sc->sc_cacheline,sc->sc_lattimer);
+
+ sc->sc_iot = cba->cba_iot; /* CardBus I/O space tag */
+ sc->sc_memt = cba->cba_memt; /* CardBus MEM space tag */
+ sc->sc_dmat = cba->cba_dmat; /* DMA tag */
+ sc->sc_cc = cba->cba_cc;
+ sc->sc_cf = cba->cba_cf;
+
+#if rbus
+ sc->sc_rbus_iot = cba->cba_rbus_iot;
+ sc->sc_rbus_memt = cba->cba_rbus_memt;
+#endif
+
+ sc->sc_funcs = NULL;
+
+ cdstatus = 0;
+}
+
+static int
+cardbus_read_tuples(ca, cis_ptr, tuples, len)
+ struct cardbus_attach_args *ca;
+ cardbusreg_t cis_ptr;
+ u_int8_t *tuples;
+ size_t len;
+{
+ struct cardbus_softc *sc = ca->ca_ct->ct_sc;
+ cardbus_chipset_tag_t cc = ca->ca_ct->ct_cc;
+ cardbus_function_tag_t cf = ca->ca_ct->ct_cf;
+ cardbustag_t tag = ca->ca_tag;
+ cardbusreg_t command;
+ int found = 0;
+
+ int i, j;
+ int cardbus_space = cis_ptr & CARDBUS_CIS_ASIMASK;
+ bus_space_handle_t bar_memh;
+ bus_size_t bar_size;
+ bus_addr_t bar_addr;
+
+ int reg;
+
+ memset(tuples, 0, len);
+
+ cis_ptr = cis_ptr & CARDBUS_CIS_ADDRMASK;
+
+ switch(cardbus_space) {
+ case CARDBUS_CIS_ASI_TUPLE:
+ DPRINTF(("%s: reading CIS data from configuration space\n",
+ sc->sc_dev.dv_xname));
+ for (i = cis_ptr, j = 0; i < 0xff; i += 4) {
+ u_int32_t e = (cf->cardbus_conf_read)(cc, tag, i);
+ tuples[j] = 0xff & e;
+ e >>= 8;
+ tuples[j + 1] = 0xff & e;
+ e >>= 8;
+ tuples[j + 2] = 0xff & e;
+ e >>= 8;
+ tuples[j + 3] = 0xff & e;
+ j += 4;
+ }
+ found++;
+ break;
+
+ case CARDBUS_CIS_ASI_BAR0:
+ case CARDBUS_CIS_ASI_BAR1:
+ case CARDBUS_CIS_ASI_BAR2:
+ case CARDBUS_CIS_ASI_BAR3:
+ case CARDBUS_CIS_ASI_BAR4:
+ case CARDBUS_CIS_ASI_BAR5:
+ case CARDBUS_CIS_ASI_ROM:
+ if(cardbus_space == CARDBUS_CIS_ASI_ROM) {
+ reg = CARDBUS_ROM_REG;
+ DPRINTF(("%s: reading CIS data from ROM\n",
+ sc->sc_dev.dv_xname));
+ } else {
+ reg = CARDBUS_BASE0_REG + (cardbus_space - 1) * 4;
+ DPRINTF(("%s: reading CIS data from BAR%d\n",
+ sc->sc_dev.dv_xname, cardbus_space - 1));
+ }
+
+ /* XXX zero register so mapreg_map doesn't get confused by old
+ contents */
+ cardbus_conf_write(cc, cf, tag, reg, 0);
+ if(Cardbus_mapreg_map(ca->ca_ct, reg,
+ CARDBUS_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
+ 0,
+ NULL, &bar_memh, &bar_addr, &bar_size)) {
+ printf("%s: failed to map memory\n", sc->sc_dev.dv_xname);
+ return 1;
+ }
+
+
+ if(cardbus_space == CARDBUS_CIS_ASI_ROM) {
+ cardbusreg_t exrom;
+ int save;
+ struct cardbus_rom_image_head rom_image;
+ struct cardbus_rom_image *p;
+
+ save = splhigh();
+ /* enable rom address decoder */
+ exrom = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, exrom | 1);
+
+ command = cardbus_conf_read(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG,
+ command | CARDBUS_COMMAND_MEM_ENABLE);
+
+ if(cardbus_read_exrom(ca->ca_memt, bar_memh, &rom_image))
+ goto out;
+
+ for(p = SIMPLEQ_FIRST(&rom_image);
+ p;
+ p = SIMPLEQ_NEXT(p, next)) {
+ if(p->rom_image == CARDBUS_CIS_ASI_ROM_IMAGE(cis_ptr)) {
+ bus_space_read_region_1(p->romt, p->romh,
+ CARDBUS_CIS_ADDR(cis_ptr),
+ tuples, 256);
+ found++;
+ }
+ break;
+ }
+ while((p = SIMPLEQ_FIRST(&rom_image)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&rom_image, p, next);
+ free(p, M_DEVBUF);
+ }
+ out:
+ exrom = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, exrom & ~1);
+ splx(save);
+ } else {
+ command = cardbus_conf_read(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG,
+ command | CARDBUS_COMMAND_MEM_ENABLE);
+ /* XXX byte order? */
+ bus_space_read_region_1(ca->ca_memt, bar_memh,
+ cis_ptr, tuples, 256);
+ found++;
+ }
+ command = cardbus_conf_read(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG,
+ command & ~CARDBUS_COMMAND_MEM_ENABLE);
+ cardbus_conf_write(cc, cf, tag, reg, 0);
+#if 0
+ /* XXX unmap memory */
+ (*ca->ca_ct->ct_cf->cardbus_space_free)(ca->ca_ct,
+ ca->ca_ct->ct_sc->sc_rbus_memt,
+ bar_memh, bar_size);
+#endif
+ break;
+
+#ifdef DIAGNOSTIC
+ default:
+ panic("%s: bad CIS space (%d)", sc->sc_dev.dv_xname, cardbus_space);
+#endif
+ }
+ return !found;
+}
+
+static void
+parse_tuple(u_int8_t *tuple, int len, void *data)
+{
+#ifdef CARDBUS_DEBUG
+ static const char func[] = "parse_tuple";
+#endif
+ struct cardbus_cis_info *cis = data;
+ int bar_index;
+ int i;
+ char *p;
+ switch(tuple[0]) {
+ case PCMCIA_CISTPL_MANFID:
+ if(tuple[1] != 5) {
+ DPRINTF(("%s: wrong length manufacturer id (%d)\n",
+ func, tuple[1]));
+ break;
+ }
+ cis->manufacturer = tuple[2] | (tuple[3] << 8);
+ cis->product = tuple[4] | (tuple[5] << 8);
+ break;
+ case PCMCIA_CISTPL_VERS_1:
+ bcopy(tuple + 2, cis->cis1_info_buf, tuple[1]);
+ i = 0;
+ p = cis->cis1_info_buf + 2;
+ while(i < sizeof(cis->cis1_info) / sizeof(cis->cis1_info[0])) {
+ cis->cis1_info[i++] = p;
+ while(*p != '\0' && *p != '\xff')
+ p++;
+ if(*p == '\xff')
+ break;
+ p++;
+ }
+ break;
+ case PCMCIA_CISTPL_BAR:
+ if(tuple[1] != 6) {
+ DPRINTF(("%s: BAR with short length (%d)\n", func, tuple[1]));
+ break;
+ }
+ bar_index = tuple[2] & 7;
+ if(bar_index == 0) {
+ DPRINTF(("%s: invalid ASI in BAR tuple\n", func));
+ break;
+ }
+ bar_index--;
+ cis->bar[bar_index].flags = tuple[2];
+ cis->bar[bar_index].size = (tuple[4] << 0) |
+ (tuple[5] << 8) |
+ (tuple[6] << 16) |
+ (tuple[7] << 24);
+ break;
+ case PCMCIA_CISTPL_FUNCID:
+ cis->funcid = tuple[2];
+ break;
+
+ case PCMCIA_CISTPL_FUNCE:
+ if(cis->funcid == PCMCIA_FUNCTION_NETWORK && tuple[1] >= 8) {
+ if(tuple[2] == PCMCIA_TPLFE_TYPE_LAN_NID) {
+ if(tuple[3] > sizeof(cis->funce.network.netid)) {
+ DPRINTF(("%s: unknown network id type (len = %d)\n",
+ func, tuple[3]));
+ } else {
+ cis->funce.network.netid_present = 1;
+ bcopy(tuple + 4, cis->funce.network.netid,
+ tuple[3]);
+ }
+ }
+ }
+ break;
+ }
+}
+
+/*
+ * int cardbus_attach_card(struct cardbus_softc *sc)
+ *
+ * This function attaches the card on the slot: turns on power,
+ * reads and analyses tuple, sets consifuration index.
+ *
+ * This function returns the number of recognised device functions.
+ * If no functions are recognised, return 0.
+ */
+int
+cardbus_attach_card(sc)
+ struct cardbus_softc *sc;
+{
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ int cdstatus;
+ cardbustag_t tag;
+ cardbusreg_t id, class, cis_ptr;
+ cardbusreg_t bhlc;
+ u_int8_t tuple[2048];
+ int function, nfunction;
+ struct cardbus_devfunc **previous_next = &(sc->sc_funcs);
+ struct device *csc;
+ int no_work_funcs = 0;
+ cardbus_devfunc_t ct;
+
+ cc = sc->sc_cc;
+ cf = sc->sc_cf;
+
+ DPRINTF(("cardbus_attach_card: cb%d start\n", sc->sc_dev.dv_unit));
+
+ /* inspect initial voltage */
+ if (0 == (cdstatus = (cf->cardbus_ctrl)(cc, CARDBUS_CD))) {
+ DPRINTF(("cardbusattach: no CardBus card on cb%d\n", sc->sc_dev.dv_unit));
+ return 0;
+ }
+
+ enable_function(sc, cdstatus, 8); /* XXX use fake function 8 to
+ keep power on during whole
+ configuration */
+
+ function = 0;
+
+ tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, function);
+
+ /*
+ * Wait until power comes up. Maxmum 500 ms.
+ */
+ {
+ int i;
+ for (i = 0; i < 5; ++i) {
+ id = cardbus_conf_read(cc, cf, tag, CARDBUS_ID_REG);
+ if (id != 0xffffffff && id != 0) {
+ break;
+ }
+ if (cold) { /* before kernel thread invoked */
+ delay(100*1000);
+ } else { /* thread context */
+ if (tsleep((void *)sc, PCATCH, "cardbus", hz/10) != EWOULDBLOCK) {
+ break;
+ }
+ }
+ }
+ if (i == 5) {
+ return 0;
+ }
+ }
+
+ bhlc = cardbus_conf_read(cc, cf, tag, CARDBUS_BHLC_REG);
+ if (CARDBUS_LATTIMER(bhlc) < 0x10) {
+ bhlc &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
+ bhlc |= (0x10 << CARDBUS_LATTIMER_SHIFT);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BHLC_REG, bhlc);
+ }
+
+ nfunction = CARDBUS_HDRTYPE_MULTIFN(bhlc) ? 8 : 1;
+
+ for(function = 0; function < nfunction; function++) {
+ struct cardbus_attach_args ca;
+
+ tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, function);
+
+ id = cardbus_conf_read(cc, cf, tag, CARDBUS_ID_REG);
+ class = cardbus_conf_read(cc, cf, tag, CARDBUS_CLASS_REG);
+ cis_ptr = cardbus_conf_read(cc, cf, tag, CARDBUS_CIS_REG);
+
+ /* Invalid vendor ID value? */
+ if (CARDBUS_VENDOR(id) == CARDBUS_VENDOR_INVALID) {
+ continue;
+ }
+
+ DPRINTF(("cardbus_attach_card: Vendor 0x%x, Product 0x%x, CIS 0x%x\n",
+ CARDBUS_VENDOR(id), CARDBUS_PRODUCT(id), cis_ptr));
+
+ enable_function(sc, cdstatus, function);
+
+ /* clean up every BAR */
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE0_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE1_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE2_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE3_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE4_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE5_REG, 0);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_ROM_REG, 0);
+
+ /*
+ * We need to allocate the ct here, since we might
+ * need it when reading the CIS
+ */
+ if (NULL == (ct = (cardbus_devfunc_t)malloc(sizeof(struct cardbus_devfunc),
+ M_DEVBUF, M_NOWAIT))) {
+ panic("no room for cardbus_tag");
+ }
+
+ ct->ct_cc = sc->sc_cc;
+ ct->ct_cf = sc->sc_cf;
+ ct->ct_bus = sc->sc_bus;
+ ct->ct_dev = sc->sc_device;
+ ct->ct_func = function;
+ ct->ct_sc = sc;
+ ct->ct_next = NULL;
+ *previous_next = ct;
+
+ memset(&ca, 0, sizeof(ca));
+
+ ca.ca_unit = sc->sc_dev.dv_unit;
+ ca.ca_ct = ct;
+
+ ca.ca_iot = sc->sc_iot;
+ ca.ca_memt = sc->sc_memt;
+ ca.ca_dmat = sc->sc_dmat;
+
+ ca.ca_tag = tag;
+ ca.ca_device = sc->sc_device;
+ ca.ca_function = function;
+ ca.ca_id = id;
+ ca.ca_class = class;
+
+ ca.ca_intrline = sc->sc_intrline;
+
+ bzero(tuple, 2048);
+
+ if(cardbus_read_tuples(&ca, cis_ptr, tuple, sizeof(tuple))) {
+ printf("cardbus_attach_card: failed to read CIS\n");
+ } else {
+#ifdef CARDBUS_DEBUG
+ decode_tuples(tuple, 2048, print_tuple, NULL);
+#endif
+ decode_tuples(tuple, 2048, parse_tuple, &ca.ca_cis);
+ }
+
+ if (NULL == (csc = config_found_sm((void *)sc, &ca, cardbusprint, cardbussubmatch))) {
+ /* do not match */
+ disable_function(sc, function);
+ free(ct, M_DEVBUF);
+ *previous_next = NULL;
+ } else {
+ /* found */
+ previous_next = &(ct->ct_next);
+ ct->ct_device = csc;
+ ++no_work_funcs;
+ }
+ }
+ /*
+ * XXX power down pseudo function 8 (this will power down the card
+ * if no functions were attached).
+ */
+ disable_function(sc, 8);
+
+ return no_work_funcs;
+}
+
+
+static int
+cardbussubmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct cardbus_attach_args *ca = aux;
+
+ if (cf->cardbuscf_dev != CARDBUS_UNK_DEV &&
+ cf->cardbuscf_dev != ca->ca_unit) {
+ return 0;
+ }
+ if (cf->cardbuscf_function != CARDBUS_UNK_FUNCTION &&
+ cf->cardbuscf_function != ca->ca_function) {
+ return 0;
+ }
+
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+
+
+static int
+cardbusprint(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+ struct cardbus_attach_args *ca = aux;
+ char devinfo[256];
+ int i;
+ if (pnp) {
+ pci_devinfo(ca->ca_id, ca->ca_class, 1, devinfo);
+ for (i = 0; i < 4; i++) {
+ if (ca->ca_cis.cis1_info[i] == NULL)
+ break;
+ if (i)
+ printf(", ");
+ printf("%s", ca->ca_cis.cis1_info[i]);
+ }
+ if (i)
+ printf(" ");
+ printf("(manufacturer 0x%x, product 0x%x)", ca->ca_cis.manufacturer,
+ ca->ca_cis.product);
+ printf(" %s at %s", devinfo, pnp);
+ }
+ printf(" dev %d function %d", ca->ca_device, ca->ca_function);
+
+ return UNCONF;
+}
+
+
+
+
+
+
+/*
+ * void cardbus_detach_card(struct cardbus_softc *sc)
+ *
+ * This function detaches the card on the slot: detach device data
+ * structure and turns off the power.
+ *
+ * This function must not be called under interrupt context.
+ */
+void
+cardbus_detach_card(sc)
+ struct cardbus_softc *sc;
+{
+ struct cardbus_devfunc *ct, *ct_next, **prev_next;
+
+ prev_next = &(sc->sc_funcs->ct_next);
+
+ for (ct = sc->sc_funcs; ct != NULL; ct = ct_next) {
+ struct device *fndev = ct->ct_device;
+ ct_next = ct->ct_next;
+
+ DPRINTF(("%s: detaching %s\n", sc->sc_dev.dv_xname, fndev->dv_xname));
+ /* call device detach function */
+
+ if (0 != config_detach(fndev, 0)) {
+ printf("%s: cannot detaching dev %s, function %d\n",
+ sc->sc_dev.dv_xname, fndev->dv_xname, ct->ct_func);
+ prev_next = &(ct->ct_next);
+ } else {
+ sc->sc_poweron_func &= ~(1 << ct->ct_func);
+ *prev_next = ct->ct_next;
+ free(ct, M_DEVBUF);
+ }
+ }
+
+ sc->sc_poweron_func = 0;
+ sc->sc_cf->cardbus_power(sc->sc_cc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
+}
+
+
+
+
+/*
+ * void *cardbus_intr_establish(cc, cf, irq, level, func, arg)
+ * Interrupt handler of pccard.
+ * args:
+ * cardbus_chipset_tag_t *cc
+ * int irq:
+ */
+void *
+cardbus_intr_establish(cc, cf, irq, level, func, arg)
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ cardbus_intr_handle_t irq;
+ int level;
+ int (*func) __P((void *));
+ void *arg;
+{
+ DPRINTF(("- cardbus_intr_establish: irq %d\n", irq));
+
+ return (*cf->cardbus_intr_establish)(cc, irq, level, func, arg);
+}
+
+
+
+/*
+ * void cardbus_intr_disestablish(cc, cf, handler)
+ * Interrupt handler of pccard.
+ * args:
+ * cardbus_chipset_tag_t *cc
+ */
+void
+cardbus_intr_disestablish(cc, cf, handler)
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ void *handler;
+{
+ DPRINTF(("- pccard_intr_disestablish\n"));
+
+ (*cf->cardbus_intr_disestablish)(cc, handler);
+ return;
+}
+
+
+
+/* XXX this should be merged with cardbus_function_{enable,disable},
+ but we don't have a ct when these functions are called */
+
+static void
+enable_function(sc, cdstatus, function)
+ struct cardbus_softc *sc;
+ int cdstatus;
+ int function;
+{
+
+ if (sc->sc_poweron_func == 0) {
+ /* switch to 3V and/or wait for power to stabilize */
+ if (cdstatus & CARDBUS_3V_CARD) {
+ sc->sc_cf->cardbus_power(sc->sc_cc, CARDBUS_VCC_3V);
+ } else {
+ /* No cards other than 3.3V cards. */
+ return;
+ }
+ (sc->sc_cf->cardbus_ctrl)(sc->sc_cc, CARDBUS_RESET);
+ }
+ sc->sc_poweron_func |= (1 << function);
+}
+
+static void
+disable_function(sc, function)
+ struct cardbus_softc *sc;
+ int function;
+{
+
+ sc->sc_poweron_func &= ~(1 << function);
+ if (sc->sc_poweron_func == 0) {
+ /* power-off because no functions are enabled */
+ sc->sc_cf->cardbus_power(sc->sc_cc, CARDBUS_VCC_0V);
+ }
+}
+
+/*
+ * int cardbus_function_enable(struct cardbus_softc *sc, int func)
+ *
+ * This function enables a function on a card. When no power is
+ * applied on the card, power will be applied on it.
+ */
+int
+cardbus_function_enable(sc, func)
+ struct cardbus_softc *sc;
+ int func;
+{
+ cardbus_chipset_tag_t cc = sc->sc_cc;
+ cardbus_function_tag_t cf = sc->sc_cf;
+ cardbusreg_t command;
+ cardbustag_t tag;
+
+ DPRINTF(("entering cardbus_function_enable... "));
+
+ /* entering critical area */
+
+ enable_function(sc, CARDBUS_3V_CARD, func); /* XXX: sc_vold should be used */
+
+ /* exiting critical area */
+
+ tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, func);
+
+ command = cardbus_conf_read(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG);
+ command |= (CARDBUS_COMMAND_MEM_ENABLE | CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MASTER_ENABLE); /* XXX: good guess needed */
+
+ cardbus_conf_write(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG, command);
+
+ cardbus_free_tag(cc, cf, tag);
+
+ DPRINTF(("%x\n", sc->sc_poweron_func));
+
+ return 0;
+}
+
+
+/*
+ * int cardbus_function_disable(struct cardbus_softc *, int func)
+ *
+ * This function disable a function on a card. When no functions are
+ * enabled, it turns off the power.
+ */
+int
+cardbus_function_disable(sc, func)
+ struct cardbus_softc *sc;
+ int func;
+{
+
+ DPRINTF(("entering cardbus_function_disable... "));
+
+ disable_function(sc, func);
+
+ return 0;
+}
+
+
+/*
+ * int cardbus_get_capability(cardbus_chipset_tag_t cc,
+ * cardbus_function_tag_t cf, cardbustag_t tag, int capid, int *offset,
+ * cardbusreg_t *value)
+ *
+ * Find the specified PCI capability.
+ */
+int
+cardbus_get_capability(cc, cf, tag, capid, offset, value)
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ cardbustag_t tag;
+ int capid;
+ int *offset;
+ cardbusreg_t *value;
+{
+ cardbusreg_t reg;
+ unsigned int ofs;
+
+ reg = cardbus_conf_read(cc, cf, tag, PCI_COMMAND_STATUS_REG);
+ if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
+ return (0);
+
+ ofs = PCI_CAPLIST_PTR(cardbus_conf_read(cc, cf, tag,
+ PCI_CAPLISTPTR_REG));
+ while (ofs != 0) {
+#ifdef DIAGNOSTIC
+ if ((ofs & 3) || (ofs < 0x40))
+ panic("cardbus_get_capability");
+#endif
+ reg = cardbus_conf_read(cc, cf, tag, ofs);
+ if (PCI_CAPLIST_CAP(reg) == capid) {
+ if (offset)
+ *offset = ofs;
+ if (value)
+ *value = reg;
+ return (1);
+ }
+ ofs = PCI_CAPLIST_NEXT(reg);
+ }
+
+ return (0);
+}
+
+
+/*
+ * below this line, there are some functions for decoding tuples.
+ * They should go out from this file.
+ */
+
+static u_int8_t *
+decode_tuple __P((u_int8_t *tuple, tuple_decode_func func, void *data));
+
+static int
+decode_tuples(tuple, buflen, func, data)
+ u_int8_t *tuple;
+ int buflen;
+ tuple_decode_func func;
+ void *data;
+{
+ u_int8_t *tp = tuple;
+
+ if (PCMCIA_CISTPL_LINKTARGET != *tuple) {
+ DPRINTF(("WRONG TUPLE: 0x%x\n", *tuple));
+ return 0;
+ }
+
+ while (NULL != (tp = decode_tuple(tp, func, data))) {
+ if (tuple + buflen < tp) {
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
+static u_int8_t *
+decode_tuple(tuple, func, data)
+ u_int8_t *tuple;
+ tuple_decode_func func;
+ void *data;
+{
+ u_int8_t type;
+ u_int8_t len;
+
+ type = tuple[0];
+ len = tuple[1] + 2;
+
+ (*func)(tuple, len, data);
+
+ if (PCMCIA_CISTPL_END == type) {
+ return NULL;
+ }
+
+ return tuple + len;
+}
+
+
+#ifdef CARDBUS_DEBUG
+static char *tuple_name __P((int type));
+
+static char *
+tuple_name(type)
+ int type;
+{
+ static char *tuple_name_s [] = {
+ "TPL_NULL", "TPL_DEVICE", "Reserved", "Reserved", /* 0-3 */
+ "CONFIG_CB", "CFTABLE_ENTRY_CB", "Reserved", "BAR", /* 4-7 */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 8-B */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* C-F */
+ "CHECKSUM", "LONGLINK_A", "LONGLINK_C", "LINKTARGET", /* 10-13 */
+ "NO_LINK", "VERS_1", "ALTSTR", "DEVICE_A",
+ "JEDEC_C", "JEDEC_A", "CONFIG", "CFTABLE_ENTRY",
+ "DEVICE_OC", "DEVICE_OA", "DEVICE_GEO", "DEVICE_GEO_A",
+ "MANFID", "FUNCID", "FUNCE", "SWIL", /* 20-23 */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 24-27 */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 28-2B */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 2C-2F */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 30-33 */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 34-37 */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 38-3B */
+ "Reserved", "Reserved", "Reserved", "Reserved", /* 3C-3F */
+ "VERS_2", "FORMAT", "GEOMETRY", "BYTEORDER",
+ "DATE", "BATTERY", "ORG"
+ };
+#define NAME_LEN(x) (sizeof x / sizeof(x[0]))
+
+ if (type > 0 && type < NAME_LEN(tuple_name_s)) {
+ return tuple_name_s[type];
+ } else if (0xff == type) {
+ return "END";
+ } else {
+ return "Reserved";
+ }
+}
+
+static void
+print_tuple(tuple, len, data)
+ u_int8_t *tuple;
+ int len;
+ void *data;
+{
+ int i;
+
+ printf("tuple: %s len %d\n", tuple_name(tuple[0]), len);
+
+ for (i = 0; i < len; ++i) {
+ if (i % 16 == 0) {
+ printf(" 0x%2x:", i);
+ }
+ printf(" %x",tuple[i]);
+ if (i % 16 == 15) {
+ printf("\n");
+ }
+ }
+ if (i % 16 != 0) {
+ printf("\n");
+ }
+}
+
+#endif
diff --git a/sys/dev/cardbus/cardbus_exrom.c b/sys/dev/cardbus/cardbus_exrom.c
new file mode 100644
index 00000000000..a33d60996fc
--- /dev/null
+++ b/sys/dev/cardbus/cardbus_exrom.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: cardbus_exrom.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardbus_exrom.c,v 1.4 2000/02/03 06:47:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to
+ * The NetBSD Foundation by Johan Danielsson.
+ *
+ * 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. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/cardbus/cardbus_exrom.h>
+
+#define READ_INT16(T, H, O) \
+(bus_space_read_1((T), (H), (O)) | (bus_space_read_1((T), (H), (O) + 1) << 8))
+
+/* A PCI ROM is divided into a number of images. Each image has two
+ * data structures, a header located at the start of the image, and a
+ * `data structure' at some offset into it.
+ *
+ * The header is a 26 byte structure:
+ *
+ * Offset Length Description
+ * 0x00 1 signature byte 1 (0x55)
+ * 0x01 1 signature byte 2 (0xAA)
+ * 0x02 22 processor architecture data
+ * 0x18 2 pointer to the data structure
+ *
+ * The data structure is a 24 byte structure:
+ *
+ * Offset Length Description
+ * 0x00 4 signature (PCIR)
+ * 0x04 2 vendor id
+ * 0x06 2 device id
+ * 0x08 2 reserved
+ * 0x0A 2 data structure length
+ * 0x0C 1 data structure revision (0)
+ * 0x0D 3 class code
+ * 0x10 2 image length (in 512 byte blocks)
+ * 0x12 2 code revision level
+ * 0x14 1 code type
+ * 0x15 1 indicator (bit 7 indicates final image)
+ * 0x16 2 reserved
+ *
+ */
+
+/*
+ * Scan through a PCI expansion ROM, and create subregions for each
+ * ROM image. This function assumes that the ROM is mapped at
+ * (tag,handle), and that the expansion ROM address decoder is
+ * enabled. The PCI specification requires that no other BAR should
+ * be accessed while the ROM is enabled, so interrupts should be
+ * disabled.
+ */
+
+int
+cardbus_read_exrom(romt, romh, head)
+ bus_space_tag_t romt;
+ bus_space_handle_t romh;
+ struct cardbus_rom_image_head *head;
+{
+ static const char func[] = "cardbus_read_exrom";
+
+ size_t addr = 0; /* offset of current rom image */
+ size_t dataptr;
+ unsigned int rom_image = 0;
+
+ SIMPLEQ_INIT(head);
+ do {
+ size_t image_size;
+ struct cardbus_rom_image *image;
+ u_int16_t val;
+
+ val = READ_INT16(romt, romh, addr + CARDBUS_EXROM_SIGNATURE);
+ if(val != 0xaa55) {
+ printf("%s: bad header signature in ROM image %u: 0x%04x\n",
+ func, rom_image, val);
+ return 1;
+ }
+ dataptr = addr + READ_INT16(romt, romh, addr + CARDBUS_EXROM_DATA_PTR);
+ /* get the ROM image size, in blocks */
+ image_size = READ_INT16(romt, romh,
+ dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
+ if(image_size == 0)
+ /* XXX some ROMs seem to have this as zero, can we assume
+ this means 1 block? */
+ image_size = 1;
+ image_size <<= 9;
+ image = malloc(sizeof(*image), M_DEVBUF, M_NOWAIT);
+ if(image == NULL) {
+ printf("%s: out of memory\n", func);
+ return 1;
+ }
+ image->rom_image = rom_image;
+ image->image_size = image_size;
+ image->romt = romt;
+ if(bus_space_subregion(romt, romh, addr,
+ image_size, &image->romh)) {
+ printf("%s: bus_space_subregion failed", func);
+ free(image, M_DEVBUF);
+ return 1;
+ }
+ SIMPLEQ_INSERT_TAIL(head, image, next);
+ addr += image_size;
+ rom_image++;
+ } while ((bus_space_read_1(romt, romh,
+ dataptr + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0);
+ return 0;
+}
+
+
+#if 0
+struct cardbus_exrom_data_structure {
+ char signature[4];
+ cardbusreg_t id; /* vendor & device id */
+ u_int16_t structure_length;
+ u_int8_t structure_revision;
+ cardbusreg_t class; /* class code in upper 24 bits */
+ u_int16_t image_length;
+ u_int16_t data_revision;
+ u_int8_t code_type;
+ u_int8_t indicator;
+};
+
+pci_exrom_parse_data_structure(bus_space_tag_t tag,
+ bus_space_handle_t handle,
+ struct pci_exrom_data_structure *ds)
+{
+ unsigned char hdr[16];
+ bus_space_read_region_1(tag, handle, dataptr, hdr, sizeof(hdr));
+ memcpy(header->signature, hdr + PCI_EXROM_DATA_SIGNATURE, 4);
+#define LEINT16(B, O) ((B)[(O)] | ((B)[(O) + 1] << 8))
+ header->id = LEINT16(hdr, PCI_EXROM_DATA_VENDOR_ID) |
+ (LEINT16(hdr, PCI_EXROM_DATA_DEVICE_ID) << 16);
+ header->structure_length = LEINT16(hdr, PCI_EXROM_DATA_LENGTH);
+ header->structure_rev = hdr[PCI_EXROM_DATA_REV];
+ header->class = (hdr[PCI_EXROM_DATA_CLASS_CODE] << 8) |
+ (hdr[PCI_EXROM_DATA_CLASS_CODE + 1] << 16) |
+ (hdr[PCI_EXROM_DATA_CLASS_CODE + 2] << 24);
+ header->image_length = LEINT16(hdr, PCI_EXROM_DATA_IMAGE_LENGTH) << 16;
+ header->data_revision = LEINT16(hdr, PCI_EXROM_DATA_DATA_REV);
+ header->code_type = hdr[PCI_EXROM_DATA_CODE_TYPE];
+ header->indicator = hdr[PCI_EXROM_DATA_INDICATOR];
+ length = min(length, header->image_length - 0x18 - offset);
+ bus_space_read_region_1(tag, handle, dataptr + 0x18 + offset,
+ buf, length);
+ ret = length;
+}
+#endif
diff --git a/sys/dev/cardbus/cardbus_exrom.h b/sys/dev/cardbus/cardbus_exrom.h
new file mode 100644
index 00000000000..1021c208101
--- /dev/null
+++ b/sys/dev/cardbus/cardbus_exrom.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: cardbus_exrom.h,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardbus_exrom.h,v 1.2 1999/12/15 12:28:54 kleink Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to
+ * The NetBSD Foundation by Johan Danielsson.
+ *
+ * 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. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _DEV_CARDBUS_CARDBUS_EXROM_H_
+#define _DEV_CARDBUS_CARDBUS_EXROM_H_
+
+/* PCI ROM header fields */
+#define CARDBUS_EXROM_SIGNATURE 0x00
+#define CARDBUS_EXROM_DATA_PTR 0x18
+
+/* PCI ROM data structure fields */
+#define CARDBUS_EXROM_DATA_SIGNATURE 0x00 /* Signature ("PCIR") */
+#define CARDBUS_EXROM_DATA_VENDOR_ID 0x04 /* Vendor Identification */
+#define CARDBUS_EXROM_DATA_DEVICE_ID 0x06 /* Device Identification */
+#define CARDBUS_EXROM_DATA_LENGTH 0x0a /* PCI Data Structure Length */
+#define CARDBUS_EXROM_DATA_REV 0x0c /* PCI Data Structure Revision */
+#define CARDBUS_EXROM_DATA_CLASS_CODE 0x0d /* Class Code */
+#define CARDBUS_EXROM_DATA_IMAGE_LENGTH 0x10 /* Image Length */
+#define CARDBUS_EXROM_DATA_DATA_REV 0x12 /* Revision Level of Code/Data */
+#define CARDBUS_EXROM_DATA_CODE_TYPE 0x14 /* Code Type */
+#define CARDBUS_EXROM_DATA_INDICATOR 0x15 /* Indicator */
+
+
+struct cardbus_rom_image {
+ unsigned int rom_image; /* image number */
+ size_t image_size;
+ bus_space_tag_t romt;
+ bus_space_handle_t romh; /* subregion */
+ SIMPLEQ_ENTRY(cardbus_rom_image) next;
+};
+
+SIMPLEQ_HEAD(cardbus_rom_image_head, cardbus_rom_image);
+
+int
+cardbus_read_exrom __P((bus_space_tag_t, bus_space_handle_t,
+ struct cardbus_rom_image_head*));
+
+#endif /* !_DEV_CARDBUS_CARDBUS_EXROM_H_ */
diff --git a/sys/dev/cardbus/cardbus_map.c b/sys/dev/cardbus/cardbus_map.c
new file mode 100644
index 00000000000..f9251b75a32
--- /dev/null
+++ b/sys/dev/cardbus/cardbus_map.c
@@ -0,0 +1,442 @@
+/* $OpenBSD: cardbus_map.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardbus_map.c,v 1.10 2000/03/07 00:31:46 mycroft Exp $ */
+
+/*
+ * Copyright (c) 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.
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <dev/cardbus/cardbusvar.h>
+
+#include <dev/pci/pcireg.h> /* XXX */
+
+#if defined DEBUG && !defined CARDBUS_MAP_DEBUG
+#define CARDBUS_MAP_DEBUG
+#endif
+
+#if defined CARDBUS_MAP_DEBUG
+#define STATIC
+#define DPRINTF(a) printf a
+#else
+#define STATIC static
+#define DPRINTF(a)
+#endif
+
+
+static int cardbus_io_find __P((cardbus_chipset_tag_t, cardbus_function_tag_t,
+ cardbustag_t, int, cardbusreg_t,
+ bus_addr_t *, bus_size_t *, int *));
+static int cardbus_mem_find __P((cardbus_chipset_tag_t, cardbus_function_tag_t,
+ cardbustag_t, int, cardbusreg_t,
+ bus_addr_t *, bus_size_t *, int *));
+
+/*
+ * static int cardbus_io_find(cardbus_chipset_tag_t cc,
+ * cardbus_function_tag_t cf, cardbustag_t tag,
+ * int reg, cardbusreg_t type, bus_addr_t *basep,
+ * bus_size_t *sizep, int *flagsp)
+ * This code is stallen from sys/dev/pci_map.c.
+ */
+static int
+cardbus_io_find(cc, cf, tag, reg, type, basep, sizep, flagsp)
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ cardbustag_t tag;
+ int reg;
+ cardbusreg_t type;
+ bus_addr_t *basep;
+ bus_size_t *sizep;
+ int *flagsp;
+{
+ cardbusreg_t address, mask;
+ int s;
+
+ /* EXT ROM is able to map on memory space ONLY. */
+ if (reg == CARDBUS_ROM_REG) {
+ return 1;
+ }
+
+ if(reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
+ panic("cardbus_io_find: bad request");
+ }
+
+ /*
+ * Section 6.2.5.1, `Address Maps', tells us that:
+ *
+ * 1) The builtin software should have already mapped the device in a
+ * reasonable way.
+ *
+ * 2) A device which wants 2^n bytes of memory will hardwire the bottom
+ * n bits of the address to 0. As recommended, we write all 1s and see
+ * what we get back.
+ */
+ s = splhigh();
+ address = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
+ mask = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, address);
+ splx(s);
+
+ if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
+ printf("cardbus_io_find: expected type i/o, found mem\n");
+ return 1;
+ }
+
+ if (PCI_MAPREG_IO_SIZE(mask) == 0) {
+ printf("cardbus_io_find: void region\n");
+ return 1;
+ }
+
+ if (basep != 0) {
+ *basep = PCI_MAPREG_IO_ADDR(address);
+ }
+ if (sizep != 0) {
+ *sizep = PCI_MAPREG_IO_SIZE(mask);
+ }
+ if (flagsp != 0) {
+ *flagsp = 0;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
+ * cardbus_function_tag_t cf, cardbustag_t tag,
+ * int reg, cardbusreg_t type, bus_addr_t *basep,
+ * bus_size_t *sizep, int *flagsp)
+ * This code is stallen from sys/dev/pci_map.c.
+ */
+static int
+cardbus_mem_find(cc, cf, tag, reg, type, basep, sizep, flagsp)
+ cardbus_chipset_tag_t cc;
+ cardbus_function_tag_t cf;
+ cardbustag_t tag;
+ int reg;
+ cardbusreg_t type;
+ bus_addr_t *basep;
+ bus_size_t *sizep;
+ int *flagsp;
+{
+ cardbusreg_t address, mask;
+ int s;
+
+ if (reg != CARDBUS_ROM_REG &&
+ (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
+ panic("cardbus_mem_find: bad request");
+ }
+
+ /*
+ * Section 6.2.5.1, `Address Maps', tells us that:
+ *
+ * 1) The builtin software should have already mapped the device in a
+ * reasonable way.
+ *
+ * 2) A device which wants 2^n bytes of memory will hardwire the bottom
+ * n bits of the address to 0. As recommended, we write all 1s and see
+ * what we get back.
+ */
+ s = splhigh();
+ address = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
+ mask = cardbus_conf_read(cc, cf, tag, reg);
+ cardbus_conf_write(cc, cf, tag, reg, address);
+ splx(s);
+
+ if (reg != CARDBUS_ROM_REG) {
+ /* memory space BAR */
+
+ if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
+ printf("cardbus_mem_find: expected type mem, found i/o\n");
+ return 1;
+ }
+ if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
+ printf("cardbus_mem_find: expected mem type %08x, found %08x\n",
+ PCI_MAPREG_MEM_TYPE(type),
+ PCI_MAPREG_MEM_TYPE(address));
+ return 1;
+ }
+ }
+
+ if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
+ printf("cardbus_mem_find: void region\n");
+ return 1;
+ }
+
+ switch (PCI_MAPREG_MEM_TYPE(address)) {
+ case PCI_MAPREG_MEM_TYPE_32BIT:
+ case PCI_MAPREG_MEM_TYPE_32BIT_1M:
+ break;
+ case PCI_MAPREG_MEM_TYPE_64BIT:
+ printf("cardbus_mem_find: 64-bit memory mapping register\n");
+ return 1;
+ default:
+ printf("cardbus_mem_find: reserved mapping register type\n");
+ return 1;
+ }
+
+ if (basep != 0) {
+ *basep = PCI_MAPREG_MEM_ADDR(address);
+ }
+ if (sizep != 0) {
+ *sizep = PCI_MAPREG_MEM_SIZE(mask);
+ }
+ if (flagsp != 0) {
+ *flagsp = PCI_MAPREG_MEM_CACHEABLE(address);
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * int cardbus_mapreg_map(struct cardbus_softc *, int, int, cardbusreg_t,
+ * int bus_space_tag_t *, bus_space_handle_t *,
+ * bus_addr_t *, bus_size_t *)
+ * This function maps bus-space on the value of Base Address
+ * Register (BAR) indexed by the argument `reg' (the second argument).
+ * When the value of the BAR is not valid, such as 0x00000000, a new
+ * address should be allocated for the BAR and new address values is
+ * written on the BAR.
+ */
+int
+cardbus_mapreg_map(sc, func, reg, type, busflags, tagp, handlep, basep, sizep)
+ struct cardbus_softc *sc;
+ int func, reg, busflags;
+ cardbusreg_t type;
+ bus_space_tag_t *tagp;
+ bus_space_handle_t *handlep;
+ bus_addr_t *basep;
+ bus_size_t *sizep;
+{
+ cardbus_chipset_tag_t cc = sc->sc_cc;
+ cardbus_function_tag_t cf = sc->sc_cf;
+ bus_space_tag_t bustag;
+#if rbus
+ rbus_tag_t rbustag;
+#endif
+ bus_space_handle_t handle;
+ bus_addr_t base;
+ bus_size_t size;
+ int flags;
+ int status = 0;
+
+ cardbustag_t tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, func);
+
+ DPRINTF(("cardbus_mapreg_map called: %s %x\n", sc->sc_dev.dv_xname,
+ type));
+
+ if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
+ if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size, &flags)) {
+ status = 1;
+ }
+ bustag = sc->sc_iot;
+#if rbus
+ rbustag = sc->sc_rbus_iot;
+#endif
+ } else {
+ if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size, &flags)){
+ status = 1;
+ }
+ bustag = sc->sc_memt;
+#if rbus
+ rbustag = sc->sc_rbus_memt;
+#endif
+ }
+ if (status == 0) {
+#if rbus
+ bus_addr_t mask = size - 1;
+ if (base != 0) {
+ mask = 0xffffffff;
+ }
+ if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
+ size, busflags | flags, &base, &handle)) {
+ panic("io alloc");
+ }
+#else
+ bus_addr_t start = 0x8300;
+ bus_addr_t end = 0x8400;
+ if (base != 0) {
+ bus_addr_t start = base;
+ bus_addr_t end = base + size;
+ }
+ if (bus_space_alloc(bustag, start, end, size, size, 0, 0, &base, &handle)) {
+ panic("io alloc");
+ }
+#endif
+ }
+ cardbus_conf_write(cc, cf, tag, reg, base);
+
+ DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", base));
+
+ if (tagp != 0) {
+ *tagp = bustag;
+ }
+ if (handlep != 0) {
+ *handlep = handle;
+ }
+ if (basep != 0) {
+ *basep = base;
+ }
+ if (sizep != 0) {
+ *sizep = size;
+ }
+ cardbus_free_tag(cc, cf, tag);
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
+ * bus_space_tag_t tag, bus_space_handle_t handle,
+ * bus_size_t size)
+ *
+ * This function releases bus-space region and close memory or io
+ * window on the bridge.
+ *
+ * Arguments:
+ * struct cardbus_softc *sc; the pointer to the device structure of cardbus.
+ * int func; the number of function on the device.
+ * int reg; the offset of BAR register.
+ */
+int
+cardbus_mapreg_unmap(sc, func, reg, tag, handle, size)
+ struct cardbus_softc *sc;
+ int func, reg;
+ bus_space_tag_t tag;
+ bus_space_handle_t handle;
+ bus_size_t size;
+{
+ cardbus_chipset_tag_t cc = sc->sc_cc;
+ cardbus_function_tag_t cf = sc->sc_cf;
+ int st = 1;
+ cardbustag_t cardbustag;
+#if rbus
+ rbus_tag_t rbustag;
+
+ if (sc->sc_iot == tag) {
+ /* bus space is io space */
+ DPRINTF(("%s: unmap i/o space\n", sc->sc_dev.dv_xname));
+ rbustag = sc->sc_rbus_iot;
+ } else if (sc->sc_memt == tag) {
+ /* bus space is memory space */
+ DPRINTF(("%s: unmap mem space\n", sc->sc_dev.dv_xname));
+ rbustag = sc->sc_rbus_memt;
+ } else {
+ return 1;
+ }
+#endif
+
+ cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, func);
+
+ cardbus_conf_write(cc, cf, cardbustag, reg, 0);
+
+#if rbus
+ (*cf->cardbus_space_free)(cc, rbustag, handle, size);
+#endif
+
+ cardbus_free_tag(cc, cf, cardbustag);
+
+ return st;
+}
+
+
+
+
+
+/*
+ * int cardbus_save_bar(cardbus_devfunc_t);
+ *
+ * This function saves the Base Address Registers at the CardBus
+ * function denoted by the argument.
+ */
+int cardbus_save_bar(ct)
+ cardbus_devfunc_t ct;
+{
+ cardbustag_t tag = Cardbus_make_tag(ct);
+ cardbus_chipset_tag_t cc = ct->ct_cc;
+ cardbus_function_tag_t cf = ct->ct_cf;
+
+ ct->ct_bar[0] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE0_REG);
+ ct->ct_bar[1] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE1_REG);
+ ct->ct_bar[2] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE2_REG);
+ ct->ct_bar[3] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE3_REG);
+ ct->ct_bar[4] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE4_REG);
+ ct->ct_bar[5] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE5_REG);
+
+ DPRINTF(("cardbus_save_bar: %x %x\n", ct->ct_bar[0], ct->ct_bar[1]));
+
+ Cardbus_free_tag(ct, tag);
+
+ return 0;
+}
+
+
+
+/*
+ * int cardbus_restore_bar(cardbus_devfunc_t);
+ *
+ * This function saves the Base Address Registers at the CardBus
+ * function denoted by the argument.
+ */
+int cardbus_restore_bar(ct)
+ cardbus_devfunc_t ct;
+{
+ cardbustag_t tag = Cardbus_make_tag(ct);
+ cardbus_chipset_tag_t cc = ct->ct_cc;
+ cardbus_function_tag_t cf = ct->ct_cf;
+
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE0_REG, ct->ct_bar[0]);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE1_REG, ct->ct_bar[1]);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE2_REG, ct->ct_bar[2]);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE3_REG, ct->ct_bar[3]);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE4_REG, ct->ct_bar[4]);
+ cardbus_conf_write(cc, cf, tag, CARDBUS_BASE5_REG, ct->ct_bar[5]);
+
+ Cardbus_free_tag(ct, tag);
+
+ return 0;
+}
diff --git a/sys/dev/cardbus/cardbusvar.h b/sys/dev/cardbus/cardbusvar.h
new file mode 100644
index 00000000000..abd8e2a2d00
--- /dev/null
+++ b/sys/dev/cardbus/cardbusvar.h
@@ -0,0 +1,450 @@
+/* $OpenBSD */
+/* $NetBSD: cardbusvar.h,v 1.17 2000/04/02 19:11:37 mycroft Exp $ */
+
+/*
+ * 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 the author.
+ * 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.
+ */
+
+#ifndef _DEV_CARDBUS_CARDBUSVAR_H_
+#define _DEV_CARDBUS_CARDBUSVAR_H_
+
+#include <dev/pci/pcivar.h> /* for pcitag_t */
+
+#if 1
+#include <dev/cardbus/rbus.h>
+#endif
+
+
+
+typedef void *cardbus_chipset_tag_t;
+typedef int cardbus_intr_handle_t;
+
+
+/* XXX they must be in cardbusreg.h */
+typedef u_int32_t cardbusreg_t;
+typedef pcitag_t cardbustag_t;
+typedef int cardbus_intr_line_t;
+
+#define CARDBUS_ID_REG 0x00
+
+typedef u_int16_t cardbus_vendor_id_t;
+typedef u_int16_t cardbus_product_id_t;
+
+# define CARDBUS_VENDOR_SHIFT 0
+# define CARDBUS_VENDOR_MASK 0xffff
+# define CARDBUS_VENDOR(id) \
+ (((id) >> CARDBUS_VENDOR_SHIFT) & CARDBUS_VENDOR_MASK)
+
+# define CARDBUS_PRODUCT_SHIFT 16
+# define CARDBUS_PRODUCT_MASK 0xffff
+# define CARDBUS_PRODUCT(id) \
+ (((id) >> CARDBUS_PRODUCT_SHIFT) & CARDBUS_PRODUCT_MASK)
+
+
+#define CARDBUS_COMMAND_STATUS_REG 0x04
+
+# define CARDBUS_COMMAND_IO_ENABLE 0x00000001
+# define CARDBUS_COMMAND_MEM_ENABLE 0x00000002
+# define CARDBUS_COMMAND_MASTER_ENABLE 0x00000004
+
+
+#define CARDBUS_CLASS_REG 0x08
+
+#define CARDBUS_CLASS_SHIFT 24
+#define CARDBUS_CLASS_MASK 0xff
+#define CARDBUS_CLASS(cr) \
+ (((cr) >> CARDBUS_CLASS_SHIFT) & CARDBUS_CLASS_MASK)
+
+#define CARDBUS_SUBCLASS_SHIFT 16
+#define CARDBUS_SUBCLASS_MASK 0xff
+#define CARDBUS_SUBCLASS(cr) \
+ (((cr) >> CARDBUS_SUBCLASS_SHIFT) & CARDBUS_SUBCLASS_MASK)
+
+#define CARDBUS_INTERFACE_SHIFT 8
+#define CARDBUS_INTERFACE_MASK 0xff
+#define CARDBUS_INTERFACE(cr) \
+ (((cr) >> CARDBUS_INTERFACE_SHIFT) & CARDBUS_INTERFACE_MASK)
+
+#define CARDBUS_REVISION_SHIFT 0
+#define CARDBUS_REVISION_MASK 0xff
+#define CARDBUS_REVISION(cr) \
+ (((cr) >> CARDBUS_REVISION_SHIFT) & CARDBUS_REVISION_MASK)
+
+/* base classes */
+#define CARDBUS_CLASS_PREHISTORIC 0x00
+#define CARDBUS_CLASS_MASS_STORAGE 0x01
+#define CARDBUS_CLASS_NETWORK 0x02
+#define CARDBUS_CLASS_DISPLAY 0x03
+#define CARDBUS_CLASS_MULTIMEDIA 0x04
+#define CARDBUS_CLASS_MEMORY 0x05
+#define CARDBUS_CLASS_BRIDGE 0x06
+#define CARDBUS_CLASS_COMMUNICATIONS 0x07
+#define CARDBUS_CLASS_SYSTEM 0x08
+#define CARDBUS_CLASS_INPUT 0x09
+#define CARDBUS_CLASS_DOCK 0x0a
+#define CARDBUS_CLASS_PROCESSOR 0x0b
+#define CARDBUS_CLASS_SERIALBUS 0x0c
+#define CARDBUS_CLASS_UNDEFINED 0xff
+
+/* 0x0c serial bus subclasses */
+#define CARDBUS_SUBCLASS_SERIALBUS_FIREWIRE 0x00
+#define CARDBUS_SUBCLASS_SERIALBUS_ACCESS 0x01
+#define CARDBUS_SUBCLASS_SERIALBUS_SSA 0x02
+#define CARDBUS_SUBCLASS_SERIALBUS_USB 0x03
+#define CARDBUS_SUBCLASS_SERIALBUS_FIBER 0x04
+
+/* BIST, Header Type, Latency Timer, Cache Line Size */
+#define CARDBUS_BHLC_REG 0x0c
+
+#define CARDBUS_BIST_SHIFT 24
+#define CARDBUS_BIST_MASK 0xff
+#define CARDBUS_BIST(bhlcr) \
+ (((bhlcr) >> CARDBUS_BIST_SHIFT) & CARDBUS_BIST_MASK)
+
+#define CARDBUS_HDRTYPE_SHIFT 16
+#define CARDBUS_HDRTYPE_MASK 0xff
+#define CARDBUS_HDRTYPE(bhlcr) \
+ (((bhlcr) >> CARDBUS_HDRTYPE_SHIFT) & CARDBUS_HDRTYPE_MASK)
+
+#define CARDBUS_HDRTYPE_TYPE(bhlcr) \
+ (CARDBUS_HDRTYPE(bhlcr) & 0x7f)
+#define CARDBUS_HDRTYPE_MULTIFN(bhlcr) \
+ ((CARDBUS_HDRTYPE(bhlcr) & 0x80) != 0)
+
+#define CARDBUS_LATTIMER_SHIFT 8
+#define CARDBUS_LATTIMER_MASK 0xff
+#define CARDBUS_LATTIMER(bhlcr) \
+ (((bhlcr) >> CARDBUS_LATTIMER_SHIFT) & CARDBUS_LATTIMER_MASK)
+
+#define CARDBUS_CACHELINE_SHIFT 0
+#define CARDBUS_CACHELINE_MASK 0xff
+#define CARDBUS_CACHELINE(bhlcr) \
+ (((bhlcr) >> CARDBUS_CACHELINE_SHIFT) & CARDBUS_CACHELINE_MASK)
+
+
+/* Base Resisters */
+#define CARDBUS_BASE0_REG 0x10
+#define CARDBUS_BASE1_REG 0x14
+#define CARDBUS_BASE2_REG 0x18
+#define CARDBUS_BASE3_REG 0x1C
+#define CARDBUS_BASE4_REG 0x20
+#define CARDBUS_BASE5_REG 0x24
+#define CARDBUS_CIS_REG 0x28
+#define CARDBUS_ROM_REG 0x30
+# define CARDBUS_CIS_ASIMASK 0x07
+# define CARDBUS_CIS_ASI(x) (CARDBUS_CIS_ASIMASK & (x))
+# define CARDBUS_CIS_ASI_TUPLE 0x00
+# define CARDBUS_CIS_ASI_BAR0 0x01
+# define CARDBUS_CIS_ASI_BAR1 0x02
+# define CARDBUS_CIS_ASI_BAR2 0x03
+# define CARDBUS_CIS_ASI_BAR3 0x04
+# define CARDBUS_CIS_ASI_BAR4 0x05
+# define CARDBUS_CIS_ASI_BAR5 0x06
+# define CARDBUS_CIS_ASI_ROM 0x07
+# define CARDBUS_CIS_ADDRMASK 0x0ffffff8
+# define CARDBUS_CIS_ADDR(x) (CARDBUS_CIS_ADDRMASK & (x))
+# define CARDBUS_CIS_ASI_BAR(x) (((CARDBUS_CIS_ASIMASK & (x))-1)*4+0x10)
+# define CARDBUS_CIS_ASI_ROM_IMAGE(x) (((x) >> 28) & 0xf)
+
+#define CARDBUS_INTERRUPT_REG 0x3c
+
+#define CARDBUS_MAPREG_TYPE_MEM 0x00000000
+#define CARDBUS_MAPREG_TYPE_IO 0x00000001
+
+/* XXX end */
+
+#if rbus
+
+typedef struct cardbus_functions {
+ int (*cardbus_space_alloc) __P((cardbus_chipset_tag_t, rbus_tag_t,
+ bus_addr_t addr, bus_size_t size,
+ bus_addr_t mask, bus_size_t align,
+ int flags, bus_addr_t *addrp,
+ bus_space_handle_t *bshp));
+ int (*cardbus_space_free) __P((cardbus_chipset_tag_t, rbus_tag_t,
+ bus_space_handle_t, bus_size_t));
+ void *(*cardbus_intr_establish) __P((cardbus_chipset_tag_t, int irq, int level, int (*ih)(void *), void *sc));
+ void (*cardbus_intr_disestablish) __P((cardbus_chipset_tag_t ct, void *ih));
+ int (*cardbus_ctrl) __P((cardbus_chipset_tag_t, int));
+ int (*cardbus_power) __P((cardbus_chipset_tag_t, int));
+
+ cardbustag_t (*cardbus_make_tag) __P((cardbus_chipset_tag_t, int, int, int));
+ void (*cardbus_free_tag) __P((cardbus_chipset_tag_t, cardbustag_t));
+ cardbusreg_t (*cardbus_conf_read) __P((cardbus_chipset_tag_t, cardbustag_t, int));
+ void (*cardbus_conf_write) __P((cardbus_chipset_tag_t, cardbustag_t, int, cardbusreg_t));
+} cardbus_function_t, *cardbus_function_tag_t;
+
+#else
+
+typedef struct cardbus_functions {
+ int (*cardbus_ctrl) __P((cardbus_chipset_tag_t, int));
+ int (*cardbus_power) __P((cardbus_chipset_tag_t, int));
+ int (*cardbus_mem_open) __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t));
+ int (*cardbus_mem_close) __P((cardbus_chipset_tag_t, int));
+ int (*cardbus_io_open) __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t));
+ int (*cardbus_io_close) __P((cardbus_chipset_tag_t, int));
+ void *(*cardbus_intr_establish) __P((cardbus_chipset_tag_t, int irq, int level, int (*ih)(void *), void *sc));
+ void (*cardbus_intr_disestablish) __P((cardbus_chipset_tag_t ct, void *ih));
+
+ cardbustag_t (*cardbus_make_tag) __P((cardbus_chipset_tag_t, int, int, int)); cardbusreg_t (*cardbus_conf_read) __P((cardbus_chipset_tag_t, cardbustag_t, int));
+ void (*cardbus_conf_write) __P((cardbus_chipset_tag_t, cardbustag_t, int, cardbusreg_t));
+} cardbus_function_t, *cardbus_function_tag_t;
+#endif /* rbus */
+
+/*
+ * struct cbslot_attach_args is the attach argument for cardbus card.
+ */
+struct cbslot_attach_args {
+ char *cba_busname;
+ bus_space_tag_t cba_iot; /* cardbus i/o space tag */
+ bus_space_tag_t cba_memt; /* cardbus mem space tag */
+ bus_dma_tag_t cba_dmat; /* DMA tag */
+
+ int cba_bus; /* cardbus bus number */
+
+ cardbus_chipset_tag_t cba_cc; /* cardbus chipset */
+ cardbus_function_tag_t cba_cf; /* cardbus functions */
+ int cba_intrline; /* interrupt line */
+
+#if rbus
+ rbus_tag_t cba_rbus_iot; /* CardBus i/o rbus tag */
+ rbus_tag_t cba_rbus_memt; /* CardBus mem rbus tag */
+#endif
+
+ int cba_cacheline; /* cache line size */
+ int cba_lattimer; /* latency timer */
+};
+
+
+#define cbslotcf_dev cf_loc[0]
+#define cbslotcf_func cf_loc[1]
+#define CBSLOT_UNK_DEV -1
+#define CBSLOT_UNK_FUNC -1
+
+
+struct cardbus_devfunc;
+
+/*
+ * struct cardbus_softc is the softc for cardbus card.
+ */
+struct cardbus_softc {
+ struct device sc_dev; /* fundamental device structure */
+
+ int sc_bus; /* cardbus bus number */
+ int sc_device; /* cardbus device number */
+ int sc_intrline; /* CardBus intrline */
+
+ bus_space_tag_t sc_iot; /* CardBus I/O space tag */
+ bus_space_tag_t sc_memt; /* CardBus MEM space tag */
+ bus_dma_tag_t sc_dmat; /* DMA tag */
+
+ cardbus_chipset_tag_t sc_cc; /* CardBus chipset */
+ cardbus_function_tag_t sc_cf; /* CardBus function */
+
+#if rbus
+ rbus_tag_t sc_rbus_iot; /* CardBus i/o rbus tag */
+ rbus_tag_t sc_rbus_memt; /* CardBus mem rbus tag */
+#endif
+
+ int sc_cacheline; /* cache line size */
+ int sc_lattimer; /* latency timer */
+ int sc_volt; /* applied Vcc voltage */
+#define PCCARD_33V 0x02
+#define PCCARD_XXV 0x04
+#define PCCARD_YYV 0x08
+ int sc_poweron_func;
+ struct cardbus_devfunc *sc_funcs; /* list of cardbus device functions */
+};
+
+
+/*
+ * struct cardbus_devfunc:
+ *
+ * This is the data deposit for each function of a CardBus device.
+ * This structure is used for memory or i/o space allocation and
+ * disallocation.
+ */
+typedef struct cardbus_devfunc {
+ cardbus_chipset_tag_t ct_cc;
+ cardbus_function_tag_t ct_cf;
+ struct cardbus_softc *ct_sc; /* pointer to the parent */
+ int ct_bus; /* bus number */
+ int ct_dev; /* device number */
+ int ct_func; /* function number */
+
+#if rbus
+ rbus_tag_t ct_rbus_iot; /* CardBus i/o rbus tag */
+ rbus_tag_t ct_rbus_memt; /* CardBus mem rbus tag */
+#endif
+
+ u_int32_t ct_bar[6]; /* Base Address Regs 0 to 6 */
+ u_int32_t ct_lc; /* Latency timer and cache line size */
+ /* u_int32_t ct_cisreg; */ /* CIS reg: is it needed??? */
+
+ struct device *ct_device; /* pointer to the device */
+
+ struct cardbus_devfunc *ct_next;
+
+ /* some data structure needed for tuple??? */
+} *cardbus_devfunc_t;
+
+
+/* XXX various things extracted from CIS */
+struct cardbus_cis_info {
+ int32_t manufacturer;
+ int32_t product;
+ char cis1_info_buf[256];
+ char* cis1_info[4];
+ struct cb_bar_info {
+ unsigned int flags;
+ unsigned int size;
+ } bar[7];
+ unsigned int funcid;
+ union {
+ struct {
+ char netid[6];
+ char netid_present;
+ char __filler;
+ } network;
+ } funce;
+};
+
+struct cardbus_attach_args {
+ int ca_unit;
+ cardbus_devfunc_t ca_ct;
+
+ bus_space_tag_t ca_iot; /* CardBus I/O space tag */
+ bus_space_tag_t ca_memt; /* CardBus MEM space tag */
+ bus_dma_tag_t ca_dmat; /* DMA tag */
+
+ u_int ca_device;
+ u_int ca_function;
+ cardbustag_t ca_tag;
+ cardbusreg_t ca_id;
+ cardbusreg_t ca_class;
+
+ /* interrupt information */
+ cardbus_intr_line_t ca_intrline;
+
+#if rbus
+ rbus_tag_t ca_rbus_iot; /* CardBus i/o rbus tag */
+ rbus_tag_t ca_rbus_memt; /* CardBus mem rbus tag */
+#endif
+
+ struct cardbus_cis_info ca_cis;
+};
+
+
+#define CARDBUS_ENABLE 1 /* enable the channel */
+#define CARDBUS_DISABLE 2 /* disable the channel */
+#define CARDBUS_RESET 4
+#define CARDBUS_CD 7
+# define CARDBUS_NOCARD 0
+# define CARDBUS_5V_CARD 0x01 /* XXX: It must not exist */
+# define CARDBUS_3V_CARD 0x02
+# define CARDBUS_XV_CARD 0x04
+# define CARDBUS_YV_CARD 0x08
+#define CARDBUS_IO_ENABLE 100
+#define CARDBUS_IO_DISABLE 101
+#define CARDBUS_MEM_ENABLE 102
+#define CARDBUS_MEM_DISABLE 103
+#define CARDBUS_BM_ENABLE 104 /* bus master */
+#define CARDBUS_BM_DISABLE 105
+
+#define CARDBUS_VCC_UC 0x0000
+#define CARDBUS_VCC_3V 0x0001
+#define CARDBUS_VCC_XV 0x0002
+#define CARDBUS_VCC_YV 0x0003
+#define CARDBUS_VCC_0V 0x0004
+#define CARDBUS_VCC_5V 0x0005 /* ??? */
+#define CARDBUS_VCCMASK 0x000f
+#define CARDBUS_VPP_UC 0x0000
+#define CARDBUS_VPP_VCC 0x0010
+#define CARDBUS_VPP_12V 0x0030
+#define CARDBUS_VPP_0V 0x0040
+#define CARDBUS_VPPMASK 0x00f0
+
+#define CARDBUSCF_DEV 0
+#define CARDBUSCF_DEV_DEFAULT -1
+#define CARDBUSCF_FUNCTION 1
+#define CARDBUSCF_FUNCTION_DEFAULT -1
+
+/*
+ * Locators devies that attach to 'cardbus', as specified to config.
+ */
+#define cardbuscf_dev cf_loc[CARDBUSCF_DEV]
+#define CARDBUS_UNK_DEV CARDBUSCF_DEV_DEFAULT
+
+#define cardbuscf_function cf_loc[CARDBUSCF_FUNCTION]
+#define CARDBUS_UNK_FUNCTION CARDBUSCF_FUNCTION_DEFAULT
+
+int cardbus_attach_card __P((struct cardbus_softc *));
+void cardbus_detach_card __P((struct cardbus_softc *));
+void *cardbus_intr_establish __P((cardbus_chipset_tag_t, cardbus_function_tag_t, cardbus_intr_handle_t irq, int level, int (*func) (void *), void *arg));
+void cardbus_intr_disestablish __P((cardbus_chipset_tag_t, cardbus_function_tag_t, void *handler));
+
+int cardbus_mapreg_map __P((struct cardbus_softc *, int, int, cardbusreg_t,
+ int, bus_space_tag_t *, bus_space_handle_t *, bus_addr_t *, bus_size_t *));
+int cardbus_mapreg_unmap __P((struct cardbus_softc *, int, int,
+ bus_space_tag_t, bus_space_handle_t, bus_size_t));
+
+int cardbus_save_bar __P((cardbus_devfunc_t));
+int cardbus_restore_bar __P((cardbus_devfunc_t));
+
+int cardbus_function_enable __P((struct cardbus_softc *, int function));
+int cardbus_function_disable __P((struct cardbus_softc *, int function));
+
+int cardbus_get_capability __P((cardbus_chipset_tag_t, cardbus_function_tag_t,
+ cardbustag_t, int, int *, cardbusreg_t *));
+
+#define Cardbus_function_enable(ct) cardbus_function_enable((ct)->ct_sc, (ct)->ct_func)
+#define Cardbus_function_disable(ct) cardbus_function_disable((ct)->ct_sc, (ct)->ct_func)
+
+
+
+#define Cardbus_mapreg_map(ct, reg, type, busflags, tagp, handlep, basep, sizep) \
+ cardbus_mapreg_map((ct)->ct_sc, (ct->ct_func), (reg), (type),\
+ (busflags), (tagp), (handlep), (basep), (sizep))
+#define Cardbus_mapreg_unmap(ct, reg, tag, handle, size) \
+ cardbus_mapreg_unmap((ct)->ct_sc, (ct->ct_func), (reg), (tag), (handle), (size))
+
+#define Cardbus_make_tag(ct) (*(ct)->ct_cf->cardbus_make_tag)((ct)->ct_cc, (ct)->ct_bus, (ct)->ct_dev, (ct)->ct_func)
+#define cardbus_make_tag(cc, cf, bus, device, function) ((cf)->cardbus_make_tag)((cc), (bus), (device), (function))
+
+#define Cardbus_free_tag(ct, tag) (*(ct)->ct_cf->cardbus_free_tag)((ct)->ct_cc, (tag))
+#define cardbus_free_tag(cc, cf, tag) (*(cf)->cardbus_free_tag)(cc, (tag))
+
+#define Cardbus_conf_read(ct, tag, offs) (*(ct)->ct_cf->cardbus_conf_read)((ct)->ct_cf, (tag), (offs))
+#define cardbus_conf_read(cc, cf, tag, offs) ((cf)->cardbus_conf_read)((cc), (tag), (offs))
+#define Cardbus_conf_write(ct, tag, offs, val) (*(ct)->ct_cf->cardbus_conf_write)((ct)->ct_cf, (tag), (offs), (val))
+#define cardbus_conf_write(cc, cf, tag, offs, val) ((cf)->cardbus_conf_write)((cc), (tag), (offs), (val))
+
+#endif /* !_DEV_CARDBUS_CARDBUSVAR_H_ */
diff --git a/sys/dev/cardbus/cardslot.c b/sys/dev/cardbus/cardslot.c
new file mode 100644
index 00000000000..1bed01f97b1
--- /dev/null
+++ b/sys/dev/cardbus/cardslot.c
@@ -0,0 +1,439 @@
+/* $OpenBSD: cardslot.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardslot.c,v 1.9 2000/03/22 09:35:06 haya Exp $ */
+
+/*
+ * Copyright (c) 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/kthread.h>
+
+#include <machine/bus.h>
+
+#include <dev/cardbus/cardslotvar.h>
+#include <dev/cardbus/cardbusvar.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciachip.h>
+#include <dev/ic/i82365var.h>
+
+#if defined CARDSLOT_DEBUG
+#define STATIC
+#define DPRINTF(a) printf a
+#else
+#define STATIC static
+#define DPRINTF(a)
+#endif
+
+
+
+STATIC void cardslotattach __P((struct device *, struct device *, void *));
+
+STATIC int cardslotmatch __P((struct device *, void *, void *));
+static void create_slot_manager __P((void *));
+static void cardslot_event_thread __P((void *arg));
+
+STATIC int cardslot_cb_print __P((void *aux, const char *pcic));
+static int cardslot_16_print __P((void *, const char *));
+static int cardslot_16_submatch __P((struct device *, void *,void *));
+
+struct cfattach cardslot_ca = {
+ sizeof(struct cardslot_softc), cardslotmatch, cardslotattach
+};
+
+#ifndef __NetBSD_Version__
+struct cfdriver cardslot_cd = {
+ NULL, "cardslot", DV_DULL
+};
+#endif
+
+
+STATIC int
+cardslotmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cardslot_attach_args *caa = aux;
+
+ if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) {
+ /* Neither CardBus nor 16-bit PCMCIA are defined. */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+STATIC void
+cardslotattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct cardslot_softc *sc = (struct cardslot_softc *)self;
+ struct cardslot_attach_args *caa = aux;
+
+ struct cbslot_attach_args *cba = caa->caa_cb_attach;
+ struct pcmciabus_attach_args *pa = caa->caa_16_attach;
+
+ struct cardbus_softc *csc;
+ struct pcmcia_softc *psc;
+
+ int card_attach_now;
+
+ sc->sc_slot = sc->sc_dev.dv_unit;
+ sc->sc_cb_softc = NULL;
+ sc->sc_16_softc = NULL;
+ SIMPLEQ_INIT(&sc->sc_events);
+ sc->sc_th_enable = 0;
+
+ printf(" slot %d flags %x\n", sc->sc_slot, sc->sc_dev.dv_cfdata->cf_flags);
+
+ DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname));
+ if (cba != NULL) {
+ if (NULL != (csc = (void *)config_found(self, cba, cardslot_cb_print))) {
+ /* cardbus found */
+ DPRINTF(("cardslotattach: found cardbus on %s\n", sc->sc_dev.dv_xname));
+ sc->sc_cb_softc = csc;
+ }
+ }
+
+ if (pa != NULL) {
+ if (NULL != (psc = (void *)config_found_sm(self, pa, cardslot_16_print,
+ cardslot_16_submatch))) {
+ /* pcmcia 16-bit bus found */
+ DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n"));
+ sc->sc_16_softc = psc;
+ /* XXX: dirty. This code should be removed to achieve MI */
+ caa->caa_ph->pcmcia = (struct device *)psc;
+ }
+ }
+
+ if (csc != NULL || psc != NULL)
+ kthread_create_deferred(create_slot_manager, (void *)sc);
+
+ card_attach_now = sc->sc_dev.dv_cfdata->cf_flags & 0x01;
+
+ if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) {
+ DPRINTF(("cardslotattach: CardBus card found\n"));
+ if (card_attach_now) {
+ if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
+ /* at least one function works */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING);
+ } else {
+ /* no functions work or this card is not known */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ }
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_CB);
+ } else {
+ /* attach deffered */
+ cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB);
+ }
+ }
+
+ if (psc && (psc->pct->card_detect)(psc->pch)) {
+ DPRINTF(("cardbusattach: 16-bit card found\n"));
+ if (card_attach_now) {
+ /* attach now */
+ pcmcia_card_attach((struct device *)sc->sc_16_softc);
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_16);
+ } else {
+ /* attach deffered */
+ cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16);
+ }
+ }
+}
+
+
+
+STATIC int
+cardslot_cb_print(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+ struct cbslot_attach_args *cba = aux;
+
+ if (pnp) {
+ printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus);
+ }
+
+ return UNCONF;
+}
+
+
+static int
+cardslot_16_submatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != 0)
+ return 0;
+
+ if (cf->cf_loc[0] == -1) {
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+ }
+
+ return 0;
+}
+
+
+
+static int
+cardslot_16_print(arg, pnp)
+ void *arg;
+ const char *pnp;
+{
+
+ if (pnp) {
+ printf("pcmciabus at %s", pnp);
+ }
+
+ return UNCONF;
+}
+
+
+
+
+static void
+create_slot_manager(arg)
+ void *arg;
+{
+ struct cardslot_softc *sc = (struct cardslot_softc *)arg;
+
+ sc->sc_th_enable = 1;
+
+ if (kthread_create(cardslot_event_thread, sc, &sc->sc_event_thread, "%s",
+ sc->sc_dev.dv_xname)) {
+ printf("%s: unable to create event thread for slot %d\n",
+ sc->sc_dev.dv_xname, sc->sc_slot);
+ panic("create_slot_manager");
+ }
+}
+
+
+
+
+/*
+ * void cardslot_event_throw(struct cardslot_softc *sc, int ev)
+ *
+ * This function throws an event to the event handler. If the state
+ * of a slot is changed, it should be noticed using this function.
+ */
+void
+cardslot_event_throw(sc, ev)
+ struct cardslot_softc *sc;
+ int ev;
+{
+ struct cardslot_event *ce;
+
+ DPRINTF(("cardslot_event_throw: an event %s comes\n",
+ ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" :
+ ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" :
+ ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" :
+ ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???"));
+
+ if (NULL == (ce = (struct cardslot_event *)malloc(sizeof (struct cardslot_event), M_TEMP, M_NOWAIT))) {
+ panic("cardslot_enevt");
+ }
+
+ ce->ce_type = ev;
+
+ {
+ int s = spltty();
+ SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q);
+ splx(s);
+ }
+
+ wakeup(&sc->sc_events);
+
+ return;
+}
+
+
+/*
+ * static void cardslot_event_thread(void *arg)
+ *
+ * This function is the main routine handing cardslot events such as
+ * insertions and removals.
+ *
+ */
+static void
+cardslot_event_thread(arg)
+ void *arg;
+{
+ struct cardslot_softc *sc = arg;
+ struct cardslot_event *ce;
+ int s;
+ static int antonym_ev[4] = {
+ CARDSLOT_EVENT_REMOVAL_16, CARDSLOT_EVENT_INSERTION_16,
+ CARDSLOT_EVENT_REMOVAL_CB, CARDSLOT_EVENT_INSERTION_CB
+ };
+
+ while (sc->sc_th_enable) {
+ s = spltty();
+ if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
+ splx(s);
+ (void) tsleep(&sc->sc_events, PWAIT, "cardslotev", 0);
+ continue;
+ }
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce, ce_q);
+ splx(s);
+
+ if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) {
+ /* Chattering supression */
+ s = spltty();
+ while (1) {
+ struct cardslot_event *ce1, *ce2;
+
+ if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
+ break;
+ }
+ if (ce1->ce_type != antonym_ev[ce->ce_type]) {
+ break;
+ }
+ if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL) {
+ break;
+ }
+ if (ce2->ce_type == ce->ce_type) {
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce1, ce_q);
+ free(ce1, M_TEMP);
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce2, ce_q);
+ free(ce2, M_TEMP);
+ }
+ }
+ splx(s);
+ }
+
+ switch (ce->ce_type) {
+ case CARDSLOT_EVENT_INSERTION_CB:
+ if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB)
+ || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) {
+ if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
+ /* A card has already been inserted and work. */
+ break;
+ }
+ }
+
+ if (sc->sc_cb_softc) {
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_CB);
+ if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
+ /* at least one function works */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING);
+ } else {
+ /* no functions work or this card is not known */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ }
+ } else {
+ panic("no cardbus on %s", sc->sc_dev.dv_xname);
+ }
+
+ break;
+
+ case CARDSLOT_EVENT_INSERTION_16:
+ if ((CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB)
+ || (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_16)) {
+ if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
+ /* A card has already been inserted and work. */
+ break;
+ }
+ }
+ if (sc->sc_16_softc) {
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_16);
+ if (pcmcia_card_attach((struct device *)sc->sc_16_softc)) {
+ /* Do not attach */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ } else {
+ /* working */
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_WORKING);
+ }
+ } else {
+ panic("no 16-bit pcmcia on %s", sc->sc_dev.dv_xname);
+ }
+
+ break;
+
+ case CARDSLOT_EVENT_REMOVAL_CB:
+ if (CARDSLOT_CARDTYPE(sc->sc_status) == CARDSLOT_STATUS_CARD_CB) {
+ /* CardBus card has not been inserted. */
+ if (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING) {
+ cardbus_detach_card(sc->sc_cb_softc);
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_CARD_NONE);
+ }
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE);
+ } else if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) {
+ /* Unknown card... */
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE);
+ }
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ break;
+
+ case CARDSLOT_EVENT_REMOVAL_16:
+ DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname));
+ if (CARDSLOT_CARDTYPE(sc->sc_status) != CARDSLOT_STATUS_CARD_16) {
+ /* 16-bit card has not been inserted. */
+ break;
+ }
+ if ((sc->sc_16_softc != NULL)
+ && (CARDSLOT_WORK(sc->sc_status) == CARDSLOT_STATUS_WORKING)) {
+ struct pcmcia_softc *psc = sc->sc_16_softc;
+
+ pcmcia_card_deactivate((struct device *)psc);
+ pcmcia_chip_socket_disable(psc->pct, psc->pch);
+ pcmcia_card_detach((struct device *)psc, DETACH_FORCE);
+ }
+ CARDSLOT_SET_CARDTYPE(sc->sc_status, CARDSLOT_STATUS_CARD_NONE);
+ CARDSLOT_SET_WORK(sc->sc_status, CARDSLOT_STATUS_NOTWORK);
+ break;
+
+ default:
+ panic("cardslot_event_thread: unknown event %d", ce->ce_type);
+ }
+ free(ce, M_TEMP);
+ }
+
+ sc->sc_event_thread = NULL;
+
+ /* In case parent is waiting for us to exit. */
+ wakeup(sc);
+
+ kthread_exit(0);
+}
diff --git a/sys/dev/cardbus/cardslotvar.h b/sys/dev/cardbus/cardslotvar.h
new file mode 100644
index 00000000000..be1e30c862a
--- /dev/null
+++ b/sys/dev/cardbus/cardslotvar.h
@@ -0,0 +1,125 @@
+/* $OpenBSD: cardslotvar.h,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: cardslotvar.h,v 1.5 2000/03/13 23:52:38 soren Exp $ */
+
+/*
+ * 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 the author.
+ * 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.
+ */
+
+#ifndef _DEV_CARDBUS_CARDSLOTVAR_H_
+#define _DEV_CARDBUS_CARDSLOTVAR_H_
+
+/* require sys/device.h */
+/* require sys/queue.h */
+
+struct cardslot_event;
+
+/*
+ * The data structure cardslot_attach_args is the attach argument for
+ * PCMCIA (including CardBus and 16-bit card) slot.
+ */
+struct cardslot_attach_args {
+ char *caa_busname;
+
+ int caa_slot;
+
+ /* for cardbus... */
+ struct cbslot_attach_args *caa_cb_attach;
+
+ /* for 16-bit pcmcia */
+ struct pcmciabus_attach_args *caa_16_attach;
+
+ /* XXX: for 16-bit pcmcia. dirty! This should be removed to achieve MI. */
+ struct pcic_handle *caa_ph;
+};
+
+
+/*
+ * The data structure cardslot_attach_args is the attach argument for
+ * PCMCIA (including CardBus and 16-bit card) slot.
+ */
+struct cardslot_softc {
+ struct device sc_dev;
+
+ int sc_slot; /* slot number */
+ int sc_status; /* the status of slot */
+
+ struct cardbus_softc *sc_cb_softc;
+ struct pcmcia_softc *sc_16_softc;
+
+ struct proc *sc_event_thread;
+ int sc_th_enable; /* true if the thread is enabled */
+
+ /* An event queue for the thread which processes slot state events. */
+
+ SIMPLEQ_HEAD(, cardslot_event) sc_events;
+};
+
+#define CARDSLOT_STATUS_CARD_MASK 0x07
+#define CARDSLOT_STATUS_CARD_NONE 0x00 /* NO card inserted */
+#define CARDSLOT_STATUS_CARD_16 0x01 /* 16-bit pcmcia card inserted */
+#define CARDSLOT_STATUS_CARD_CB 0x02 /* CardBus pcmcia card inserted */
+#define CARDSLOT_STATUS_UNKNOWN 0x07 /* Unknown card inserted */
+
+#define CARDSLOT_CARDTYPE(x) ((x) & CARDSLOT_STATUS_CARD_MASK)
+#define CARDSLOT_SET_CARDTYPE(x, type) \
+ do {(x) &= ~CARDSLOT_STATUS_CARD_MASK;\
+ (x) |= (CARDSLOT_STATUS_CARD_MASK & (type));} while(0)
+
+#define CARDSLOT_STATUS_WORK_MASK 0x08
+#define CARDSLOT_STATUS_WORKING 0x08 /* at least one function works */
+#define CARDSLOT_STATUS_NOTWORK 0x00 /* no functions are working */
+
+#define CARDSLOT_WORK(x) ((x) & CARDSLOT_STATUS_WORK_MASK)
+#define CARDSLOT_SET_WORK(x, type) \
+ do {(x) &= ~CARDSLOT_STATUS_WORK_MASK;\
+ (x) |= (CARDSLOT_STATUS_WORK_MASK & (type));} while(0)
+
+
+struct cardslot_event {
+ SIMPLEQ_ENTRY(cardslot_event) ce_q;
+
+ int ce_type;
+};
+
+typedef struct cardslot_softc *cardslot_t;
+
+/* ce_type */
+#define CARDSLOT_EVENT_INSERTION_16 0
+#define CARDSLOT_EVENT_REMOVAL_16 1
+
+#define CARDSLOT_EVENT_INSERTION_CB 2
+#define CARDSLOT_EVENT_REMOVAL_CB 3
+
+#define IS_CARDSLOT_INSERT_REMOVE_EV(x) (0 <= (x) && (x) <= 3)
+
+void cardslot_event_throw __P((cardslot_t cs, int ev));
+
+#endif /* !_DEV_CARDBUS_CARDSLOTVAR_H_ */
diff --git a/sys/dev/cardbus/files.cardbus b/sys/dev/cardbus/files.cardbus
new file mode 100644
index 00000000000..f3dc58bacb1
--- /dev/null
+++ b/sys/dev/cardbus/files.cardbus
@@ -0,0 +1,51 @@
+# $OpenBSD: files.cardbus,v 1.1 2000/04/08 05:50:52 aaron Exp $
+# $NetBSD: files.cardbus,v 1.8 2000/01/26 06:37:24 thorpej Exp $
+#
+# files.cardbus
+#
+
+device cardslot: cbbus, pcmciabus
+attach cardslot at pcmciaslot
+file dev/cardbus/cardslot.c cardslot needs-flag
+
+device cardbus {[dev = -1], [function = -1]}
+attach cardbus at cbbus
+file dev/cardbus/cardbus.c cardbus needs-flag
+file dev/cardbus/cardbus_map.c cardbus
+file dev/cardbus/cardbus_exrom.c cardbus
+file dev/cardbus/rbus.c cardbus
+
+#
+# 3Com 3C575TX, 3C575BTX, and 3C575CTX
+#
+attach xl at cardbus with xl_cardbus
+file dev/cardbus/if_xl_cardbus.c xl_cardbus
+
+#
+# Intel PRO/100 8255x based CardBus cards.
+#
+#attach fxp at cardbus with fxp_cardbus
+#file dev/cardbus/if_fxp_cardbus.c fxp_cardbus
+
+#
+#
+#attach com at cardbus with com_cardbus
+#file dev/cardbus/com_cardbus.c com_cardbus
+
+#
+# DECchip 21143 and clones.
+#
+#attach tlp at cardbus with tlp_cardbus
+#file dev/cardbus/if_tlp_cardbus.c tlp_cardbus
+
+#
+# OHCI USB controller
+#
+#attach ohci at cardbus with ohci_cardbus
+#file dev/cardbus/ohci_cardbus.c ohci_cardbus
+
+#
+# Adaptec ADP-1480 SCSI controller
+#
+#attach ahc at cardbus with ahc_cardbus: ahc_seeprom, smc93cx6
+#file dev/cardbus/ahc_cardbus.c ahc_cardbus
diff --git a/sys/dev/cardbus/if_xl_cardbus.c b/sys/dev/cardbus/if_xl_cardbus.c
new file mode 100644
index 00000000000..d24fd484f94
--- /dev/null
+++ b/sys/dev/cardbus/if_xl_cardbus.c
@@ -0,0 +1,426 @@
+/* $OpenBSD: if_xl_cardbus.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: if_xl_cardbus.c,v 1.13 2000/03/07 00:32:52 mycroft Exp $ */
+
+/*
+ * CardBus specific routines for 3Com 3C575-family CardBus ethernet adapter
+ *
+ * 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 the author.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY HAYAKAWA KOICHI ``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 TAKESHI OHASHI 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.
+ *
+ *
+ */
+
+/* #define XL_DEBUG 4 */ /* define to report infomation for debugging */
+
+#define XL_POWER_STATIC /* do not use enable/disable functions */
+ /* I'm waiting elinkxl.c uses
+ sc->enable and sc->disable
+ functions. */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/cardbus/cardbusvar.h>
+#include <dev/cardbus/cardbusdevs.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/xlreg.h>
+
+#if defined DEBUG && !defined XL_DEBUG
+#define XL_DEBUG
+#endif
+
+#if defined XL_DEBUG
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
+
+#define CARDBUS_3C575BTX_FUNCSTAT_PCIREG CARDBUS_BASE2_REG /* means 0x18 */
+#define XL_CB_INTR 4 /* intr acknowledge reg. CardBus only */
+#define XL_CB_INTR_ACK 0x8000 /* intr acknowledge bit */
+
+int xl_cardbus_match __P((struct device *, void *, void *));
+void xl_cardbus_attach __P((struct device *, struct device *,void *));
+int xl_cardbus_detach __P((struct device *, int));
+void xl_cardbus_intr_ack __P((struct xl_softc *));
+
+#if !defined XL_POWER_STATIC
+int xl_cardbus_enable __P((struct xl_softc *sc));
+void xl_cardbus_disable __P((struct xl_softc *sc));
+#endif /* !defined XL_POWER_STATIC */
+
+struct xl_cardbus_softc {
+ struct xl_softc sc_softc;
+
+ cardbus_devfunc_t sc_ct;
+ int sc_intrline;
+ u_int8_t sc_cardbus_flags;
+#define XL_REATTACH 0x01
+#define XL_ABSENT 0x02
+ u_int8_t sc_cardtype;
+#define XL_3C575 1
+#define XL_3C575B 2
+
+ /* CardBus function status space. 575B requests it. */
+ bus_space_tag_t sc_funct;
+ bus_space_handle_t sc_funch;
+ bus_size_t sc_funcsize;
+
+ bus_size_t sc_mapsize; /* the size of mapped bus space region */
+};
+
+struct cfattach xl_cardbus_ca = {
+ sizeof(struct xl_cardbus_softc), xl_cardbus_match,
+ xl_cardbus_attach, xl_cardbus_detach
+};
+
+const struct xl_cardbus_product {
+ u_int32_t ecp_prodid; /* CardBus product ID */
+ int ecp_flags; /* initial softc flags */
+ pcireg_t ecp_csr; /* PCI CSR flags */
+ int ecp_cardtype; /* card type */
+ const char *ecp_name; /* device name */
+} xl_cardbus_products[] = {
+ { CARDBUS_PRODUCT_3COM_3C575TX,
+ /* XL_CONF_MII, */ 0,
+ CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MASTER_ENABLE,
+ XL_3C575,
+ "3c575-TX Ethernet" },
+
+ { CARDBUS_PRODUCT_3COM_3C575BTX,
+ /* XL_CONF_90XB|XL_CONF_MII, */ 0,
+ CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE |
+ CARDBUS_COMMAND_MASTER_ENABLE,
+ XL_3C575B,
+ "3c575B-TX Ethernet" },
+
+ { CARDBUS_PRODUCT_3COM_3CCFE575CT,
+ /* XL_CONF_90XB|XL_CONF_MII, */ 0,
+ CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE |
+ CARDBUS_COMMAND_MASTER_ENABLE,
+ XL_3C575B,
+ "3c575C-TX Ethernet" },
+
+ { 0,
+ 0,
+ 0,
+ NULL },
+};
+
+const struct xl_cardbus_product *xl_cardbus_lookup
+ __P((const struct cardbus_attach_args *));
+
+const struct xl_cardbus_product *
+xl_cardbus_lookup(ca)
+ const struct cardbus_attach_args *ca;
+{
+ const struct xl_cardbus_product *ecp;
+
+ if (CARDBUS_VENDOR(ca->ca_id) != CARDBUS_VENDOR_3COM)
+ return (NULL);
+
+ for (ecp = xl_cardbus_products; ecp->ecp_name != NULL; ecp++)
+ if (CARDBUS_PRODUCT(ca->ca_id) == ecp->ecp_prodid)
+ return (ecp);
+ return (NULL);
+}
+
+int
+xl_cardbus_match(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cardbus_attach_args *ca = aux;
+
+ if (xl_cardbus_lookup(ca) != NULL)
+ return (1);
+
+ return (0);
+}
+
+void
+xl_cardbus_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct xl_cardbus_softc *psc = (void *)self;
+ struct xl_softc *sc = &psc->sc_softc;
+ struct cardbus_attach_args *ca = aux;
+ cardbus_devfunc_t ct = ca->ca_ct;
+ cardbus_chipset_tag_t cc = ct->ct_cc;
+ cardbus_function_tag_t cf = ct->ct_cf;
+ cardbusreg_t iob, command, bhlc;
+ const struct xl_cardbus_product *ecp;
+ bus_space_handle_t ioh;
+ bus_addr_t adr;
+
+ if (Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, 0,
+ &sc->xl_btag, &ioh, &adr, &psc->sc_mapsize)) {
+ printf(": can't map i/o space\n");
+ return;
+ }
+
+ ecp = xl_cardbus_lookup(ca);
+ if (ecp == NULL) {
+ printf("\n");
+ panic("xl_cardbus_attach: impossible");
+ }
+
+ printf(": 3Com %s", ecp->ecp_name);
+
+#if 0
+#if !defined XL_POWER_STATIC
+ sc->enable = xl_cardbus_enable;
+ sc->disable = xl_cardbus_disable;
+#else
+ sc->enable = NULL;
+ sc->disable = NULL;
+#endif
+ sc->enabled = 1;
+ sc->sc_dmat = ca->ca_dmat;
+ sc->xl_conf = ecp->ecp_flags;
+#endif
+ sc->xl_bustype = XL_BUS_CARDBUS;
+
+ iob = adr;
+ sc->xl_bhandle = ioh;
+
+#if rbus
+#else
+ (ct->ct_cf->cardbus_io_open)(cc, 0, iob, iob + 0x40);
+#endif
+ (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
+
+ command = cardbus_conf_read(cc, cf, ca->ca_tag,
+ CARDBUS_COMMAND_STATUS_REG);
+ command |= ecp->ecp_csr;
+ psc->sc_cardtype = ecp->ecp_cardtype;
+
+ if (psc->sc_cardtype == XL_3C575B) {
+ /* Map CardBus function status window. */
+ if (Cardbus_mapreg_map(ct, CARDBUS_3C575BTX_FUNCSTAT_PCIREG,
+ CARDBUS_MAPREG_TYPE_MEM, 0, &psc->sc_funct,
+ &psc->sc_funch, 0, &psc->sc_funcsize)) {
+ printf("%s: unable to map function status window\n",
+ self->dv_xname);
+ return;
+ }
+
+ /*
+ * Make sure CardBus brigde can access memory space. Usually
+ * memory access is enabled by BIOS, but some BIOSes do not
+ * enable it.
+ */
+ (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
+
+ /* Setup interrupt acknowledge hook */
+ sc->intr_ack = xl_cardbus_intr_ack;
+ }
+
+ (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
+ cardbus_conf_write(cc, cf, ca->ca_tag, CARDBUS_COMMAND_STATUS_REG,
+ command);
+
+ /*
+ * set latency timmer
+ */
+ bhlc = cardbus_conf_read(cc, cf, ca->ca_tag, CARDBUS_BHLC_REG);
+ if (CARDBUS_LATTIMER(bhlc) < 0x20) {
+ /* at least the value of latency timer should 0x20. */
+ DPRINTF(("if_xl_cardbus: lattimer 0x%x -> 0x20\n",
+ CARDBUS_LATTIMER(bhlc)));
+ bhlc &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
+ bhlc |= (0x20 << CARDBUS_LATTIMER_SHIFT);
+ cardbus_conf_write(cc, cf, ca->ca_tag, CARDBUS_BHLC_REG, bhlc);
+ }
+
+ psc->sc_ct = ca->ca_ct;
+ psc->sc_intrline = ca->ca_intrline;
+
+#if defined XL_POWER_STATIC
+ /* Map and establish the interrupt. */
+
+ sc->xl_intrhand = cardbus_intr_establish(cc, cf, ca->ca_intrline,
+ IPL_NET, xl_intr, psc);
+
+ if (sc->xl_intrhand == NULL) {
+ printf(": couldn't establish interrupt");
+ printf(" at %d", ca->ca_intrline);
+ printf("\n");
+ return;
+ }
+ printf(": irq %d", ca->ca_intrline);
+#endif
+
+ bus_space_write_2(sc->xl_btag, sc->xl_bhandle, XL_COMMAND, XL_CMD_RESET);
+ delay(400);
+ {
+ int i = 0;
+ while (bus_space_read_2(sc->xl_btag, sc->xl_bhandle, XL_STATUS) &
+ XL_STAT_CMDBUSY) {
+ if (++i > 10000) {
+ printf("ex: timeout %x\n",
+ bus_space_read_2(sc->xl_btag, sc->xl_bhandle,
+ XL_STATUS));
+ printf("ex: addr %x\n",
+ cardbus_conf_read(cc, cf, ca->ca_tag,
+ CARDBUS_BASE0_REG));
+ return; /* emergency exit */
+ }
+ }
+ }
+
+ xl_attach(sc);
+
+ if (psc->sc_cardtype == XL_3C575B)
+ bus_space_write_4(psc->sc_funct, psc->sc_funch,
+ XL_CB_INTR, XL_CB_INTR_ACK);
+
+#if !defined XL_POWER_STATIC
+ cardbus_function_disable(psc->sc_ct);
+ sc->enabled = 0;
+#endif
+}
+
+void
+xl_cardbus_intr_ack(sc)
+ struct xl_softc *sc;
+{
+ struct xl_cardbus_softc *psc = (struct xl_cardbus_softc *)sc;
+
+ bus_space_write_4(psc->sc_funct, psc->sc_funch, XL_CB_INTR,
+ XL_CB_INTR_ACK);
+}
+
+int
+xl_cardbus_detach(self, arg)
+ struct device *self;
+ int arg;
+{
+ struct xl_cardbus_softc *psc = (void *)self;
+ struct xl_softc *sc = &psc->sc_softc;
+ struct cardbus_devfunc *ct = psc->sc_ct;
+ int rv = 0;
+
+#if defined(DIAGNOSTIC)
+ if (ct == NULL) {
+ panic("%s: data structure lacks\n", sc->sc_dev.dv_xname);
+ }
+#endif
+
+#if 0
+ rv = xl_detach(sc);
+#endif
+ if (rv == 0) {
+ /*
+ * Unhook the interrupt handler.
+ */
+ cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->xl_intrhand);
+
+ if (psc->sc_cardtype == XL_3C575B) {
+ Cardbus_mapreg_unmap(ct,
+ CARDBUS_3C575BTX_FUNCSTAT_PCIREG,
+ psc->sc_funct, psc->sc_funch, psc->sc_funcsize);
+ }
+
+ Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->xl_btag,
+ sc->xl_bhandle, psc->sc_mapsize);
+ }
+ return (rv);
+}
+
+#if !defined XL_POWER_STATIC
+int
+xl_cardbus_enable(sc)
+ struct xl_softc *sc;
+{
+ struct xl_cardbus_softc *csc = (struct xl_cardbus_softc *)sc;
+ cardbus_function_tag_t cf = csc->sc_ct->ct_cf;
+ cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc;
+
+ Cardbus_function_enable(csc->sc_ct);
+ cardbus_restore_bar(csc->sc_ct);
+
+ sc->xl_intrhand = cardbus_intr_establish(cc, cf, csc->sc_intrline,
+ IPL_NET, xl_intr, sc);
+ if (NULL == sc->xl_intrhand) {
+ printf("%s: couldn't establish interrupt\n",
+ sc->sc_dev.dv_xname);
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+xl_cardbus_disable(sc)
+ struct xl_softc *sc;
+{
+ struct xl_cardbus_softc *csc = (struct xl_cardbus_softc *)sc;
+ cardbus_function_tag_t cf = csc->sc_ct->ct_cf;
+ cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc;
+
+ cardbus_save_bar(csc->sc_ct);
+
+ Cardbus_function_disable(csc->sc_ct);
+
+ cardbus_intr_disestablish(cc, cf, sc->xl_intrhand);
+}
+#endif /* XL_POWER_STATIC */
diff --git a/sys/dev/cardbus/rbus.c b/sys/dev/cardbus/rbus.c
new file mode 100644
index 00000000000..5ca2b2529a4
--- /dev/null
+++ b/sys/dev/cardbus/rbus.c
@@ -0,0 +1,387 @@
+/* $OpenBSD: rbus.c,v 1.1 2000/04/08 05:50:52 aaron Exp $ */
+/* $NetBSD: rbus.c,v 1.3 1999/11/06 06:20:53 soren Exp $ */
+/*
+ * 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.
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/extent.h>
+
+#include <machine/bus.h>
+
+#include <dev/cardbus/rbus.h>
+
+/* #define RBUS_DEBUG */
+
+#if defined RBUS_DEBUG
+#define STATIC
+#define DPRINTF(a) printf a
+#define DDELAY(x) delay((x)*1000*1000)
+#else
+#define STATIC static
+#define DPRINTF(a)
+#endif
+
+
+
+static rbus_tag_t rbus_new_body __P((bus_space_tag_t bt, rbus_tag_t parent,
+ struct extent *ex, bus_addr_t start,
+ bus_addr_t end, bus_addr_t offset,
+ int flags));
+
+
+int
+rbus_space_alloc(rbt, addr, size, mask, align, flags, addrp, bshp)
+ rbus_tag_t rbt;
+ bus_addr_t addr;
+ bus_size_t size;
+ bus_addr_t mask, align;
+ int flags;
+ bus_addr_t *addrp;
+ bus_space_handle_t *bshp;
+{
+ return rbus_space_alloc_subregion(rbt, rbt->rb_start, rbt->rb_end, addr,
+ size, mask, align, flags, addrp, bshp);
+}
+
+
+
+
+int
+rbus_space_alloc_subregion(rbt, substart, subend, addr, size, mask, align, flags, addrp, bshp)
+ rbus_tag_t rbt;
+ bus_addr_t addr;
+ bus_addr_t substart;
+ bus_addr_t subend;
+ bus_size_t size;
+ bus_addr_t mask, align;
+ int flags;
+ bus_addr_t *addrp;
+ bus_space_handle_t *bshp;
+{
+ bus_addr_t decodesize = mask + 1;
+ bus_addr_t boundary, search_addr;
+ int val = 0;
+ bus_addr_t result;
+ int exflags = EX_FAST | EX_NOWAIT;
+
+ DPRINTF(("rbus_space_alloc: addr %lx, size %lx, mask %lx, align %lx\n",
+ addr, size, mask, align));
+
+ addr += rbt->rb_offset;
+
+ if (mask == 0) {
+ /* FULL Decode */
+ decodesize = 0;
+ }
+
+ if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
+ return rbus_space_alloc(rbt->rb_parent, addr, size, mask, align, flags,
+ addrp, bshp);
+ } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
+ rbt->rb_flags == RBUS_SPACE_DEDICATE) {
+ /* rbt has its own sh_extent */
+
+ /* sanity check: the subregion [substart, subend] should be
+ smaller than the region included in sh_extent */
+ if (substart < rbt->rb_ext->ex_start || subend > rbt->rb_ext->ex_end) {
+ return 1;
+ }
+
+ if (decodesize == align) {
+ if(extent_alloc_subregion(rbt->rb_ext, substart, subend, size, align, 0,
+ exflags, (u_long *)&result)) {
+ return 1;
+ }
+ } else if (decodesize == 0) {
+ /* maybe, the resister is overflowed. */
+
+ if (extent_alloc_subregion(rbt->rb_ext, addr, addr + size, size,
+ 0, 0, exflags, (u_long *)&result)) {
+ return 1;
+ }
+ } else {
+
+ boundary = decodesize > align ? decodesize : align;
+
+ search_addr = (substart & ~(boundary - 1)) + addr;
+
+ if (search_addr < substart) {
+ search_addr += boundary;
+ }
+
+ for (; search_addr + size <= subend; search_addr += boundary) {
+ val = extent_alloc_subregion(rbt->rb_ext,search_addr, search_addr+size,
+ size, align, 0, exflags, (u_long *)&result);
+ if (val == 0) {
+ break;
+ }
+ }
+ if (val) {
+ return 1;
+ }
+ }
+
+ if(md_space_map(rbt->rb_bt, result, size, flags, bshp)) {
+ /* map failed */
+ extent_free(rbt->rb_ext, result, size, exflags);
+ return 1;
+ }
+
+ if (addrp != NULL) {
+ *addrp = result + rbt->rb_offset;
+ }
+ return 0;
+
+ } else {
+ /* error!! */
+ return 1;
+ }
+ return 1;
+}
+
+
+
+
+
+int
+rbus_space_free(rbt, bsh, size, addrp)
+ rbus_tag_t rbt;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+ bus_addr_t *addrp;
+{
+ int exflags = EX_FAST | EX_NOWAIT;
+ bus_addr_t addr;
+ int status = 1;
+
+ if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
+ status = rbus_space_free(rbt->rb_parent, bsh, size, &addr);
+ } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
+ rbt->rb_flags == RBUS_SPACE_DEDICATE) {
+ md_space_unmap(rbt->rb_bt, bsh, size, &addr);
+
+ extent_free(rbt->rb_ext, addr, size, exflags);
+
+ status = 0;
+ } else {
+ /* error. INVALID rbustag */
+ status = 1;
+ }
+ if (addrp != NULL) {
+ *addrp = addr;
+ }
+ return status;
+}
+
+
+
+/*
+ * static rbus_tag_t
+ * rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
+ * struct extent *ex, bus_addr_t start, bus_size_t end,
+ * bus_addr_t offset, int flags)
+ *
+ */
+static rbus_tag_t
+rbus_new_body(bt, parent, ex, start, end, offset, flags)
+ bus_space_tag_t bt;
+ rbus_tag_t parent;
+ struct extent *ex;
+ bus_addr_t start, end, offset;
+ int flags;
+{
+ rbus_tag_t rb;
+
+ /* sanity check */
+ if (parent != NULL) {
+ if (start < parent->rb_start || end > parent->rb_end) {
+ /* out of range: [start, size] should be containd in parent space */
+ return 0;
+ /* Should I invoke panic? */
+ }
+ }
+
+ if (NULL == (rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF,
+ M_NOWAIT))) {
+ panic("no memory for rbus instance");
+ }
+
+ rb->rb_bt = bt;
+ rb->rb_parent = parent;
+ rb->rb_start = start;
+ rb->rb_end = end;
+ rb->rb_offset = offset;
+ rb->rb_flags = flags;
+ rb->rb_ext = ex;
+
+ DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n", start, end,
+ flags == RBUS_SPACE_SHARE ? "share" :
+ flags == RBUS_SPACE_DEDICATE ? "dedicated" :
+ flags == RBUS_SPACE_ASK_PARENT ? "parent" : "invalid",
+ ex != NULL ? ex->ex_name : "noname"));
+
+ return rb;
+}
+
+
+
+/*
+ * rbus_tag_t rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t
+ * size, bus_addr_t offset, int flags)
+ *
+ * This function makes a new child rbus instance.
+ */
+rbus_tag_t
+rbus_new(parent, start, size, offset, flags)
+ rbus_tag_t parent;
+ bus_addr_t start;
+ bus_size_t size;
+ bus_addr_t offset;
+ int flags;
+{
+ rbus_tag_t rb;
+ struct extent *ex = NULL;
+ bus_addr_t end = start + size;
+
+ if (flags == RBUS_SPACE_SHARE) {
+ ex = parent->rb_ext;
+ } else if (flags == RBUS_SPACE_DEDICATE) {
+ if (NULL == (ex = extent_create("rbus", start, end, M_DEVBUF, NULL, 0,
+ EX_NOCOALESCE|EX_NOWAIT))) {
+ free(rb, M_DEVBUF);
+ return NULL;
+ }
+ } else if (flags == RBUS_SPACE_ASK_PARENT) {
+ ex = NULL;
+ } else {
+ /* Invalid flag */
+ return 0;
+ }
+
+ rb = rbus_new_body(parent->rb_bt, parent, ex, start, start + size,
+ offset, flags);
+
+ if ((rb == NULL) && (flags == RBUS_SPACE_DEDICATE)) {
+ extent_destroy(ex);
+ }
+
+ return rb;
+}
+
+
+
+
+/*
+ * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t,
+ * bus_size_t, bus_addr_t offset)
+ *
+ * This function makes a root rbus instance.
+ */
+rbus_tag_t
+rbus_new_root_delegate(bt, start, size, offset)
+ bus_space_tag_t bt;
+ bus_addr_t start;
+ bus_size_t size;
+ bus_addr_t offset;
+{
+ rbus_tag_t rb;
+ struct extent *ex;
+
+ if (NULL == (ex = extent_create("rbus root", start, start + size, M_DEVBUF,
+ NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
+ return NULL;
+ }
+
+ rb = rbus_new_body(bt, NULL, ex, start, start + size, offset,
+ RBUS_SPACE_DEDICATE);
+
+ if (rb == NULL) {
+ extent_destroy(ex);
+ }
+
+ return rb;
+}
+
+
+
+/*
+ * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *,
+ * bus_addr_t, bus_size_t, bus_addr_t offset)
+ *
+ * This function makes a root rbus instance.
+ */
+rbus_tag_t
+rbus_new_root_share(bt, ex, start, size, offset)
+ bus_space_tag_t bt;
+ struct extent *ex;
+ bus_addr_t start;
+ bus_size_t size;
+ bus_addr_t offset;
+{
+ /* sanity check */
+ if (start < ex->ex_start || start + size > ex->ex_end) {
+ /* out of range: [start, size] should be containd in parent space */
+ return 0;
+ /* Should I invoke panic? */
+ }
+
+ return rbus_new_body(bt, NULL, ex, start, start + size, offset,
+ RBUS_SPACE_SHARE);
+}
+
+
+
+
+
+/*
+ * int rbus_delete (rbus_tag_t rb)
+ *
+ * This function deletes the rbus structure pointed in the argument.
+ */
+int
+rbus_delete(rb)
+ rbus_tag_t rb;
+{
+ DPRINTF(("rbus_delete called [%s]\n",
+ rb->rb_ext != NULL ? rb->rb_ext->ex_name : "noname"));
+ if (rb->rb_flags == RBUS_SPACE_DEDICATE) {
+ extent_destroy(rb->rb_ext);
+ }
+
+ free(rb, M_DEVBUF);
+
+ return 0;
+}
diff --git a/sys/dev/cardbus/rbus.h b/sys/dev/cardbus/rbus.h
new file mode 100644
index 00000000000..89a6ac17d6f
--- /dev/null
+++ b/sys/dev/cardbus/rbus.h
@@ -0,0 +1,166 @@
+/* $OpenBSD: rbus.h,v 1.1 2000/04/08 05:50:53 aaron Exp $ */
+/* $NetBSD: rbus.h,v 1.3 1999/12/15 12:28:55 kleink Exp $ */
+/*
+ * 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 the author.
+ * 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.
+ */
+
+#ifndef _DEV_CARDBUS_RBUS_H_
+#define _DEV_CARDBUS_RBUS_H_
+
+/*
+ * This file defines rbus (pseudo) class
+ *
+ * What is rbus?
+ *
+ * Ths rbus is a recursive bus-space administrator. This means a
+ * parent bus-space administrator, which usually belongs to a bus
+ * bridge, makes some child bus-space administorators and gives
+ * (restricted) bus-space for children. There are a root bus-space
+ * administrator which maintains whole bus-space.
+ *
+ * Why recursive?
+ *
+ * The recursive bus-space administration has two virtues. The
+ * former is this modelling matches the actual memory and io space
+ * management of bridge devices well. The latter is the rbus is
+ * distributed management system, so it matches well with
+ * multi-thread kernel.
+ *
+ * Abstraction
+ *
+ * The rbus models bus-to-bus bridge into three way: dedicate, share
+ * and slave. Dedicate means that the bridge has dedicate bus space.
+ * Share means that the bridge has bus space, but this bus space is
+ * shared with other bus bridges. Slave means the bus bridge which
+ * does not have it own bus space and ask a parent bus bridge for bus
+ * space when a client requests bus space to the bridge.
+ */
+
+
+/* require sys/extent.h */
+/* require machine/bus.h */
+
+#define rbus 1
+
+
+struct extent;
+
+
+/*
+ * General rule
+ *
+ * 1) When a rbustag has no space for child (it means rb_extent is
+ * NULL), ask bus-space for parent through rb_parent.
+ *
+ * 2) When a rbustag has its own space (whether shared or dedicated),
+ * allocate from rb_ext.
+ */
+struct rbustag {
+ bus_space_tag_t rb_bt;
+ struct rbustag *rb_parent;
+ struct extent *rb_ext;
+ bus_addr_t rb_start;
+ bus_addr_t rb_end;
+ bus_addr_t rb_offset;
+#if notyet
+ int (*rb_space_alloc) __P((struct rbustag *,
+ bus_addr_t start, bus_addr_t end,
+ bus_addr_t addr, bus_size_t size,
+ bus_addr_t mask, bus_addr_t align,
+ int flags,
+ bus_addr_t *addrp, bus_space_handle_t *bshp));
+ int (*rbus_space_free) __P((struct rbustag *, bus_space_handle_t,
+ bus_size_t size, bus_addr_t *addrp));
+#endif
+ int rb_flags;
+#define RBUS_SPACE_INVALID 0x00
+#define RBUS_SPACE_SHARE 0x01
+#define RBUS_SPACE_DEDICATE 0x02
+#define RBUS_SPACE_MASK 0x03
+#define RBUS_SPACE_ASK_PARENT 0x04
+ /* your own data below */
+ void *rb_md;
+};
+
+typedef struct rbustag *rbus_tag_t;
+
+
+
+
+/*
+ * These functions sugarcoat rbus interface to make rbus being used
+ * easier. These functions should be member functions of rbus
+ * `class'.
+ */
+int rbus_space_alloc __P((rbus_tag_t,
+ bus_addr_t addr, bus_size_t size, bus_addr_t mask,
+ bus_addr_t align, int flags,
+ bus_addr_t *addrp, bus_space_handle_t *bshp));
+
+int rbus_space_alloc_subregion __P((rbus_tag_t,
+ bus_addr_t start, bus_addr_t end,
+ bus_addr_t addr, bus_size_t size,
+ bus_addr_t mask, bus_addr_t align,
+ int flags,
+ bus_addr_t *addrp, bus_space_handle_t *bshp));
+
+int rbus_space_free __P((rbus_tag_t, bus_space_handle_t, bus_size_t size,
+ bus_addr_t *addrp));
+
+
+/*
+ * These functions create rbus instance. These functions are
+ * so-called-as a constructor of rbus.
+ *
+ * rbus_new is a constructor which make an rbus instance from a parent
+ * rbus.
+ */
+rbus_tag_t rbus_new __P((rbus_tag_t parent, bus_addr_t start, bus_size_t size,
+ bus_addr_t offset, int flags));
+
+rbus_tag_t rbus_new_root_delegate __P((bus_space_tag_t, bus_addr_t, bus_size_t,
+ bus_addr_t offset));
+rbus_tag_t rbus_new_root_share __P((bus_space_tag_t, struct extent *,
+ bus_addr_t, bus_size_t,bus_addr_t offset));
+
+/*
+ * This function release bus-space used by the argument. This
+ * function is so-called-as a destructor.
+ */
+int rbus_delete __P((rbus_tag_t));
+
+
+/*
+ * Machine-dependent definitions.
+ */
+#include <machine/rbus_machdep.h>
+
+#endif /* !_DEV_CARDBUS_RBUS_H_ */
diff --git a/sys/dev/ic/i82365.c b/sys/dev/ic/i82365.c
index 8dacec68c01..b2d74edd8a7 100644
--- a/sys/dev/ic/i82365.c
+++ b/sys/dev/ic/i82365.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82365.c,v 1.10 2000/02/02 16:49:05 fgsch Exp $ */
+/* $OpenBSD: i82365.c,v 1.11 2000/04/08 05:50:50 aaron Exp $ */
/* $NetBSD: i82365.c,v 1.10 1998/06/09 07:36:55 thorpej Exp $ */
/*
@@ -104,6 +104,9 @@ void pcic_queue_event __P((struct pcic_handle *, int));
void pcic_wait_ready __P((struct pcic_handle *));
+u_int8_t st_pcic_read __P((struct pcic_handle *, int));
+void st_pcic_write __P((struct pcic_handle *, int, u_int8_t));
+
struct cfdriver pcic_cd = {
NULL, "pcic", DV_DULL
};
@@ -209,8 +212,13 @@ pcic_attach(sc)
DPRINTF(("pcic ident regs:"));
- sc->handle[0].sc = sc;
+ sc->handle[0].ph_parent = (struct device *)sc;
sc->handle[0].sock = C0SA;
+ /* initialise pcic_read and pcic_write functions */
+ sc->handle[0].ph_read = st_pcic_read;
+ sc->handle[0].ph_write = st_pcic_write;
+ sc->handle[0].ph_bus_t = sc->iot;
+ sc->handle[0].ph_bus_h = sc->ioh;
if (pcic_ident_ok(reg = pcic_read(&sc->handle[0], PCIC_IDENT))) {
sc->handle[0].flags = PCIC_FLAG_SOCKETP;
count++;
@@ -221,8 +229,13 @@ pcic_attach(sc)
DPRINTF((" 0x%02x", reg));
- sc->handle[1].sc = sc;
+ sc->handle[1].ph_parent = (struct device *)sc;
sc->handle[1].sock = C0SB;
+ /* initialise pcic_read and pcic_write functions */
+ sc->handle[1].ph_read = st_pcic_read;
+ sc->handle[1].ph_write = st_pcic_write;
+ sc->handle[1].ph_bus_t = sc->iot;
+ sc->handle[1].ph_bus_h = sc->ioh;
if (pcic_ident_ok(reg = pcic_read(&sc->handle[1], PCIC_IDENT))) {
sc->handle[1].flags = PCIC_FLAG_SOCKETP;
count++;
@@ -238,8 +251,13 @@ pcic_attach(sc)
* if you try to read from the second one. Maybe pcic_ident_ok
* shouldn't accept 0?
*/
- sc->handle[2].sc = sc;
+ sc->handle[2].ph_parent = (struct device *)sc;
sc->handle[2].sock = C1SA;
+ /* initialise pcic_read and pcic_write functions */
+ sc->handle[2].ph_read = st_pcic_read;
+ sc->handle[2].ph_write = st_pcic_write;
+ sc->handle[2].ph_bus_t = sc->iot;
+ sc->handle[2].ph_bus_h = sc->ioh;
if (pcic_vendor(&sc->handle[0]) != PCIC_VENDOR_CIRRUS_PD672X ||
pcic_read(&sc->handle[2], PCIC_IDENT) != 0) {
if (pcic_ident_ok(reg = pcic_read(&sc->handle[2],
@@ -253,8 +271,13 @@ pcic_attach(sc)
DPRINTF((" 0x%02x", reg));
- sc->handle[3].sc = sc;
+ sc->handle[3].ph_parent = (struct device *)sc;
sc->handle[3].sock = C1SB;
+ /* initialise pcic_read and pcic_write functions */
+ sc->handle[3].ph_read = st_pcic_read;
+ sc->handle[3].ph_write = st_pcic_write;
+ sc->handle[3].ph_bus_t = sc->iot;
+ sc->handle[3].ph_bus_h = sc->ioh;
if (pcic_ident_ok(reg = pcic_read(&sc->handle[3],
PCIC_IDENT))) {
sc->handle[3].flags = PCIC_FLAG_SOCKETP;
@@ -330,6 +353,7 @@ pcic_attach_socket(h)
struct pcic_handle *h;
{
struct pcmciabus_attach_args paa;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
/* initialize the rest of the handle */
@@ -340,18 +364,21 @@ pcic_attach_socket(h)
/* now, config one pcmcia device per socket */
- paa.pct = (pcmcia_chipset_tag_t) h->sc->pct;
+ paa.paa_busname = "pcmcia";
+ paa.pct = (pcmcia_chipset_tag_t) sc->pct;
paa.pch = (pcmcia_chipset_handle_t) h;
- paa.iobase = h->sc->iobase;
- paa.iosize = h->sc->iosize;
+ paa.iobase = sc->iobase;
+ paa.iosize = sc->iosize;
- h->pcmcia = config_found_sm(&h->sc->dev, &paa, pcic_print,
+ h->pcmcia = config_found_sm(&sc->dev, &paa, pcic_print,
pcic_submatch);
/* if there's actually a pcmcia device attached, initialize the slot */
if (h->pcmcia)
pcic_init_socket(h);
+ else
+ h->flags &= ~PCIC_FLAG_SOCKETP;
}
void
@@ -379,9 +406,9 @@ pcic_create_event_thread(arg)
}
if (kthread_create(pcic_event_thread, h, &h->event_thread,
- "%s,%s", h->sc->dev.dv_xname, cs)) {
+ "%s,%s", h->ph_parent->dv_xname, cs)) {
printf("%s: unable to create event thread for sock 0x%02x\n",
- h->sc->dev.dv_xname, h->sock);
+ h->ph_parent->dv_xname, h->sock);
panic("pcic_create_event_thread");
}
}
@@ -393,6 +420,7 @@ pcic_event_thread(arg)
struct pcic_handle *h = arg;
struct pcic_event *pe;
int s;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
while (h->shutdown == 0) {
s = splhigh();
@@ -433,7 +461,7 @@ pcic_event_thread(arg)
}
splx(s);
- DPRINTF(("%s: insertion event\n", h->sc->dev.dv_xname));
+ DPRINTF(("%s: insertion event\n", h->ph_parent->dv_xname));
pcic_attach_card(h);
break;
@@ -459,7 +487,7 @@ pcic_event_thread(arg)
}
splx(s);
- DPRINTF(("%s: removal event\n", h->sc->dev.dv_xname));
+ DPRINTF(("%s: removal event\n", h->ph_parent->dv_xname));
pcic_detach_card(h, DETACH_FORCE);
break;
@@ -473,7 +501,7 @@ pcic_event_thread(arg)
h->event_thread = NULL;
/* In case parent is waiting for us to exit. */
- wakeup(h->sc);
+ wakeup(sc);
kthread_exit(0);
}
@@ -483,6 +511,7 @@ pcic_init_socket(h)
struct pcic_handle *h;
{
int reg;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
/*
* queue creation of a kernel thread to handle insert/removal events.
@@ -495,7 +524,7 @@ pcic_init_socket(h)
/* set up the card to interrupt on card detect */
- pcic_write(h, PCIC_CSC_INTR, (h->sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
+ pcic_write(h, PCIC_CSC_INTR, (sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
PCIC_CSC_INTR_CD_ENABLE);
pcic_write(h, PCIC_INTR, 0);
pcic_read(h, PCIC_CSC);
@@ -507,7 +536,7 @@ pcic_init_socket(h)
reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_2);
if (reg & PCIC_CIRRUS_MISC_CTL_2_SUSPEND) {
DPRINTF(("%s: socket %02x was suspended\n",
- h->sc->dev.dv_xname, h->sock));
+ h->ph_parent->dv_xname, h->sock));
reg &= ~PCIC_CIRRUS_MISC_CTL_2_SUSPEND;
pcic_write(h, PCIC_CIRRUS_MISC_CTL_2, reg);
}
@@ -648,21 +677,21 @@ pcic_intr_socket(h)
PCIC_CSC_BATTDEAD);
if (cscreg & PCIC_CSC_GPI) {
- DPRINTF(("%s: %02x GPI\n", h->sc->dev.dv_xname, h->sock));
+ DPRINTF(("%s: %02x GPI\n", h->ph_parent->dv_xname, h->sock));
}
if (cscreg & PCIC_CSC_CD) {
int statreg;
statreg = pcic_read(h, PCIC_IF_STATUS);
- DPRINTF(("%s: %02x CD %x\n", h->sc->dev.dv_xname, h->sock,
+ DPRINTF(("%s: %02x CD %x\n", h->ph_parent->dv_xname, h->sock,
statreg));
if ((statreg & PCIC_IF_STATUS_CARDDETECT_MASK) ==
PCIC_IF_STATUS_CARDDETECT_PRESENT) {
if (h->laststate != PCIC_LASTSTATE_PRESENT) {
DPRINTF(("%s: enqueing INSERTION event\n",
- h->sc->dev.dv_xname));
+ h->ph_parent->dv_xname));
pcic_queue_event(h, PCIC_EVENT_INSERTION);
}
h->laststate = PCIC_LASTSTATE_PRESENT;
@@ -670,11 +699,11 @@ pcic_intr_socket(h)
if (h->laststate == PCIC_LASTSTATE_PRESENT) {
/* Deactivate the card now. */
DPRINTF(("%s: deactivating card\n",
- h->sc->dev.dv_xname));
+ h->ph_parent->dv_xname));
pcic_deactivate_card(h);
DPRINTF(("%s: enqueing REMOVAL event\n",
- h->sc->dev.dv_xname));
+ h->ph_parent->dv_xname));
pcic_queue_event(h, PCIC_EVENT_REMOVAL);
}
h->laststate =
@@ -683,14 +712,14 @@ pcic_intr_socket(h)
}
}
if (cscreg & PCIC_CSC_READY) {
- DPRINTF(("%s: %02x READY\n", h->sc->dev.dv_xname, h->sock));
+ DPRINTF(("%s: %02x READY\n", h->ph_parent->dv_xname, h->sock));
/* shouldn't happen */
}
if (cscreg & PCIC_CSC_BATTWARN) {
- DPRINTF(("%s: %02x BATTWARN\n", h->sc->dev.dv_xname, h->sock));
+ DPRINTF(("%s: %02x BATTWARN\n", h->ph_parent->dv_xname, h->sock));
}
if (cscreg & PCIC_CSC_BATTDEAD) {
- DPRINTF(("%s: %02x BATTDEAD\n", h->sc->dev.dv_xname, h->sock));
+ DPRINTF(("%s: %02x BATTDEAD\n", h->ph_parent->dv_xname, h->sock));
}
return (cscreg ? 1 : 0);
}
@@ -770,6 +799,7 @@ pcic_chip_mem_alloc(pch, size, pcmhp)
bus_addr_t addr;
bus_size_t sizepg;
int i, mask, mhandle;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
/* out of sc->memh, allocate as many pages as necessary */
@@ -782,14 +812,14 @@ pcic_chip_mem_alloc(pch, size, pcmhp)
mhandle = 0; /* XXX gcc -Wuninitialized */
for (i = 0; i < (PCIC_MEM_PAGES + 1 - sizepg); i++) {
- if ((h->sc->subregionmask & (mask << i)) == (mask << i)) {
- if (bus_space_subregion(h->sc->memt, h->sc->memh,
+ if ((sc->subregionmask & (mask << i)) == (mask << i)) {
+ if (bus_space_subregion(sc->memt, sc->memh,
i * PCIC_MEM_PAGESIZE,
sizepg * PCIC_MEM_PAGESIZE, &memh))
return (1);
mhandle = mask << i;
- addr = h->sc->membase + (i * PCIC_MEM_PAGESIZE);
- h->sc->subregionmask &= ~(mhandle);
+ addr = sc->membase + (i * PCIC_MEM_PAGESIZE);
+ sc->subregionmask &= ~(mhandle);
break;
}
}
@@ -800,7 +830,7 @@ pcic_chip_mem_alloc(pch, size, pcmhp)
DPRINTF(("pcic_chip_mem_alloc bus addr 0x%lx+0x%lx\n", (u_long) addr,
(u_long) size));
- pcmhp->memt = h->sc->memt;
+ pcmhp->memt = sc->memt;
pcmhp->memh = memh;
pcmhp->addr = addr;
pcmhp->size = size;
@@ -816,8 +846,9 @@ pcic_chip_mem_free(pch, pcmhp)
struct pcmcia_mem_handle *pcmhp;
{
struct pcic_handle *h = (struct pcic_handle *) pch;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
- h->sc->subregionmask |= pcmhp->mhandle;
+ sc->subregionmask |= pcmhp->mhandle;
}
static struct mem_map_index_st {
@@ -882,17 +913,17 @@ pcic_chip_do_mem_map(h, win)
int win;
{
int reg;
+ int kind = h->mem[win].kind & ~PCMCIA_WIDTH_MEM_MASK;
+ int mem8 =
+ (h->mem[win].kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8
+ || (kind == PCMCIA_MEM_ATTR);
pcic_write(h, mem_map_index[win].sysmem_start_lsb,
(h->mem[win].addr >> PCIC_SYSMEM_ADDRX_SHIFT) & 0xff);
pcic_write(h, mem_map_index[win].sysmem_start_msb,
((h->mem[win].addr >> (PCIC_SYSMEM_ADDRX_SHIFT + 8)) &
- PCIC_SYSMEM_ADDRX_START_MSB_ADDR_MASK));
-
-#if 0
- /* XXX do I want 16 bit all the time? */
- PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT;
-#endif
+ PCIC_SYSMEM_ADDRX_START_MSB_ADDR_MASK) |
+ (mem8 ? 0 : PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT));
pcic_write(h, mem_map_index[win].sysmem_stop_lsb,
((h->mem[win].addr + h->mem[win].size) >>
@@ -908,7 +939,7 @@ pcic_chip_do_mem_map(h, win)
pcic_write(h, mem_map_index[win].cardmem_msb,
((h->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8)) &
PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK) |
- ((h->mem[win].kind == PCMCIA_MEM_ATTR) ?
+ ((kind == PCMCIA_MEM_ATTR) ?
PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
reg = pcic_read(h, PCIC_ADDRWIN_ENABLE);
@@ -946,6 +977,7 @@ pcic_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
bus_addr_t busaddr;
long card_offset;
int i, win;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
win = -1;
for (i = 0; i < (sizeof(mem_map_index) / sizeof(mem_map_index[0]));
@@ -964,7 +996,7 @@ pcic_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
/* XXX this is pretty gross */
- if (h->sc->memt != pcmhp->memt)
+ if (sc->memt != pcmhp->memt)
panic("pcic_chip_mem_map memt is bogus");
busaddr = pcmhp->addr;
@@ -1032,13 +1064,14 @@ pcic_chip_io_alloc(pch, start, size, align, pcihp)
bus_space_handle_t ioh;
bus_addr_t ioaddr, beg, fin;
int flags = 0;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
struct pcic_ranges *range;
/*
* Allocate some arbitrary I/O space.
*/
- iot = h->sc->iot;
+ iot = sc->iot;
if (start) {
ioaddr = start;
@@ -1046,28 +1079,28 @@ pcic_chip_io_alloc(pch, start, size, align, pcihp)
return (1);
DPRINTF(("pcic_chip_io_alloc map port %lx+%lx\n",
(u_long)ioaddr, (u_long)size));
- } else if (h->sc->ranges) {
+ } else if (sc->ranges) {
flags |= PCMCIA_IO_ALLOCATED;
/*
* In this case, we know the "size" and "align" that
* we want. So we need to start walking down
- * h->sc->ranges, searching for a similar space that
+ * sc->ranges, searching for a similar space that
* is (1) large enough for the size and alignment
* (2) then we need to try to allocate
* (3) if it fails to allocate, we try next range.
*
* We must also check that the start/size of each
* allocation we are about to do is within the bounds
- * of "h->sc->iobase" and "h->sc->iosize".
+ * of "sc->iobase" and "sc->iosize".
* (Some pcmcia controllers handle a 12 bits of addressing,
* but we want to use the same range structure)
*/
- for (range = h->sc->ranges; range->start; range++) {
+ for (range = sc->ranges; range->start; range++) {
/* Potentially trim the range because of bounds. */
- beg = max(range->start, h->sc->iobase);
+ beg = max(range->start, sc->iobase);
fin = min(range->start + range->len,
- h->sc->iobase + h->sc->iosize);
+ sc->iobase + sc->iosize);
/* Short-circuit easy cases. */
if (fin < beg || fin - beg < size)
@@ -1090,8 +1123,8 @@ pcic_chip_io_alloc(pch, start, size, align, pcihp)
} else {
flags |= PCMCIA_IO_ALLOCATED;
- if (bus_space_alloc(iot, h->sc->iobase,
- h->sc->iobase + h->sc->iosize, size, align, 0, 0,
+ if (bus_space_alloc(iot, sc->iobase,
+ sc->iobase + sc->iosize, size, align, 0, 0,
&ioaddr, &ioh))
return (1);
DPRINTF(("pcic_chip_io_alloc alloc port %lx+%lx\n",
@@ -1211,6 +1244,7 @@ pcic_chip_io_map(pch, width, offset, size, pcihp, windowp)
#ifdef PCICDEBUG
static char *width_names[] = { "auto", "io8", "io16" };
#endif
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
/* XXX Sanity check offset/size. */
@@ -1230,7 +1264,7 @@ pcic_chip_io_map(pch, width, offset, size, pcihp, windowp)
/* XXX this is pretty gross */
- if (h->sc->iot != pcihp->iot)
+ if (sc->iot != pcihp->iot)
panic("pcic_chip_io_map iot is bogus");
DPRINTF(("pcic_chip_io_map window %d %s port %lx+%lx\n",
@@ -1369,7 +1403,7 @@ pcic_chip_socket_enable(pch)
pcic_write(h, PCIC_INTR, reg);
DPRINTF(("%s: pcic_chip_socket_enable %02x cardtype %s %02x\n",
- h->sc->dev.dv_xname, h->sock,
+ h->ph_parent->dv_xname, h->sock,
((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"), reg));
/* reinstall all the memory and io mappings */
@@ -1400,3 +1434,28 @@ pcic_chip_socket_disable(pch)
*/
delay(300 * 1000);
}
+
+u_int8_t
+st_pcic_read(h, idx)
+ struct pcic_handle *h;
+ int idx;
+{
+ if (idx != -1) {
+ bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_INDEX, h->sock + idx);
+ }
+
+ return bus_space_read_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_DATA);
+}
+
+void
+st_pcic_write(h, idx, data)
+ struct pcic_handle *h;
+ int idx;
+ u_int8_t data;
+{
+ if (idx != -1) {
+ bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_INDEX, h->sock + idx);
+ }
+
+ bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_DATA, data);
+}
diff --git a/sys/dev/ic/i82365var.h b/sys/dev/ic/i82365var.h
index 81af7b771f2..72792836c86 100644
--- a/sys/dev/ic/i82365var.h
+++ b/sys/dev/ic/i82365var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82365var.h,v 1.5 1999/08/08 01:07:02 niklas Exp $ */
+/* $OpenBSD: i82365var.h,v 1.6 2000/04/08 05:50:50 aaron Exp $ */
/* $NetBSD: i82365var.h,v 1.4 1998/05/23 18:32:29 matt Exp $ */
/*
@@ -49,7 +49,12 @@ struct pcic_event {
#define PCIC_EVENT_REMOVAL 1
struct pcic_handle {
- struct pcic_softc *sc;
+ struct device *ph_parent;
+ bus_space_tag_t ph_bus_t;
+ bus_space_handle_t ph_bus_h;
+ u_int8_t (*ph_read) __P((struct pcic_handle *, int));
+ void (*ph_write) __P((struct pcic_handle *, int, u_int8_t));
+
int vendor;
int sock;
int flags;
@@ -146,9 +151,6 @@ void pcic_attach __P((struct pcic_softc *));
void pcic_attach_sockets __P((struct pcic_softc *));
int pcic_intr __P((void *arg));
-static inline int pcic_read __P((struct pcic_handle *, int));
-static inline void pcic_write __P((struct pcic_handle *, int, int));
-
int pcic_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
struct pcmcia_mem_handle *));
void pcic_chip_mem_free __P((pcmcia_chipset_handle_t,
@@ -168,29 +170,8 @@ void pcic_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
void pcic_chip_socket_enable __P((pcmcia_chipset_handle_t));
void pcic_chip_socket_disable __P((pcmcia_chipset_handle_t));
-static __inline int pcic_read __P((struct pcic_handle *, int));
-static __inline int
-pcic_read(h, idx)
- struct pcic_handle *h;
- int idx;
-{
- if (idx != -1)
- bus_space_write_1(h->sc->iot, h->sc->ioh, PCIC_REG_INDEX,
- h->sock + idx);
- return (bus_space_read_1(h->sc->iot, h->sc->ioh, PCIC_REG_DATA));
-}
-
-static __inline void pcic_write __P((struct pcic_handle *, int, int));
-static __inline void
-pcic_write(h, idx, data)
- struct pcic_handle *h;
- int idx;
- int data;
-{
- if (idx != -1)
- bus_space_write_1(h->sc->iot, h->sc->ioh, PCIC_REG_INDEX,
- h->sock + idx);
- if (data != -1)
- bus_space_write_1(h->sc->iot, h->sc->ioh, PCIC_REG_DATA,
- (data));
-}
+#define pcic_read(h, idx) \
+ (*(h)->ph_read)((h), (idx))
+
+#define pcic_write(h, idx, data) \
+ (*(h)->ph_write)((h), (idx), (data))
diff --git a/sys/dev/pci/if_xl.c b/sys/dev/ic/xl.c
index a06904cbfb8..5ea3fa6a541 100644
--- a/sys/dev/pci/if_xl.c
+++ b/sys/dev/ic/xl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_xl.c,v 1.38 2000/02/15 13:47:52 jason Exp $ */
+/* $OpenBSD: xl.c,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -56,6 +56,7 @@
* 3Com 3c450-TX 10/100Mbps/RJ-45 (Tornado ASIC)
* 3Com 3c980-TX 10/100Mbps server adapter (Hurricane ASIC)
* 3Com 3c980C-TX 10/100Mbps server adapter (Tornado ASIC)
+ * 3Com 3CCFE575CT 10/100Mbps LAN CardBus PC Card
* 3Com 3cSOHO100-TX 10/100Mbps/RJ-45 (Hurricane ASIC)
* Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45
* Dell on-board 3c920 10/100Mbps/RJ-45
@@ -123,6 +124,7 @@
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
+
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
@@ -134,22 +136,7 @@
#include <vm/vm.h> /* for vtophys */
#include <vm/pmap.h> /* for vtophys */
-/*
- * The following #define causes the code to use PIO to access the
- * chip's registers instead of memory mapped mode. The reason PIO mode
- * is on by default is that the Etherlink XL manual seems to indicate
- * that only the newer revision chips (3c905B) support both PIO and
- * memory mapped access. Since we want to be compatible with the older
- * bus master chips, we use PIO here. If you comment this out, the
- * driver will use memory mapped I/O, which may be faster but which
- * might not work on some devices.
- */
-#define XL_USEIOSPACE
-
-#include <dev/pci/if_xlreg.h>
-
-int xl_probe __P((struct device *, void *, void *));
-void xl_attach __P((struct device *, struct device *, void *));
+#include <dev/ic/xlreg.h>
int xl_newbuf __P((struct xl_softc *, struct xl_chain_onefrag *));
void xl_stats_update __P((void *));
@@ -450,7 +437,7 @@ xl_miibus_readreg(self, phy, reg)
struct xl_softc *sc = (struct xl_softc *)self;
struct xl_mii_frame frame;
- if (phy != 24)
+ if (sc->xl_bustype != XL_BUS_CARDBUS && phy != 24)
return (0);
bzero((char *)&frame, sizeof(frame));
@@ -470,7 +457,7 @@ xl_miibus_writereg(self, phy, reg, data)
struct xl_softc *sc = (struct xl_softc *)self;
struct xl_mii_frame frame;
- if (phy != 24)
+ if (sc->xl_bustype != XL_BUS_CARDBUS && phy != 24)
return;
bzero((char *)&frame, sizeof(frame));
@@ -542,7 +529,14 @@ int xl_read_eeprom(sc, dest, off, cnt, swap)
return(1);
for (i = 0; i < cnt; i++) {
- CSR_WRITE_2(sc, XL_W0_EE_CMD, XL_EE_READ | (off + i));
+ switch (sc->xl_bustype) {
+ case XL_BUS_PCI:
+ CSR_WRITE_2(sc, XL_W0_EE_CMD, XL_EE_READ | (off + i));
+ break;
+ case XL_BUS_CARDBUS:
+ CSR_WRITE_2(sc, XL_W0_EE_CMD, 0x230 + (off + i));
+ break;
+ }
err = xl_eeprom_wait(sc);
if (err)
break;
@@ -863,41 +857,6 @@ void xl_reset(sc, hard)
return;
}
-int
-xl_probe(parent, match, aux)
- struct device *parent;
- void *match;
- void *aux;
-{
- struct pci_attach_args *pa = (struct pci_attach_args *) aux;
-
- if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3COM)
- return (0);
-
- switch (PCI_PRODUCT(pa->pa_id)) {
- case PCI_PRODUCT_3COM_3CSOHO100TX:
- case PCI_PRODUCT_3COM_3C900TPO:
- case PCI_PRODUCT_3COM_3C900COMBO:
- case PCI_PRODUCT_3COM_3C900B:
- case PCI_PRODUCT_3COM_3C900BCOMBO:
- case PCI_PRODUCT_3COM_3C900BTPC:
- case PCI_PRODUCT_3COM_3C900BFL:
- case PCI_PRODUCT_3COM_3C905TX:
- case PCI_PRODUCT_3COM_3C905T4:
- case PCI_PRODUCT_3COM_3C905BTX:
- case PCI_PRODUCT_3COM_3C905BT4:
- case PCI_PRODUCT_3COM_3C905BCOMBO:
- case PCI_PRODUCT_3COM_3C905BFX:
- case PCI_PRODUCT_3COM_3C980TX:
- case PCI_PRODUCT_3COM_3C980CTX:
- case PCI_PRODUCT_3COM_3C905CTX:
- case PCI_PRODUCT_3COM_3C450:
- return (1);
- }
-
- return (0);
-}
-
/*
* This routine is a kludge to work around possible hardware faults
* or manufacturing defects that can cause the media options register
@@ -1021,6 +980,10 @@ void xl_choose_xcvr(sc, verbose)
printf("xl%d: guessing 10/100 plus BNC/AUI\n",
sc->xl_unit);
break;
+ case TC_DEVICEID_3CCFE575CT_CARDBUS:
+ sc->xl_media = XL_MEDIAOPT_MII;
+ sc->xl_xcvr = XL_XCVR_MII;
+ break;
default:
printf("xl%d: unknown device ID: %x -- "
"defaulting to 10baseT\n", sc->xl_unit, devid);
@@ -1466,6 +1429,9 @@ int xl_intr(arg)
CSR_WRITE_2(sc, XL_COMMAND,
XL_CMD_INTR_ACK|(status & XL_INTRS));
+ if (sc->xl_bustype == XL_BUS_CARDBUS)
+ bus_space_write_4(sc->xl_funct,sc->xl_funch, 4, 0x8000);
+
if (status & XL_STAT_UP_COMPLETE) {
int curpkts;
@@ -2042,6 +2008,10 @@ void xl_init(xsc)
* Enable interrupts.
*/
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
+
+ if (sc->xl_bustype == XL_BUS_CARDBUS)
+ bus_space_write_4(sc->xl_funct, sc->xl_funch, 4, 0x8000);
+
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
@@ -2342,6 +2312,9 @@ void xl_stop(sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
+ if (sc->xl_bustype == XL_BUS_CARDBUS)
+ bus_space_write_4(sc->xl_funct, sc->xl_funch, 4, 0x8000);
+
/* Stop the stats updater. */
untimeout(xl_stats_update, sc);
@@ -2374,135 +2347,17 @@ void xl_stop(sc)
}
void
-xl_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
+xl_attach(sc)
+ struct xl_softc *sc;
{
- struct xl_softc *sc = (struct xl_softc *)self;
- struct pci_attach_args *pa = aux;
- pci_chipset_tag_t pc = pa->pa_pc;
- pci_intr_handle_t ih;
- const char *intrstr = NULL;
u_int8_t enaddr[ETHER_ADDR_LEN];
struct ifnet *ifp = &sc->arpcom.ac_if;
- bus_addr_t iobase;
- bus_size_t iosize;
- u_int32_t command;
caddr_t roundptr;
u_int round;
int i, media = IFM_ETHER|IFM_100_TX|IFM_FDX;
struct ifmedia *ifm;
sc->xl_unit = sc->sc_dev.dv_unit;
-
- /*
- * If this is a 3c905B, we have to check one extra thing.
- * The 905B supports power management and may be placed in
- * a low-power mode (D3 mode), typically by certain operating
- * systems which shall not be named. The PCI BIOS is supposed
- * to reset the NIC and bring it out of low-power mode, but
- * some do not. Consequently, we have to see if this chip
- * supports power management, and if so, make sure it's not
- * in low-power mode. If power management is available, the
- * capid byte will be 0x01.
- *
- * I _think_ that what actually happens is that the chip
- * loses its PCI configuration during the transition from
- * D3 back to D0; this means that it should be possible for
- * us to save the PCI iobase, membase and IRQ, put the chip
- * back in the D0 state, then restore the PCI config ourselves.
- */
- command = pci_conf_read(pc, pa->pa_tag, XL_PCI_CAPID) & 0xff;
- if (command == 0x01) {
-
- command = pci_conf_read(pc, pa->pa_tag,
- XL_PCI_PWRMGMTCTRL);
- if (command & XL_PSTATE_MASK) {
- u_int32_t io, mem, irq;
-
- /* Save PCI config */
- io = pci_conf_read(pc, pa->pa_tag, XL_PCI_LOIO);
- mem = pci_conf_read(pc, pa->pa_tag, XL_PCI_LOMEM);
- irq = pci_conf_read(pc, pa->pa_tag, XL_PCI_INTLINE);
-
- /* Reset the power state. */
- printf("%s: chip is in D%d power mode "
- "-- setting to D0\n",
- sc->sc_dev.dv_xname, command & XL_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_conf_write(pc, pa->pa_tag,
- XL_PCI_PWRMGMTCTRL, command);
-
- pci_conf_write(pc, pa->pa_tag, XL_PCI_LOIO, io);
- pci_conf_write(pc, pa->pa_tag, XL_PCI_LOMEM, mem);
- pci_conf_write(pc, pa->pa_tag, XL_PCI_INTLINE, irq);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
- command |= PCI_COMMAND_IO_ENABLE |
- PCI_COMMAND_MEM_ENABLE |
- PCI_COMMAND_MASTER_ENABLE;
- pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
- command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
-
-#ifdef XL_USEIOSPACE
- if (!(command & PCI_COMMAND_IO_ENABLE)) {
- printf("%s: failed to enable i/o ports\n",
- sc->sc_dev.dv_xname);
- return;
- }
- /*
- * Map control/status registers.
- */
- if (pci_io_find(pc, pa->pa_tag, XL_PCI_LOIO, &iobase, &iosize)) {
- printf(": can't find i/o space\n");
- return;
- }
- if (bus_space_map(pa->pa_iot, iobase, iosize, 0, &sc->xl_bhandle)) {
- printf(": can't map i/o space\n");
- return;
- }
- sc->xl_btag = pa->pa_iot;
-#else
- if (!(command & PCI_COMMAND_MEM_ENABLE)) {
- printf(": failed to enable memory mapping\n");
- return;
- }
- if (pci_mem_find(pc, pa->pa_tag, XL_PCI_LOMEM, &iobase, &iosize, NULL)){
- printf(": can't find mem space\n");
- return;
- }
- if (bus_space_map(pa->pa_memt, iobase, iosize, 0, &sc->xl_bhandle)) {
- printf(": can't map mem space\n");
- return;
- }
- sc->xl_btag = pa->pa_memt;
-#endif
-
- /*
- * Allocate our interrupt.
- */
- if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
- pa->pa_intrline, &ih)) {
- printf(": couldn't map interrupt\n");
- return;
- }
-
- intrstr = pci_intr_string(pc, ih);
- sc->xl_intrhand = pci_intr_establish(pc, ih, IPL_NET, xl_intr, sc,
- self->dv_xname);
- if (sc->xl_intrhand == NULL) {
- printf(": couldn't establish interrupt");
- if (intrstr != NULL)
- printf(" at %s", intrstr);
- return;
- }
- printf(": %s", intrstr);
-
xl_reset(sc, 1);
/*
@@ -2517,6 +2372,22 @@ xl_attach(parent, self, aux)
printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+ if (sc->xl_bustype == XL_BUS_CARDBUS) {
+ u_int16_t devid;
+ u_int16_t n;
+
+ XL_SEL_WIN(2);
+ n = CSR_READ_2(sc, 12);
+ xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0);
+
+ if (devid != 0x5257)
+ n |= 0x0010;
+ if (devid == 0x5257 || devid == 0x6560 || devid == 0x6562)
+ n |= 0x4000;
+
+ CSR_WRITE_2(sc, 12, n);
+ }
+
sc->xl_ldata_ptr = malloc(sizeof(struct xl_list_data) + 8,
M_DEVBUF, M_NOWAIT);
if (sc->xl_ldata_ptr == NULL) {
@@ -2573,8 +2444,20 @@ xl_attach(parent, self, aux)
sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK;
sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS;
+ if (sc->xl_bustype == XL_BUS_CARDBUS) {
+ XL_SEL_WIN(2);
+ CSR_WRITE_2(sc, 12, 0x4000 | CSR_READ_2(sc, 12));
+ }
+ DELAY(100000);
+
xl_mediacheck(sc);
+ if (sc->xl_bustype == XL_BUS_CARDBUS) {
+ XL_SEL_WIN(2);
+ CSR_WRITE_2(sc, 12, 0x4000 | CSR_READ_2(sc, 12));
+ }
+ DELAY(100000);
+
if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX
|| sc->xl_media & XL_MEDIAOPT_BT4) {
ifmedia_init(&sc->sc_mii.mii_media, 0,
@@ -2585,7 +2468,7 @@ xl_attach(parent, self, aux)
sc->sc_mii.mii_writereg = xl_miibus_writereg;
sc->sc_mii.mii_statchg = xl_miibus_statchg;
xl_setcfg(sc);
- mii_phy_probe(self, &sc->sc_mii, 0xffffffff);
+ mii_phy_probe((struct device *)sc, &sc->sc_mii, 0xffffffff);
if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE,
@@ -2713,10 +2596,6 @@ xl_shutdown(v)
xl_stop(sc);
}
-struct cfattach xl_ca = {
- sizeof(struct xl_softc), xl_probe, xl_attach,
-};
-
struct cfdriver xl_cd = {
0, "xl", DV_IFNET
};
diff --git a/sys/dev/pci/if_xlreg.h b/sys/dev/ic/xlreg.h
index 7536935ef51..2024d97788e 100644
--- a/sys/dev/pci/if_xlreg.h
+++ b/sys/dev/ic/xlreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_xlreg.h,v 1.17 1999/12/16 22:15:45 deraadt Exp $ */
+/* $OpenBSD: xlreg.h,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -34,6 +34,9 @@
* $FreeBSD: if_xlreg.h,v 1.17 1999/05/30 18:09:17 wpaul Exp $
*/
+#define XL_BUS_PCI 0x00
+#define XL_BUS_CARDBUS 0x01
+
#define XL_EE_READ 0x0080 /* read, 5 bit address */
#define XL_EE_WRITE 0x0040 /* write, 5 bit address */
#define XL_EE_ERASE 0x00c0 /* erase, 5 bit address */
@@ -280,6 +283,7 @@
#define XL_XCVR_MII 0x06
#define XL_XCVR_RSVD_1 0x07
#define XL_XCVR_AUTO 0x08 /* 3c905B only */
+#define XL_XCVR_NWAY 0x09 /* 3CCFE575CT CardBus */
#define XL_MACCTRL_DEFER_EXT_END 0x0001
#define XL_MACCTRL_DEFER_0 0x0002
@@ -557,6 +561,8 @@ struct xl_softc {
mii_data_t sc_mii; /* mii bus */
bus_space_handle_t xl_bhandle;
bus_space_tag_t xl_btag;
+ bus_space_handle_t xl_funch;
+ bus_space_tag_t xl_funct;
struct xl_type *xl_info; /* 3Com adapter info */
u_int8_t xl_hasmii; /* whether we have mii or not */
u_int8_t xl_unit; /* interface number */
@@ -566,10 +572,12 @@ struct xl_softc {
u_int16_t xl_caps;
u_int8_t xl_stats_no_timeout;
u_int16_t xl_tx_thresh;
+ u_int8_t xl_bustype; /* i.e., PCI or CardBus? */
int xl_if_flags;
caddr_t xl_ldata_ptr;
struct xl_list_data *xl_ldata;
struct xl_chain_data xl_cdata;
+ void (*intr_ack) __P((struct xl_softc *));
};
#define xl_rx_goodframes(x) \
@@ -642,6 +650,7 @@ struct xl_stats {
#define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800
#define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805
#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646
+#define TC_DEVICEID_3CCFE575CT_CARDBUS 0x5257
/*
* PCI low memory base and low I/O base register, and
@@ -688,3 +697,6 @@ struct xl_stats {
#ifndef ETHER_ALIGN
#define ETHER_ALIGN 2
#endif
+
+extern int xl_intr __P((void *));
+extern void xl_attach __P((struct xl_softc *));
diff --git a/sys/dev/isa/i82365_isasubr.c b/sys/dev/isa/i82365_isasubr.c
index 5ceb3ef4bd7..929239cd995 100644
--- a/sys/dev/isa/i82365_isasubr.c
+++ b/sys/dev/isa/i82365_isasubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82365_isasubr.c,v 1.10 1999/08/11 12:02:07 niklas Exp $ */
+/* $OpenBSD: i82365_isasubr.c,v 1.11 2000/04/08 05:50:53 aaron Exp $ */
/* $NetBSD: i82365_isasubr.c,v 1.1 1998/06/07 18:28:31 sommerfe Exp $ */
/*
@@ -192,7 +192,8 @@ pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg)
void *arg;
{
struct pcic_handle *h = (struct pcic_handle *)pch;
- isa_chipset_tag_t ic = h->sc->intr_est;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
+ isa_chipset_tag_t ic = sc->intr_est;
int irq, ist;
void *ih;
@@ -203,7 +204,7 @@ pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg)
else
ist = IST_LEVEL;
- irq = pcic_intr_find(h->sc, ist);
+ irq = pcic_intr_find(sc, ist);
if (!irq)
return (NULL);
@@ -226,7 +227,8 @@ pcic_isa_chip_intr_disestablish(pch, ih)
void *ih;
{
struct pcic_handle *h = (struct pcic_handle *) pch;
- isa_chipset_tag_t ic = h->sc->intr_est;
+ struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
+ isa_chipset_tag_t ic = sc->intr_est;
int reg;
h->ih_irq = 0;
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index a7190a278df..a60e99daeef 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.67 2000/03/27 00:34:15 aaron Exp $
+# $OpenBSD: files.pci,v 1.68 2000/04/08 05:50:51 aaron Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -161,9 +161,8 @@ attach bktr at pci
file dev/pci/brooktree848.c bktr needs-count
# 3C90x
-device xl: ether, ifnet, mii, ifmedia
-attach xl at pci
-file dev/pci/if_xl.c xl
+attach xl at pci with xl_pci
+file dev/pci/if_xl_pci.c xl_pci
# SMC EPIC, 83c170
device tx: ether, ifnet, ifmedia
@@ -222,6 +221,12 @@ file dev/pci/uhci_pci.c uhci
attach ohci at pci with ohci_pci
file dev/pci/ohci_pci.c ohci
+# YENTA PCI-CardBus bridge
+#device cbb: cbbus, pcmciabus
+device cbb: pcmciaslot
+attach cbb at pci with cbb_pci
+file dev/pci/pccbb.c cbb
+
# SysKonnect 984x gigabit ethernet
device skc {}
attach skc at pci
diff --git a/sys/dev/pci/if_xl_pci.c b/sys/dev/pci/if_xl_pci.c
new file mode 100644
index 00000000000..266ea7aeae9
--- /dev/null
+++ b/sys/dev/pci/if_xl_pci.c
@@ -0,0 +1,225 @@
+/* $OpenBSD: if_xl_pci.c,v 1.1 2000/04/08 05:50:51 aaron Exp $ */
+
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/proc.h> /* only for declaration of wakeup() used by vm.h */
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+
+/*
+ * The following #define causes the code to use PIO to access the
+ * chip's registers instead of memory mapped mode. The reason PIO mode
+ * is on by default is that the Etherlink XL manual seems to indicate
+ * that only the newer revision chips (3c905B) support both PIO and
+ * memory mapped access. Since we want to be compatible with the older
+ * bus master chips, we use PIO here. If you comment this out, the
+ * driver will use memory mapped I/O, which may be faster but which
+ * might not work on some devices.
+ */
+#define XL_USEIOSPACE
+
+#include <dev/ic/xlreg.h>
+
+int xl_pci_match __P((struct device *, void *, void *));
+void xl_pci_attach __P((struct device *, struct device *, void *));
+
+int
+xl_pci_match(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3COM)
+ return (0);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_3COM_3CSOHO100TX:
+ case PCI_PRODUCT_3COM_3C900TPO:
+ case PCI_PRODUCT_3COM_3C900COMBO:
+ case PCI_PRODUCT_3COM_3C900B:
+ case PCI_PRODUCT_3COM_3C900BCOMBO:
+ case PCI_PRODUCT_3COM_3C900BTPC:
+ case PCI_PRODUCT_3COM_3C900BFL:
+ case PCI_PRODUCT_3COM_3C905TX:
+ case PCI_PRODUCT_3COM_3C905T4:
+ case PCI_PRODUCT_3COM_3C905BTX:
+ case PCI_PRODUCT_3COM_3C905BT4:
+ case PCI_PRODUCT_3COM_3C905BCOMBO:
+ case PCI_PRODUCT_3COM_3C905BFX:
+ case PCI_PRODUCT_3COM_3C980TX:
+ case PCI_PRODUCT_3COM_3C980CTX:
+ case PCI_PRODUCT_3COM_3C905CTX:
+ case PCI_PRODUCT_3COM_3C450:
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+xl_pci_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct xl_softc *sc = (struct xl_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ bus_addr_t iobase;
+ bus_size_t iosize;
+ u_int32_t command;
+
+ sc->xl_unit = sc->sc_dev.dv_unit;
+
+ /*
+ * If this is a 3c905B, we have to check one extra thing.
+ * The 905B supports power management and may be placed in
+ * a low-power mode (D3 mode), typically by certain operating
+ * systems which shall not be named. The PCI BIOS is supposed
+ * to reset the NIC and bring it out of low-power mode, but
+ * some do not. Consequently, we have to see if this chip
+ * supports power management, and if so, make sure it's not
+ * in low-power mode. If power management is available, the
+ * capid byte will be 0x01.
+ *
+ * I _think_ that what actually happens is that the chip
+ * loses its PCI configuration during the transition from
+ * D3 back to D0; this means that it should be possible for
+ * us to save the PCI iobase, membase and IRQ, put the chip
+ * back in the D0 state, then restore the PCI config ourselves.
+ */
+ command = pci_conf_read(pc, pa->pa_tag, XL_PCI_CAPID) & 0xff;
+ if (command == 0x01) {
+
+ command = pci_conf_read(pc, pa->pa_tag,
+ XL_PCI_PWRMGMTCTRL);
+ if (command & XL_PSTATE_MASK) {
+ u_int32_t io, mem, irq;
+
+ /* Save PCI config */
+ io = pci_conf_read(pc, pa->pa_tag, XL_PCI_LOIO);
+ mem = pci_conf_read(pc, pa->pa_tag, XL_PCI_LOMEM);
+ irq = pci_conf_read(pc, pa->pa_tag, XL_PCI_INTLINE);
+
+ /* Reset the power state. */
+ printf("%s: chip is in D%d power mode "
+ "-- setting to D0\n",
+ sc->sc_dev.dv_xname, command & XL_PSTATE_MASK);
+ command &= 0xFFFFFFFC;
+ pci_conf_write(pc, pa->pa_tag,
+ XL_PCI_PWRMGMTCTRL, command);
+
+ pci_conf_write(pc, pa->pa_tag, XL_PCI_LOIO, io);
+ pci_conf_write(pc, pa->pa_tag, XL_PCI_LOMEM, mem);
+ pci_conf_write(pc, pa->pa_tag, XL_PCI_INTLINE, irq);
+ }
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ command |= PCI_COMMAND_IO_ENABLE |
+ PCI_COMMAND_MEM_ENABLE |
+ PCI_COMMAND_MASTER_ENABLE;
+ pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
+ command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+
+#ifdef XL_USEIOSPACE
+ if (!(command & PCI_COMMAND_IO_ENABLE)) {
+ printf("%s: failed to enable i/o ports\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ /*
+ * Map control/status registers.
+ */
+ if (pci_io_find(pc, pa->pa_tag, XL_PCI_LOIO, &iobase, &iosize)) {
+ printf(": can't find i/o space\n");
+ return;
+ }
+ if (bus_space_map(pa->pa_iot, iobase, iosize, 0, &sc->xl_bhandle)) {
+ printf(": can't map i/o space\n");
+ return;
+ }
+ sc->xl_btag = pa->pa_iot;
+#else
+ if (!(command & PCI_COMMAND_MEM_ENABLE)) {
+ printf(": failed to enable memory mapping\n");
+ return;
+ }
+ if (pci_mem_find(pc, pa->pa_tag, XL_PCI_LOMEM, &iobase, &iosize, NULL)){
+ printf(": can't find mem space\n");
+ return;
+ }
+ if (bus_space_map(pa->pa_memt, iobase, iosize, 0, &sc->xl_bhandle)) {
+ printf(": can't map mem space\n");
+ return;
+ }
+ sc->xl_btag = pa->pa_memt;
+#endif
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf(": couldn't map interrupt\n");
+ return;
+ }
+
+ intrstr = pci_intr_string(pc, ih);
+ sc->xl_intrhand = pci_intr_establish(pc, ih, IPL_NET, xl_intr, sc,
+ self->dv_xname);
+ if (sc->xl_intrhand == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ return;
+ }
+ printf(": %s", intrstr);
+
+ xl_attach(sc);
+}
+
+struct cfattach xl_pci_ca = {
+ sizeof(struct xl_softc), xl_pci_match, xl_pci_attach,
+};
diff --git a/sys/dev/pci/pccbb.c b/sys/dev/pci/pccbb.c
new file mode 100644
index 00000000000..e6d2ae43517
--- /dev/null
+++ b/sys/dev/pci/pccbb.c
@@ -0,0 +1,3100 @@
+/* $OpenBSD: pccbb.c,v 1.1 2000/04/08 05:50:51 aaron Exp $ */
+/* $NetBSD: pccbb.c,v 1.37 2000/03/23 07:01:40 thorpej Exp $ */
+
+/*
+ * 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.
+ */
+
+/*
+#define CBB_DEBUG
+#define SHOW_REGS
+#define PCCBB_PCMCIA_POLL
+*/
+/* #define CBB_DEBUG */
+
+/*
+#define CB_PCMCIA_POLL
+#define CB_PCMCIA_POLL_ONLY
+#define LEVEL2
+*/
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/pccbbreg.h>
+
+#include <dev/cardbus/cardslotvar.h>
+
+#include <dev/cardbus/cardbusvar.h>
+
+#include <dev/pcmcia/pcmciareg.h>
+#include <dev/pcmcia/pcmciavar.h>
+
+#include <dev/ic/i82365reg.h>
+#include <dev/ic/i82365var.h>
+#include <dev/pci/pccbbvar.h>
+
+#ifndef __NetBSD_Version__
+struct cfdriver cbb_cd = {
+ NULL, "cbb", DV_DULL
+};
+#endif
+
+#if defined CBB_DEBUG
+#define DPRINTF(x) printf x
+#define STATIC
+#else
+#define DPRINTF(x)
+#define STATIC static
+#endif
+
+int pcicbbmatch __P((struct device *, void *, void *));
+void pccbbattach __P((struct device *, struct device *, void *));
+int pccbbintr __P((void *));
+static void pci113x_insert __P((void *));
+static int pccbbintr_function __P((struct pccbb_softc *));
+
+static int pccbb_detect_card __P((struct pccbb_softc *));
+
+static void pccbb_pcmcia_write __P((struct pcic_handle *, int, u_int8_t));
+static u_int8_t pccbb_pcmcia_read __P((struct 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, int *));
+STATIC void pccbb_pcmcia_attach_setup __P((struct pccbb_softc *,
+ struct pcmciabus_attach_args *));
+#if 0
+STATIC void pccbb_pcmcia_attach_card __P((struct pcic_handle *));
+STATIC void pccbb_pcmcia_detach_card __P((struct pcic_handle *, int));
+STATIC void pccbb_pcmcia_deactivate_card __P((struct pcic_handle *));
+#endif
+
+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));
+#if !rbus
+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));
+#endif /* !rbus */
+static void *pccbb_intr_establish __P((struct pccbb_softc *, int irq,
+ int level, int (*ih) (void *), void *sc));
+static void pccbb_intr_disestablish __P((struct pccbb_softc *, void *ih));
+
+static void *pccbb_cb_intr_establish __P((cardbus_chipset_tag_t, int irq,
+ int level, int (*ih) (void *), void *sc));
+static void pccbb_cb_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 void pccbb_chipinit __P((struct pccbb_softc *));
+
+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 int pccbb_pcmcia_card_detect __P((pcmcia_chipset_handle_t pch));
+
+static void pccbb_pcmcia_do_io_map __P((struct pcic_handle *, int));
+static void pccbb_pcmcia_wait_ready __P((struct pcic_handle *));
+static void pccbb_pcmcia_do_mem_map __P((struct pcic_handle *, int));
+static void pccbb_powerhook __P((int, void *));
+
+/* bus-space allocation and deallocation functions */
+#if rbus
+
+static int pccbb_rbus_cb_space_alloc __P((cardbus_chipset_tag_t, rbus_tag_t,
+ bus_addr_t addr, bus_size_t size, bus_addr_t mask, bus_size_t align,
+ int flags, bus_addr_t * addrp, bus_space_handle_t * bshp));
+static int pccbb_rbus_cb_space_free __P((cardbus_chipset_tag_t, rbus_tag_t,
+ bus_space_handle_t, bus_size_t));
+
+#endif /* rbus */
+
+#if rbus
+
+static int pccbb_open_win __P((struct pccbb_softc *, bus_space_tag_t,
+ bus_addr_t, bus_size_t, bus_space_handle_t, int flags));
+static int pccbb_close_win __P((struct pccbb_softc *, bus_space_tag_t,
+ bus_space_handle_t, bus_size_t));
+static int pccbb_winlist_insert __P((struct pccbb_win_chain_head *, bus_addr_t,
+ bus_size_t, bus_space_handle_t, int));
+static int pccbb_winlist_delete __P((struct pccbb_win_chain_head *,
+ bus_space_handle_t, bus_size_t));
+static void pccbb_winset __P((bus_addr_t align, struct pccbb_softc *,
+ bus_space_tag_t));
+void pccbb_winlist_show(struct pccbb_win_chain *);
+
+#endif /* rbus */
+
+/* for config_defer */
+static void pccbb_pci_callback __P((struct device *));
+
+#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), pcicbbmatch, 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,
+ pccbb_pcmcia_card_detect
+};
+
+#if rbus
+static struct cardbus_functions pccbb_funcs = {
+ pccbb_rbus_cb_space_alloc,
+ pccbb_rbus_cb_space_free,
+ pccbb_cb_intr_establish,
+ pccbb_cb_intr_disestablish,
+ pccbb_ctrl,
+ pccbb_power,
+ pccbb_make_tag,
+ pccbb_free_tag,
+ pccbb_conf_read,
+ pccbb_conf_write,
+};
+#else
+static struct cardbus_functions pccbb_funcs = {
+ pccbb_ctrl,
+ pccbb_power,
+ pccbb_mem_open,
+ pccbb_mem_close,
+ pccbb_io_open,
+ pccbb_io_close,
+ pccbb_cb_intr_establish,
+ pccbb_cb_intr_disestablish,
+ pccbb_make_tag,
+ pccbb_conf_read,
+ pccbb_conf_write,
+};
+#endif
+
+int
+pcicbbmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
+ PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_CARDBUS &&
+ PCI_INTERFACE(pa->pa_class) == 0) {
+ return 1;
+ }
+
+ 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 */
+ int yc_chiptype;
+ int yc_flags;
+} yc_chipsets[] = {
+ /* Texas Instruments chips */
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1130), CB_TI113X,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1131), CB_TI113X,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1250), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1220), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1221), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1225), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251B), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1211), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1420), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1450), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1451), CB_TI12XX,
+ PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
+
+ /* Ricoh chips */
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C475), CB_RX5C47X,
+ PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C476), CB_RX5C47X,
+ PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C477), CB_RX5C47X,
+ PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C478), CB_RX5C47X,
+ PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C465), CB_RX5C46X,
+ PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RF5C466), CB_RX5C46X,
+ PCCBB_PCMCIA_MEM_32},
+
+ /* Toshiba products */
+ { MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95),
+ CB_TOPIC95, PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B),
+ CB_TOPIC95B, PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC97),
+ CB_TOPIC97, PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC100),
+ CB_TOPIC97, PCCBB_PCMCIA_MEM_32},
+
+ /* Cirrus Logic products */
+ { MAKEID(PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6832),
+ CB_CIRRUS, PCCBB_PCMCIA_MEM_32},
+ { MAKEID(PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6833),
+ CB_CIRRUS, PCCBB_PCMCIA_MEM_32},
+
+ /* sentinel, or Generic chip */
+ { 0 /* null id */ , CB_UNKNOWN, PCCBB_PCMCIA_MEM_32},
+};
+
+static int
+cb_chipset(pci_id, flagp)
+ u_int32_t pci_id;
+ int *flagp;
+{
+ struct yenta_chipinfo *yc;
+
+ /* Loop over except the last default entry. */
+ for (yc = yc_chipsets; yc < yc_chipsets +
+ sizeof(yc_chipsets) / sizeof(yc_chipsets[0]) - 1; yc++)
+ if (pci_id != yc->yc_id)
+ break;
+
+ if (flagp != NULL)
+ *flagp = yc->yc_flags;
+
+ return (yc->yc_chiptype);
+}
+
+static void
+pccbb_shutdown(void *arg)
+{
+ struct pccbb_softc *sc = arg;
+ pcireg_t command;
+
+ DPRINTF(("%s: shutdown\n", sc->sc_dev.dv_xname));
+ bus_space_write_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_MASK,
+ 0);
+
+ command = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
+
+ command &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
+ PCI_COMMAND_MASTER_ENABLE);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, command);
+
+}
+
+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, busreg;
+ bus_addr_t sockbase;
+ int flags;
+
+ sc->sc_chipset = cb_chipset(pa->pa_id, &flags);
+
+#ifdef CBB_DEBUG
+ printf(" (chipflags %x)", flags);
+#endif
+
+ TAILQ_INIT(&sc->sc_memwindow);
+ TAILQ_INIT(&sc->sc_iowindow);
+
+#if rbus
+ sc->sc_rbus_iot = rbus_pccbb_parent_io(pa);
+ sc->sc_rbus_memt = rbus_pccbb_parent_mem(pa);
+#endif /* rbus */
+
+ sc->sc_base_memh = 0;
+
+ /*
+ * 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 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,
+ sockbase);
+ /* give up... allocate reg space via rbus. */
+ printf("***** HOI!\n");
+ sc->sc_base_memh = 0;
+ pci_conf_write(pc, pa->pa_tag, PCI_SOCKBASE, 0);
+ }
+ } else {
+ DPRINTF(("%s: socket base address 0x%lx\n",
+ sc->sc_dev.dv_xname, sockbase));
+ }
+ }
+
+ sc->sc_mem_start = 0; /* XXX */
+ sc->sc_mem_end = 0xffffffff; /* XXX */
+
+ /*
+ * When interrupt isn't routed correctly, give up probing cbb and do
+ * not kill pcic-compatible port.
+ */
+ if ((0 == pa->pa_intrline) || (255 == pa->pa_intrline)) {
+ printf("\n%s: NOT USED because of unconfigured interrupt\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /*
+ * When bus number isn't set correctly, give up using 32-bit CardBus
+ * mode.
+ */
+ busreg = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM);
+#if notyet
+ if (((busreg >> 8) & 0xff) == 0) {
+ printf("%s: CardBus support disabled because of unconfigured bus number\n",
+ sc->sc_dev.dv_xname);
+ flags |= PCCBB_PCMCIA_16BITONLY;
+ }
+#endif
+
+ /* pccbb_machdep.c end */
+
+#if defined CBB_DEBUG
+ {
+ static char *intrname[5] = { "NON", "A", "B", "C", "D" };
+ printf("%s: intrpin %s, intrtag %d\n", sc->sc_dev.dv_xname,
+ 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_dmat = pa->pa_dmat;
+ 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;
+
+ sc->sc_pcmcia_flags = flags; /* set PCMCIA facility */
+
+ shutdownhook_establish(pccbb_shutdown, sc);
+
+#if 0
+ config_defer(self, pccbb_pci_callback);
+#endif
+ pccbb_pci_callback(self);
+}
+
+
+
+
+/*
+ * static void pccbb_pci_callback(struct device *self)
+ *
+ * The actual attach routine: get memory space for YENTA register
+ * space, setup YENTA register and route interrupt.
+ *
+ * This function should be deferred because this device may obtain
+ * memory space dynamically. This function must avoid obtaining
+ * memory area which has already kept for another device. Also,
+ * this function MUST be done before ISA attach process because this
+ * function kills pcic compatible port used by ISA pcic.
+ */
+static void
+pccbb_pci_callback(self)
+ struct device *self;
+{
+ struct pccbb_softc *sc = (void *)self;
+ pci_chipset_tag_t pc = sc->sc_pc;
+ 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;
+ bus_addr_t sockbase;
+ struct cbslot_attach_args cba;
+ struct pcmciabus_attach_args paa;
+ struct cardslot_attach_args caa;
+ struct cardslot_softc *csc;
+
+ if (0 == sc->sc_base_memh) {
+ /* The socket registers aren't mapped correctly. */
+#if rbus
+ if (rbus_space_alloc(sc->sc_rbus_memt, 0, 0x1000, 0x0fff,
+ (sc->sc_chipset == CB_RX5C47X
+ || sc->sc_chipset == CB_TI113X) ? 0x10000 : 0x1000,
+ 0, &sockbase, &sc->sc_base_memh)) {
+ return;
+ }
+ sc->sc_base_memt = sc->sc_memt;
+ pci_conf_write(pc, sc->sc_tag, PCI_SOCKBASE, sockbase);
+ DPRINTF(("%s: CardBus resister address 0x%lx -> 0x%x\n",
+ sc->sc_dev.dv_xname, sockbase, pci_conf_read(pc, sc->sc_tag,
+ PCI_SOCKBASE)));
+#else
+ sc->sc_base_memt = sc->sc_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, 0x1000, 0, 0, &sockbase, &sc->sc_base_memh)) {
+ /* cannot allocate memory space */
+ return;
+ }
+ pci_conf_write(pc, sc->sc_tag, PCI_SOCKBASE, sockbase);
+ DPRINTF(("%s: CardBus resister address 0x%x -> 0x%x\n",
+ sc->sc_dev.dv_xname, sock_base, pci_conf_read(pc,
+ sc->sc_tag, PCI_SOCKBASE)));
+#endif
+ }
+
+ /* bus bridge initialization */
+ pccbb_chipinit(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, sc->sc_intrtag, sc->sc_intrpin,
+ sc->sc_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, pccbbintr, sc,
+ sc->sc_dev.dv_xname);
+
+ 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\n", intrstr);
+ powerhook_establish(pccbb_powerhook, sc);
+
+ {
+ u_int32_t sockstat =
+ bus_space_read_4(base_memt, base_memh, CB_SOCKET_STAT);
+ if (0 == (sockstat & CB_SOCKET_STAT_CD)) {
+ sc->sc_flags |= CBB_CARDEXIST;
+ }
+ }
+
+ /*
+ * attach cardbus
+ */
+ if (!(sc->sc_pcmcia_flags & PCCBB_PCMCIA_16BITONLY)) {
+ pcireg_t busreg = pci_conf_read(pc, sc->sc_tag, PCI_BUSNUM);
+ pcireg_t bhlc = pci_conf_read(pc, sc->sc_tag, PCI_BHLC_REG);
+
+ /* initialize cbslot_attach */
+ cba.cba_busname = "cardbus";
+ cba.cba_iot = sc->sc_iot;
+ cba.cba_memt = sc->sc_memt;
+ cba.cba_dmat = sc->sc_dmat;
+ cba.cba_bus = (busreg >> 8) & 0x0ff;
+ cba.cba_cc = (void *)sc;
+ cba.cba_cf = &pccbb_funcs;
+ cba.cba_intrline = sc->sc_intrline;
+
+#if rbus
+ cba.cba_rbus_iot = sc->sc_rbus_iot;
+ cba.cba_rbus_memt = sc->sc_rbus_memt;
+#endif
+
+ cba.cba_cacheline = PCI_CACHELINE(bhlc);
+ cba.cba_lattimer = PCI_CB_LATENCY(busreg);
+
+#if defined CBB_DEBUG
+ printf("%s: cacheline 0x%x lattimer 0x%x\n",
+ sc->sc_dev.dv_xname, cba.cba_cacheline, cba.cba_lattimer);
+ printf("%s: bhlc 0x%x lscp 0x%x\n", sc->sc_dev.dv_xname, bhlc,
+ busreg);
+#endif
+#if defined SHOW_REGS
+ cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt,
+ sc->sc_base_memh);
+#endif
+ }
+
+ pccbb_pcmcia_attach_setup(sc, &paa);
+ caa.caa_cb_attach = NULL;
+ if (!(sc->sc_pcmcia_flags & PCCBB_PCMCIA_16BITONLY)) {
+ caa.caa_cb_attach = &cba;
+ }
+ caa.caa_16_attach = &paa;
+ caa.caa_ph = &sc->sc_pcmcia_h;
+
+ if (NULL != (csc = (void *)config_found(self, &caa, cbbprint))) {
+ DPRINTF(("pccbbattach: found cardslot\n"));
+ sc->sc_csc = csc;
+ }
+
+ return;
+}
+
+
+
+
+
+/*
+ * static void pccbb_chipinit(struct pccbb_softc *sc)
+ *
+ * This function initialize YENTA chip registers listed below:
+ * 1) PCI command reg,
+ * 2) PCI and CardBus latency timer,
+ * 3) disable legacy (PCIC-compatible) io,
+ * 4) route PCI interrupt,
+ * 5) close all memory and io windows.
+ */
+static void
+pccbb_chipinit(sc)
+ struct pccbb_softc *sc;
+{
+ pci_chipset_tag_t pc = sc->sc_pc;
+ pcitag_t tag = sc->sc_tag;
+ pcireg_t reg;
+
+ /*
+ * Set PCI command reg.
+ * Some laptop's BIOSes (i.e. TICO) do not enable CardBus chip.
+ */
+ reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+ /* I believe it is harmless. */
+ reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
+ PCI_COMMAND_MASTER_ENABLE);
+ pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg);
+
+ /*
+ * Set CardBus latency timer.
+ */
+ reg = pci_conf_read(pc, tag, PCI_CB_LSCP_REG);
+ if (PCI_CB_LATENCY(reg) < 0x20) {
+ reg &= ~(PCI_CB_LATENCY_MASK << PCI_CB_LATENCY_SHIFT);
+ reg |= (0x20 << PCI_CB_LATENCY_SHIFT);
+ pci_conf_write(pc, tag, PCI_CB_LSCP_REG, reg);
+ }
+ DPRINTF(("CardBus latency timer 0x%x (%x)\n",
+ PCI_CB_LATENCY(reg), pci_conf_read(pc, tag, PCI_CB_LSCP_REG)));
+
+ /*
+ * Set PCI latency timer.
+ */
+ reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ if (PCI_LATTIMER(reg) < 0x10) {
+ reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
+ reg |= (0x10 << PCI_LATTIMER_SHIFT);
+ pci_conf_write(pc, tag, PCI_BHLC_REG, reg);
+ }
+ DPRINTF(("PCI latency timer 0x%x (%x)\n",
+ PCI_LATTIMER(reg), pci_conf_read(pc, tag, PCI_BHLC_REG)));
+
+ /* Disable legacy register mapping. */
+ switch (sc->sc_chipset) {
+ case CB_RX5C46X: /* fallthrough */
+#if 0
+ case CB_RX5C47X:
+#endif
+ /*
+ * The legacy pcic io-port on Ricoh CardBus bridges cannot be
+ * disabled by substituting 0 into PCI_LEGACY register. Ricoh
+ * CardBus bridges have special bits on Bridge control reg (addr
+ * 0x3e on PCI config space).
+ */
+ reg = pci_conf_read(pc, tag, PCI_BCR_INTR);
+ reg &= ~(CB_BCRI_RL_3E0_ENA | CB_BCRI_RL_3E2_ENA);
+ pci_conf_write(pc, tag, PCI_BCR_INTR, reg);
+ break;
+
+ default:
+ /* XXX I don't know proper way to kill legacy I/O. */
+ pci_conf_write(pc, tag, PCI_LEGACY, 0x0);
+ break;
+ }
+
+ /* Route functional interrupts to PCI. */
+ reg = pci_conf_read(pc, tag, PCI_BCR_INTR);
+ reg &= ~CB_BCR_INTR_IREQ_ENABLE; /* use PCI Intr */
+ reg |= CB_BCR_WRITE_POST_ENABLE; /* enable write post */
+ pci_conf_write(pc, tag, PCI_BCR_INTR, reg);
+
+ switch (sc->sc_chipset) {
+ case CB_TI113X:
+ reg = pci_conf_read(pc, tag, PCI_CBCTRL);
+ /* This bit is shared, but may read as 0 on some chips, so set
+ it explicitly on both functions. */
+ reg |= PCI113X_CBCTRL_PCI_IRQ_ENA;
+ /* CSC intr enable */
+ reg |= PCI113X_CBCTRL_PCI_CSC;
+ /* functional intr prohibit */
+ reg &= ~PCI113X_CBCTRL_PCI_INTR;
+ pci_conf_write(pc, tag, PCI_CBCTRL, reg);
+ break;
+
+ case CB_TOPIC95B:
+ reg = pci_conf_read(pc, tag, TOPIC_SOCKET_CTRL);
+ reg |= TOPIC_SOCKET_CTRL_SCR_IRQSEL;
+ pci_conf_write(pc, tag, TOPIC_SOCKET_CTRL, reg);
+
+ reg = pci_conf_read(pc, tag, TOPIC_SLOT_CTRL);
+ DPRINTF(("%s: topic slot ctrl reg 0x%x -> ",
+ sc->sc_dev.dv_xname, reg));
+ reg |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
+ TOPIC_SLOT_CTRL_ID_LOCK | TOPIC_SLOT_CTRL_CARDBUS);
+ reg &= ~TOPIC_SLOT_CTRL_SWDETECT;
+ DPRINTF(("0x%x\n", reg));
+ pci_conf_write(pc, tag, TOPIC_SLOT_CTRL, reg);
+ break;
+ }
+
+ /* Close all memory and I/O windows. */
+ pci_conf_write(pc, tag, PCI_CB_MEMBASE0, 0xffffffff);
+ pci_conf_write(pc, tag, PCI_CB_MEMLIMIT0, 0);
+ pci_conf_write(pc, tag, PCI_CB_MEMBASE1, 0xffffffff);
+ pci_conf_write(pc, tag, PCI_CB_MEMLIMIT1, 0);
+ pci_conf_write(pc, tag, PCI_CB_IOBASE0, 0xffffffff);
+ pci_conf_write(pc, tag, PCI_CB_IOLIMIT0, 0);
+ pci_conf_write(pc, tag, PCI_CB_IOBASE1, 0xffffffff);
+ pci_conf_write(pc, tag, PCI_CB_IOLIMIT1, 0);
+}
+
+
+
+
+/*
+ * STATIC void pccbb_pcmcia_attach_setup(struct pccbb_softc *sc,
+ * struct pcmciabus_attach_args *paa)
+ *
+ * This function attaches 16-bit PCcard bus.
+ */
+STATIC void
+pccbb_pcmcia_attach_setup(sc, paa)
+ struct pccbb_softc *sc;
+ struct pcmciabus_attach_args *paa;
+{
+ struct pcic_handle *ph = &sc->sc_pcmcia_h;
+#if rbus
+ rbus_tag_t rb;
+#endif
+
+ /* initialize pcmcia part in pccbb_softc */
+ ph->ph_parent = (struct device *)sc;
+ ph->sock = sc->sc_function;
+ ph->flags = 0;
+ ph->shutdown = 0;
+ ph->ih_irq = sc->sc_intrline;
+ ph->ph_bus_t = sc->sc_base_memt;
+ ph->ph_bus_h = sc->sc_base_memh;
+ ph->ph_read = pccbb_pcmcia_read;
+ ph->ph_write = pccbb_pcmcia_write;
+ sc->sc_pct = &pccbb_pcmcia_funcs;
+
+ /*
+ * We need to do a few things here:
+ * 1) Disable routing of CSC and functional interrupts to ISA IRQs by
+ * setting the IRQ numbers to 0.
+ * 2) Set bit 4 of PCIC_INTR, which is needed on some chips to enable
+ * routing of CSC interrupts (e.g. card removal) to PCI while in
+ * PCMCIA mode. We just leave this set all the time.
+ * 3) Enable card insertion/removal interrupts in case the chip also
+ * needs that while in PCMCIA mode.
+ * 4) Clear any pending CSC interrupt.
+ */
+ Pcic_write(ph, PCIC_INTR, PCIC_INTR_ENABLE | PCIC_INTR_RESET);
+ Pcic_write(ph, PCIC_CSC_INTR, PCIC_CSC_INTR_CD_ENABLE);
+ Pcic_read(ph, PCIC_CSC);
+
+ /* initialize 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;
+#if rbus
+ rb = ((struct pccbb_softc *)(ph->ph_parent))->sc_rbus_iot;
+ paa->iobase = rb->rb_start + rb->rb_offset;
+ paa->iosize = rb->rb_end - rb->rb_start;
+#endif
+
+ return;
+}
+
+#if 0
+STATIC void
+pccbb_pcmcia_attach_card(ph)
+ struct pcic_handle *ph;
+{
+ if (ph->flags & PCIC_FLAG_CARDP) {
+ panic("pccbb_pcmcia_attach_card: already attached");
+ }
+
+ /* call the MI attach function */
+ pcmcia_card_attach(ph->pcmcia);
+
+ ph->flags |= PCIC_FLAG_CARDP;
+}
+
+STATIC void
+pccbb_pcmcia_detach_card(ph, flags)
+ struct pcic_handle *ph;
+ int flags;
+{
+ if (!(ph->flags & PCIC_FLAG_CARDP)) {
+ panic("pccbb_pcmcia_detach_card: already detached");
+ }
+
+ ph->flags &= ~PCIC_FLAG_CARDP;
+
+ /* call the MI detach function */
+ pcmcia_card_detach(ph->pcmcia, flags);
+}
+#endif
+
+/*
+ * 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 = (struct pccbb_softc *)arg;
+ u_int32_t sockevent, sockstate;
+ bus_space_tag_t memt = sc->sc_base_memt;
+ bus_space_handle_t memh = sc->sc_base_memh;
+ struct pcic_handle *ph = &sc->sc_pcmcia_h;
+
+ sockevent = bus_space_read_4(memt, memh, CB_SOCKET_EVENT);
+ bus_space_write_4(memt, memh, CB_SOCKET_EVENT, sockevent);
+ Pcic_read(ph, PCIC_CSC);
+
+ if (sockevent == 0) {
+ /* This intr is not for me: it may be for my child devices. */
+ return (pccbbintr_function(sc));
+ }
+
+ if (sockevent & CB_SOCKET_EVENT_CD) {
+ sockstate = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
+ if (CB_SOCKET_STAT_CD == (sockstate & CB_SOCKET_STAT_CD)) {
+ /* A card should be removed. */
+ if (sc->sc_flags & CBB_CARDEXIST) {
+ DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname,
+ sockevent));
+ DPRINTF((" card removed, 0x%08x\n", sockstate));
+ sc->sc_flags &= ~CBB_CARDEXIST;
+ if (sc->sc_csc->sc_status &
+ CARDSLOT_STATUS_CARD_16) {
+#if 0
+ struct pcic_handle *ph =
+ &sc->sc_pcmcia_h;
+
+ pcmcia_card_deactivate(ph->pcmcia);
+ pccbb_pcmcia_socket_disable(ph);
+ pccbb_pcmcia_detach_card(ph,
+ DETACH_FORCE);
+#endif
+ cardslot_event_throw(sc->sc_csc,
+ CARDSLOT_EVENT_REMOVAL_16);
+ } else if (sc->sc_csc->sc_status &
+ CARDSLOT_STATUS_CARD_CB) {
+ /* Cardbus intr removed */
+ cardslot_event_throw(sc->sc_csc,
+ CARDSLOT_EVENT_REMOVAL_CB);
+ }
+ }
+ } else if (0x00 == (sockstate & CB_SOCKET_STAT_CD) &&
+ /*
+ * The pccbbintr may called from powerdown hook when
+ * the system resumed, to detect the card
+ * insertion/removal during suspension.
+ */
+ (sc->sc_flags & CBB_CARDEXIST) == 0) {
+ if (sc->sc_flags & CBB_INSERTING) {
+ untimeout(pci113x_insert, sc);
+ }
+ timeout(pci113x_insert, sc, hz / 10);
+ sc->sc_flags |= CBB_INSERTING;
+ }
+ }
+
+ return (1);
+}
+
+/*
+ * static int pccbbintr_function(struct pccbb_softc *sc)
+ *
+ * This function calls each interrupt handler registered at the
+ * bridge. The interrupt handlers are called in registered order.
+ */
+static int
+pccbbintr_function(sc)
+ struct pccbb_softc *sc;
+{
+ int retval = 0, val;
+ struct pccbb_intrhand_list *pil;
+
+ for (pil = sc->sc_pil; pil != NULL; pil = pil->pil_next) {
+ val = (*pil->pil_func) (pil->pil_arg);
+ retval = retval == 1 ? 1 :
+ retval == 0 ? val : val != 0 ? val : retval;
+ }
+
+ return retval;
+}
+
+static void
+pci113x_insert(arg)
+ void *arg;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)arg;
+ u_int32_t sockevent, sockstate;
+
+ 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);
+
+ if (0 == (sockstate & CB_SOCKET_STAT_CD)) { /* card exist */
+ DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname, sockevent));
+ DPRINTF((" card inserted, 0x%08x\n", sockstate));
+ sc->sc_flags |= CBB_CARDEXIST;
+ /* call pccard interrupt handler here */
+ if (sockstate & CB_SOCKET_STAT_16BIT) {
+ /* 16-bit card found */
+/* pccbb_pcmcia_attach_card(&sc->sc_pcmcia_h); */
+ cardslot_event_throw(sc->sc_csc,
+ CARDSLOT_EVENT_INSERTION_16);
+ } else if (sockstate & CB_SOCKET_STAT_CB) {
+ /* cardbus card found */
+/* cardbus_attach_card(sc->sc_csc); */
+ cardslot_event_throw(sc->sc_csc,
+ CARDSLOT_EVENT_INSERTION_CB);
+ } else {
+ /* who are you? */
+ }
+ } else {
+ timeout(pci113x_insert, sc, hz / 10);
+ }
+}
+
+#define PCCBB_PCMCIA_OFFSET 0x800
+static u_int8_t
+pccbb_pcmcia_read(ph, reg)
+ struct pcic_handle *ph;
+ int reg;
+{
+ return bus_space_read_1(ph->ph_bus_t, ph->ph_bus_h,
+ PCCBB_PCMCIA_OFFSET + reg);
+}
+
+static void
+pccbb_pcmcia_write(ph, reg, val)
+ struct pcic_handle *ph;
+ int reg;
+ u_int8_t val;
+{
+ bus_space_write_1(ph->ph_bus_t, ph->ph_bus_h, PCCBB_PCMCIA_OFFSET + reg,
+ val);
+}
+
+/*
+ * 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);
+
+ delay(20 * 1000); /* wait 20 ms: Vcc setup time */
+ /*
+ * XXX delay 200 ms: though the standard defines that the Vcc set-up
+ * time is 20 ms, some PC-Card bridge requires longer duration.
+ */
+ delay(200 * 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);
+ 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));
+#if 0
+ 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 */
+}
+
+#if defined CB_PCMCIA_POLL
+struct cb_poll_str {
+ void *arg;
+ int (*func) __P((void *));
+ int level;
+ pccard_chipset_tag_t ct;
+ int count;
+};
+
+static struct cb_poll_str cb_poll[10];
+static int cb_poll_n = 0;
+
+static void cb_pcmcia_poll __P((void *arg));
+
+static void
+cb_pcmcia_poll(arg)
+ void *arg;
+{
+ struct cb_poll_str *poll = arg;
+ struct cbb_pcmcia_softc *psc = (void *)poll->ct->v;
+ struct pccbb_softc *sc = psc->cpc_parent;
+ int s;
+ u_int32_t spsr; /* socket present-state reg */
+
+ timeout(cb_pcmcia_poll, arg, hz / 10);
+ 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);
+
+#if defined CB_PCMCIA_POLL_ONLY && defined LEVEL2
+ if (!(spsr & 0x40)) { /* CINT low */
+#else
+ if (1) {
+#endif
+ if ((*poll->func) (poll->arg) == 1) {
+ ++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 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;
+
+ /* CD1 and CD2 asserted */
+ if (0x00 == (sockstat & CB_SOCKET_STAT_CD)) {
+ /* 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 CardBus card.
+ */
+STATIC int
+cb_reset(sc)
+ struct pccbb_softc *sc;
+{
+ /*
+ * Reset Assert at least 20 ms
+ * Some machines request longer duration.
+ */
+ int reset_duration =
+ (sc->sc_chipset == CB_RX5C47X ? 400 * 1000 : 40 * 1000);
+ u_int32_t bcr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR);
+
+ bcr |= (0x40 << 16); /* Reset bit Assert (bit 6 at 0x3E) */
+ pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BCR_INTR, bcr);
+ delay(reset_duration);
+
+ 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(reset_duration);
+ }
+ /* 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
+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;
+}
+
+/*
+ * 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;
+}
+
+#if !rbus
+/*
+ * 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;
+}
+#endif
+
+/*
+ * static void *pccbb_cb_intr_establish(cardbus_chipset_tag_t ct,
+ * int irq,
+ * int level,
+ * int (* func) __P((void *)),
+ * void *arg)
+ *
+ * This function registers an interrupt handler at the bridge, in
+ * order not to call the interrupt handlers of child devices when
+ * a card-deletion interrupt occurs.
+ *
+ * The arguments irq and level are not used.
+ */
+static void *
+pccbb_cb_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;
+
+ return pccbb_intr_establish(sc, irq, level, func, arg);
+}
+
+
+/*
+ * static void *pccbb_cb_intr_disestablish(cardbus_chipset_tag_t ct,
+ * void *ih)
+ *
+ * This function removes an interrupt handler pointed by ih.
+ */
+static void
+pccbb_cb_intr_disestablish(ct, ih)
+ cardbus_chipset_tag_t ct;
+ void *ih;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ pccbb_intr_disestablish(sc, ih);
+}
+
+
+/*
+ * static void *pccbb_intr_establish(struct pccbb_softc *sc,
+ * int irq,
+ * int level,
+ * int (* func) __P((void *)),
+ * void *arg)
+ *
+ * This function registers an interrupt handler at the bridge, in
+ * order not to call the interrupt handlers of child devices when
+ * a card-deletion interrupt occurs.
+ *
+ * The arguments irq and level are not used.
+ */
+static void *
+pccbb_intr_establish(sc, irq, level, func, arg)
+ struct pccbb_softc *sc;
+ int irq, level;
+ int (*func) __P((void *));
+ void *arg;
+{
+ struct pccbb_intrhand_list *pil, *newpil;
+
+ DPRINTF(("pccbb_intr_establish start. %p\n", sc->sc_pil));
+
+ if (sc->sc_pil == NULL) {
+ /* initialize bridge intr routing */
+
+ switch (sc->sc_chipset) {
+ case CB_TI113X:
+ {
+ pcireg_t cbctrl =
+ pci_conf_read(sc->sc_pc, sc->sc_tag,
+ PCI_CBCTRL);
+ /* functional intr enabled */
+ cbctrl |= PCI113X_CBCTRL_PCI_INTR;
+ pci_conf_write(sc->sc_pc, sc->sc_tag,
+ PCI_CBCTRL, cbctrl);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Allocate a room for interrupt handler structure.
+ */
+ if (NULL == (newpil =
+ (struct pccbb_intrhand_list *)malloc(sizeof(struct
+ pccbb_intrhand_list), M_DEVBUF, M_WAITOK))) {
+ return NULL;
+ }
+
+ newpil->pil_func = func;
+ newpil->pil_arg = arg;
+ newpil->pil_next = NULL;
+
+ if (sc->sc_pil == NULL) {
+ sc->sc_pil = newpil;
+ } else {
+ for (pil = sc->sc_pil; pil->pil_next != NULL;
+ pil = pil->pil_next);
+ pil->pil_next = newpil;
+ }
+
+ DPRINTF(("pccbb_intr_establish add pil. %p\n", sc->sc_pil));
+
+ return newpil;
+}
+
+/*
+ * static void *pccbb_intr_disestablish(struct pccbb_softc *sc,
+ * void *ih)
+ *
+ * This function removes an interrupt handler pointed by ih.
+ */
+static void
+pccbb_intr_disestablish(sc, ih)
+ struct pccbb_softc *sc;
+ void *ih;
+{
+ struct pccbb_intrhand_list *pil, **pil_prev;
+
+ DPRINTF(("pccbb_intr_disestablish start. %p\n", sc->sc_pil));
+
+ pil_prev = &sc->sc_pil;
+
+ for (pil = sc->sc_pil; pil != NULL; pil = pil->pil_next) {
+ if (pil == ih) {
+ *pil_prev = pil->pil_next;
+ free(pil, M_DEVBUF);
+ DPRINTF(("pccbb_intr_disestablish frees one pil\n"));
+ break;
+ }
+ pil_prev = &pil->pil_next;
+ }
+
+ if (sc->sc_pil == NULL) {
+ /* No interrupt handlers */
+
+ DPRINTF(("pccbb_intr_disestablish: no interrupt handler\n"));
+
+ switch (sc->sc_chipset) {
+ case CB_TI113X:
+ {
+ pcireg_t cbctrl =
+ pci_conf_read(sc->sc_pc, sc->sc_tag,
+ PCI_CBCTRL);
+ /* functional intr disabled */
+ cbctrl &= ~PCI113X_CBCTRL_PCI_INTR;
+ pci_conf_write(sc->sc_pc, sc->sc_tag,
+ PCI_CBCTRL, cbctrl);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+#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(" %08x", pci_conf_read(pc, tag, i));
+ }
+ for (i = 0x80; i < 0xb0; i += 4) {
+ if (i % 16 == 0) {
+ printf("\n 0x%02x:", i);
+ }
+ printf(" %08x", pci_conf_read(pc, tag, i));
+ }
+
+ if (memh == 0) {
+ 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(cc, tag)
+ cardbus_chipset_tag_t cc;
+ cardbustag_t tag;
+{
+}
+
+/*
+ * 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(cc, tag, offset)
+ cardbus_chipset_tag_t cc;
+ cardbustag_t tag;
+ int offset; /* register offset */
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)cc;
+
+ 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(cc, tag, reg, val)
+ cardbus_chipset_tag_t cc;
+ cardbustag_t tag;
+ int reg; /* register offset */
+ cardbusreg_t val;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)cc;
+
+ pci_conf_write(sc->sc_pc, tag, reg, val);
+}
+
+#if 0
+STATIC int
+pccbb_new_pcmcia_io_alloc(pcmcia_chipset_handle_t pch,
+ bus_addr_t start, bus_size_t size, bus_size_t align, bus_addr_t mask,
+ int speed, int flags,
+ bus_space_handle_t * iohp)
+#endif
+/*
+ * 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 allocated 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 pcic_handle *ph = (struct pcic_handle *)pch;
+ bus_addr_t ioaddr;
+ int flags = 0;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+#if rbus
+ rbus_tag_t rb;
+#endif
+ if (align == 0) {
+ align = size; /* XXX: funny??? */
+ }
+
+ /*
+ * Allocate some arbitrary I/O space.
+ */
+
+ iot = ((struct pccbb_softc *)(ph->ph_parent))->sc_iot;
+
+#if rbus
+ rb = ((struct pccbb_softc *)(ph->ph_parent))->sc_rbus_iot;
+ /* XXX: I assume all card decode lower 10 bits by its hardware */
+ if (rbus_space_alloc(rb, start, size, 0x3ff, align, 0, &ioaddr, &ioh)) {
+ return 1;
+ }
+#else
+ 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));
+ }
+#endif
+
+ 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;
+{
+#if !rbus
+ bus_space_tag_t iot = pcihp->iot;
+#endif
+ bus_space_handle_t ioh = pcihp->ioh;
+ bus_size_t size = pcihp->size;
+
+#if rbus
+ struct pccbb_softc *sc =
+ (struct pccbb_softc *)((struct pcic_handle *)pch)->ph_parent;
+ rbus_tag_t rb = sc->sc_rbus_iot;
+
+ rbus_space_free(rb, ioh, size, NULL);
+#else
+ if (pcihp->flags & PCMCIA_IO_ALLOCATED)
+ bus_space_free(iot, ioh, size);
+ else
+ bus_space_unmap(iot, ioh, size);
+#endif
+}
+
+/*
+ * 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 pcic_handle *ph = (struct 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 (((struct pccbb_softc *)ph->ph_parent)->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 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 unmaps I/O region. No return value.
+ */
+STATIC void
+pccbb_pcmcia_io_unmap(pch, win)
+ pcmcia_chipset_handle_t pch;
+ int win;
+{
+ struct pcic_handle *ph = (struct 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 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 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 pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+ int cardtype, win;
+ u_int8_t power, intr;
+ pcireg_t spsr;
+ int voltage;
+
+ /* this bit is mostly stolen from pcic_attach_card */
+
+ DPRINTF(("pccbb_pcmcia_socket_enable: "));
+
+ /* 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) {
+ DPRINTF(("5V card\n"));
+ voltage = CARDBUS_VCC_5V | CARDBUS_VPP_VCC;
+ } else if (spsr & CB_SOCKET_STAT_3VCARD) {
+ DPRINTF(("3V card\n"));
+ 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 | PCIC_INTR_CARDTYPE_MASK);
+ 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 200ms until power fails (Tpf). Then, wait 100ms since
+ * we are changing Vcc (Toff).
+ */
+ /* delay(300*1000); too much */
+
+ /* 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); too much */
+
+ power = Pcic_read(ph, PCIC_PWRCTL);
+ power |= PCIC_PWRCTL_OE;
+ Pcic_write(ph, PCIC_PWRCTL, power);
+
+ /*
+ * hold RESET at least 10us.
+ */
+ delay(10);
+ delay(2 * 1000); /* XXX: TI1130 requires it. */
+ delay(20 * 1000); /* XXX: TI1130 requires it. */
+
+ /* clear the reset flag */
+
+ intr |= PCIC_INTR_RESET;
+ Pcic_write(ph, PCIC_INTR, intr);
+
+ /* 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 = pcmcia_card_gettype(ph->pcmcia);
+
+ 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->ph_parent->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 pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+ u_int8_t power, intr;
+
+ DPRINTF(("pccbb_pcmcia_socket_disable\n"));
+
+ /* reset signal asserting... */
+
+ intr = Pcic_read(ph, PCIC_INTR);
+ intr &= ~(PCIC_INTR_CARDTYPE_MASK);
+ 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_card_detect(pcmcia_chipset_handle_t *ph)
+ *
+ * This function detects whether a card is in the slot or not.
+ * If a card is inserted, return 1. Otherwise, return 0.
+ */
+STATIC int
+pccbb_pcmcia_card_detect(pch)
+ pcmcia_chipset_handle_t pch;
+{
+ struct pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+
+ DPRINTF(("pccbb_pcmcia_card_detect\n"));
+ return pccbb_detect_card(sc) == 1 ? 1 : 0;
+}
+
+#if 0
+STATIC int
+pccbb_new_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch,
+ bus_addr_t start, bus_size_t size, bus_size_t align, int speed, int flags,
+ bus_space_tag_t * memtp bus_space_handle_t * memhp)
+#endif
+/*
+ * 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 allocated 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 pcic_handle *ph = (struct pcic_handle *)pch;
+ bus_space_handle_t memh;
+ bus_addr_t addr;
+ bus_size_t sizepg;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+#if rbus
+ rbus_tag_t rb;
+#endif
+
+ /* 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 rbus
+ rb = sc->sc_rbus_memt;
+ if (rbus_space_alloc(rb, 0, sizepg * PCIC_MEM_PAGESIZE,
+ sizepg * PCIC_MEM_PAGESIZE - 1, PCIC_MEM_PAGESIZE, 0,
+ &addr, &memh)) {
+ return 1;
+ }
+#else
+ 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;
+ }
+#endif
+
+ DPRINTF(
+ ("pccbb_pcmcia_alloc_mem: addr 0x%lx size 0x%lx, realsize 0x%lx\n",
+ addr, size, 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 function
+ * pccbb_pcmcia_mem_alloc().
+ */
+STATIC void
+pccbb_pcmcia_mem_free(pch, pcmhp)
+ pcmcia_chipset_handle_t pch;
+ struct pcmcia_mem_handle *pcmhp;
+{
+#if rbus
+ struct pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+
+ rbus_space_free(sc->sc_rbus_memt, pcmhp->memh, pcmhp->realsize, NULL);
+#else
+ bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->realsize);
+#endif
+}
+
+/*
+ * STATIC void pccbb_pcmcia_do_mem_map(struct pcic_handle *ph, int win)
+ *
+ * This function release the memory space allocated by the function
+ * pccbb_pcmcia_mem_alloc().
+ */
+STATIC void
+pccbb_pcmcia_do_mem_map(ph, win)
+ struct 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;
+
+ int kind = ph->mem[win].kind & ~PCMCIA_WIDTH_MEM_MASK;
+ int mem8 =
+ (ph->mem[win].kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8
+ || (kind == PCMCIA_MEM_ATTR);
+
+ 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",
+ phys_addr, 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)
+
+ /* bit 19:12 */
+ start_low = (phys_addr >> PCIC_MEMREG_LSB_SHIFT) & 0xff;
+ /* bit 23:20 and bit 7 on */
+ start_high = ((phys_addr >> PCIC_MEMREG_MSB_SHIFT) & 0x0f)
+ |(mem8 ? 0 : PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT);
+ /* bit 31:24, for 32-bit address */
+ mem_window = (phys_addr >> PCIC_MEMREG_WIN_SHIFT) & 0xff;
+
+ Pcic_write(ph, regbase_win + PCIC_SMM_START_LOW, start_low);
+ Pcic_write(ph, regbase_win + PCIC_SMM_START_HIGH, start_high);
+
+ if (((struct pccbb_softc *)ph->
+ ph_parent)->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
+ Pcic_write(ph, 0x40 + win, mem_window);
+ }
+
+ 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)
+ | ((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 (((struct pccbb_softc *)(ph->
+ ph_parent))->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 (((struct pccbb_softc *)(ph->
+ ph_parent))->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 function
+ * 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 pcic_handle *ph = (struct 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 (((struct pccbb_softc *)ph->ph_parent)->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 function
+ * pccbb_pcmcia_mem_map().
+ */
+STATIC void
+pccbb_pcmcia_mem_unmap(pch, window)
+ pcmcia_chipset_handle_t pch;
+ int window;
+{
+ struct pcic_handle *ph = (struct 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 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 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);
+
+#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 pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+
+ 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!!
+ */
+ }
+
+ return pccbb_intr_establish(sc, IST_LEVEL, ipl, func, arg);
+}
+
+/*
+ * 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 pcic_handle *ph = (struct pcic_handle *)pch;
+ struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
+
+ pccbb_intr_disestablish(sc, ih);
+}
+
+#if rbus
+/*
+ * static int
+ * pccbb_rbus_cb_space_alloc(cardbus_chipset_tag_t ct, rbus_tag_t rb,
+ * bus_addr_t addr, bus_size_t size,
+ * bus_addr_t mask, bus_size_t align,
+ * int flags, bus_addr_t *addrp;
+ * bus_space_handle_t *bshp)
+ *
+ * This function allocates a portion of memory or io space for
+ * clients. This function is called from CardBus card drivers.
+ */
+static int
+pccbb_rbus_cb_space_alloc(ct, rb, addr, size, mask, align, flags, addrp, bshp)
+ cardbus_chipset_tag_t ct;
+ rbus_tag_t rb;
+ bus_addr_t addr;
+ bus_size_t size;
+ bus_addr_t mask;
+ bus_size_t align;
+ int flags;
+ bus_addr_t *addrp;
+ bus_space_handle_t *bshp;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+
+ DPRINTF(
+ ("pccbb_rbus_cb_space_alloc: adr %lx, size %lx, mask %lx, align %lx\n",
+ addr, size, mask, align));
+
+ if (align == 0) {
+ align = size;
+ }
+
+ if (rb->rb_bt == sc->sc_memt) {
+ if (align < 16) {
+ return 1;
+ }
+ } else if (rb->rb_bt == sc->sc_iot) {
+ if (align < 4) {
+ return 1;
+ }
+ /* XXX: hack for avoiding ISA image */
+ if (mask < 0x0100) {
+ mask = 0x3ff;
+ addr = 0x300;
+ }
+
+ } else {
+ DPRINTF(
+ ("pccbb_rbus_cb_space_alloc: Bus space tag %x is NOT used.\n",
+ rb->rb_bt));
+ return 1;
+ /* XXX: panic here? */
+ }
+
+ if (rbus_space_alloc(rb, addr, size, mask, align, flags, addrp, bshp)) {
+ printf("%s: <rbus> no bus space\n", sc->sc_dev.dv_xname);
+ return 1;
+ }
+
+ pccbb_open_win(sc, rb->rb_bt, *addrp, size, *bshp, 0);
+
+ return 0;
+}
+
+/*
+ * static int
+ * pccbb_rbus_cb_space_free(cardbus_chipset_tag_t *ct, rbus_tag_t rb,
+ * bus_space_handle_t *bshp, bus_size_t size);
+ *
+ * This function is called from CardBus card drivers.
+ */
+static int
+pccbb_rbus_cb_space_free(ct, rb, bsh, size)
+ cardbus_chipset_tag_t ct;
+ rbus_tag_t rb;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ struct pccbb_softc *sc = (struct pccbb_softc *)ct;
+ bus_space_tag_t bt = rb->rb_bt;
+
+ pccbb_close_win(sc, bt, bsh, size);
+
+ if (bt == sc->sc_memt) {
+ } else if (bt == sc->sc_iot) {
+ } else {
+ return 1;
+ /* XXX: panic here? */
+ }
+
+ return rbus_space_free(rb, bsh, size, NULL);
+}
+#endif /* rbus */
+
+#if rbus
+
+static int
+pccbb_open_win(sc, bst, addr, size, bsh, flags)
+ struct pccbb_softc *sc;
+ bus_space_tag_t bst;
+ bus_addr_t addr;
+ bus_size_t size;
+ bus_space_handle_t bsh;
+ int flags;
+{
+ struct pccbb_win_chain_head *head;
+ bus_addr_t align;
+
+ head = &sc->sc_iowindow;
+ align = 0x04;
+ if (sc->sc_memt == bst) {
+ head = &sc->sc_memwindow;
+ align = 0x1000;
+ DPRINTF(("using memory window, %x %x %x\n\n",
+ sc->sc_iot, sc->sc_memt, bst));
+ }
+
+ if (pccbb_winlist_insert(head, addr, size, bsh, flags)) {
+ printf("%s: pccbb_open_win: %s winlist insert failed\n",
+ sc->sc_dev.dv_xname,
+ (head == &sc->sc_memwindow) ? "mem" : "io");
+ }
+ pccbb_winset(align, sc, bst);
+
+ return 0;
+}
+
+static int
+pccbb_close_win(sc, bst, bsh, size)
+ struct pccbb_softc *sc;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ struct pccbb_win_chain_head *head;
+ bus_addr_t align;
+
+ head = &sc->sc_iowindow;
+ align = 0x04;
+ if (sc->sc_memt == bst) {
+ head = &sc->sc_memwindow;
+ align = 0x1000;
+ }
+
+ if (pccbb_winlist_delete(head, bsh, size)) {
+ printf("%s: pccbb_close_win: %s winlist delete failed\n",
+ sc->sc_dev.dv_xname,
+ (head == &sc->sc_memwindow) ? "mem" : "io");
+ }
+ pccbb_winset(align, sc, bst);
+
+ return 0;
+}
+
+static int
+pccbb_winlist_insert(head, start, size, bsh, flags)
+ struct pccbb_win_chain_head *head;
+ bus_addr_t start;
+ bus_size_t size;
+ bus_space_handle_t bsh;
+ int flags;
+{
+ struct pccbb_win_chain *chainp, *elem;
+
+ if ((elem = malloc(sizeof(struct pccbb_win_chain), M_DEVBUF,
+ M_NOWAIT)) == NULL)
+ return (1); /* fail */
+
+ elem->wc_start = start;
+ elem->wc_end = start + (size - 1);
+ elem->wc_handle = bsh;
+ elem->wc_flags = flags;
+
+ for (chainp = TAILQ_FIRST(head); chainp != NULL;
+ chainp = TAILQ_NEXT(chainp, wc_list)) {
+ if (chainp->wc_end < start)
+ continue;
+ TAILQ_INSERT_AFTER(head, chainp, elem, wc_list);
+ return (0);
+ }
+
+ TAILQ_INSERT_TAIL(head, elem, wc_list);
+ return (0);
+}
+
+static int
+pccbb_winlist_delete(head, bsh, size)
+ struct pccbb_win_chain_head *head;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ struct pccbb_win_chain *chainp;
+
+ for (chainp = TAILQ_FIRST(head); chainp != NULL;
+ chainp = TAILQ_NEXT(chainp, wc_list)) {
+ if (chainp->wc_handle != bsh)
+ continue;
+ if ((chainp->wc_end - chainp->wc_start) != (size - 1)) {
+ printf("pccbb_winlist_delete: window 0x%lx size "
+ "inconsistent: 0x%lx, 0x%lx\n",
+ chainp->wc_start,
+ chainp->wc_end - chainp->wc_start,
+ size - 1);
+ return 1;
+ }
+
+ TAILQ_REMOVE(head, chainp, wc_list);
+ free(chainp, M_DEVBUF);
+
+ return 0;
+ }
+
+ return 1; /* fail: no candidate to remove */
+}
+
+static void
+pccbb_winset(align, sc, bst)
+ bus_addr_t align;
+ struct pccbb_softc *sc;
+ bus_space_tag_t bst;
+{
+ pci_chipset_tag_t pc;
+ pcitag_t tag;
+ bus_addr_t mask = ~(align - 1);
+ struct {
+ cardbusreg_t win_start;
+ cardbusreg_t win_limit;
+ int win_flags;
+ } win[2];
+ struct pccbb_win_chain *chainp;
+ int offs;
+
+ win[0].win_start = 0xffffffff;
+ win[0].win_limit = 0;
+ win[1].win_start = 0xffffffff;
+ win[1].win_limit = 0;
+
+ chainp = TAILQ_FIRST(&sc->sc_iowindow);
+ offs = 0x2c;
+ if (sc->sc_memt == bst) {
+ chainp = TAILQ_FIRST(&sc->sc_memwindow);
+ offs = 0x1c;
+ }
+
+ if (chainp != NULL) {
+ win[0].win_start = chainp->wc_start & mask;
+ win[0].win_limit = chainp->wc_end & mask;
+ win[0].win_flags = chainp->wc_flags;
+ chainp = TAILQ_NEXT(chainp, wc_list);
+ }
+
+ for (; chainp != NULL; chainp = TAILQ_NEXT(chainp, wc_list)) {
+ if (win[1].win_start == 0xffffffff) {
+ /* window 1 is not used */
+ if ((win[0].win_flags == chainp->wc_flags) &&
+ (win[0].win_limit + align >=
+ (chainp->wc_start & mask))) {
+ /* concatenate */
+ win[0].win_limit = chainp->wc_end & mask;
+ } else {
+ /* make new window */
+ win[1].win_start = chainp->wc_start & mask;
+ win[1].win_limit = chainp->wc_end & mask;
+ win[1].win_flags = chainp->wc_flags;
+ }
+ continue;
+ }
+
+ /* Both windows are engaged. */
+ if (win[0].win_flags == win[1].win_flags) {
+ /* same flags */
+ if (win[0].win_flags == chainp->wc_flags) {
+ if (win[1].win_start - (win[0].win_limit +
+ align) <
+ (chainp->wc_start & mask) -
+ ((chainp->wc_end & mask) + align)) {
+ /*
+ * merge window 0 and 1, and set win1
+ * to chainp
+ */
+ win[0].win_limit = win[1].win_limit;
+ win[1].win_start =
+ chainp->wc_start & mask;
+ win[1].win_limit =
+ chainp->wc_end & mask;
+ } else {
+ win[1].win_limit =
+ chainp->wc_end & mask;
+ }
+ } else {
+ /* different flags */
+
+ /* concatenate win0 and win1 */
+ win[0].win_limit = win[1].win_limit;
+ /* allocate win[1] to new space */
+ win[1].win_start = chainp->wc_start & mask;
+ win[1].win_limit = chainp->wc_end & mask;
+ win[1].win_flags = chainp->wc_flags;
+ }
+ } else {
+ /* the flags of win[0] and win[1] is different */
+ if (win[0].win_flags == chainp->wc_flags) {
+ win[0].win_limit = chainp->wc_end & mask;
+ /*
+ * XXX this creates overlapping windows, so
+ * what should the poor bridge do if one is
+ * cachable, and the other is not?
+ */
+ printf("%s: overlapping windows\n",
+ sc->sc_dev.dv_xname);
+ } else {
+ win[1].win_limit = chainp->wc_end & mask;
+ }
+ }
+ }
+
+ pc = sc->sc_pc;
+ tag = sc->sc_tag;
+ pci_conf_write(pc, tag, offs, win[0].win_start);
+ pci_conf_write(pc, tag, offs + 4, win[0].win_limit);
+ pci_conf_write(pc, tag, offs + 8, win[1].win_start);
+ pci_conf_write(pc, tag, offs + 12, win[1].win_limit);
+ DPRINTF(("--pccbb_winset: win0 [%x, %lx), win1 [%x, %lx)\n",
+ pci_conf_read(pc, tag, offs),
+ pci_conf_read(pc, tag, offs + 4) + align,
+ pci_conf_read(pc, tag, offs + 8),
+ pci_conf_read(pc, tag, offs + 12) + align));
+
+ if (bst == sc->sc_memt) {
+ if (win[0].win_flags & PCCBB_MEM_CACHABLE) {
+ pcireg_t bcr = pci_conf_read(pc, tag, PCI_BCR_INTR);
+ bcr |= CB_BCR_PREFETCH_MEMWIN0;
+ pci_conf_write(pc, tag, PCI_BCR_INTR, bcr);
+ }
+ if (win[1].win_flags & PCCBB_MEM_CACHABLE) {
+ pcireg_t bcr = pci_conf_read(pc, tag, PCI_BCR_INTR);
+ bcr |= CB_BCR_PREFETCH_MEMWIN1;
+ pci_conf_write(pc, tag, PCI_BCR_INTR, bcr);
+ }
+ }
+}
+
+#endif /* rbus */
+
+static void
+pccbb_powerhook(why, arg)
+ int why;
+ void *arg;
+{
+ struct pccbb_softc *sc = arg;
+ u_int32_t reg;
+ bus_space_tag_t base_memt = sc->sc_base_memt; /* socket regs memory */
+ bus_space_handle_t base_memh = sc->sc_base_memh;
+
+ DPRINTF(("%s: power: why %d\n", sc->sc_dev.dv_xname, why));
+
+ if (why == PWR_RESUME) {
+ /* CSC Interrupt: Card detect interrupt on */
+ reg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_MASK);
+ /* Card detect intr is turned on. */
+ reg |= CB_SOCKET_MASK_CD;
+ bus_space_write_4(base_memt, base_memh, CB_SOCKET_MASK, reg);
+ /* reset interrupt */
+ reg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_EVENT);
+ bus_space_write_4(base_memt, base_memh, CB_SOCKET_EVENT, reg);
+
+ /*
+ * check for card insertion or removal during suspend period.
+ * XXX: the code can't cope with card swap (remove then
+ * insert). how can we detect such situation?
+ */
+ (void)pccbbintr(sc);
+ }
+}
diff --git a/sys/dev/pci/pccbbreg.h b/sys/dev/pci/pccbbreg.h
new file mode 100644
index 00000000000..d027482a875
--- /dev/null
+++ b/sys/dev/pci/pccbbreg.h
@@ -0,0 +1,225 @@
+/* $OpenBSD: pccbbreg.h,v 1.1 2000/04/08 05:50:51 aaron Exp $ */
+/* $NetBSD: pccbbreg.h,v 1.4 2000/01/13 08:46:46 joda Exp $ */
+/*
+ * 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.
+ */
+
+
+#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 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 */
+
+#define PCCBB_SOCKEVENT_BITS "\020\001CSTS\002CD1\003CD2\004PWR"
+#define PCCBB_SOCKSTATE_BITS "\020\001CSTS\002CD1\003CD3\004PWR" \
+ "\00516BIT\006CB\007CINT\010NOTA\011DLOST\012BADVCC" \
+ "\0135v\0143v\015Xv\016Yv\0355vS\0363vS\037XvS\040YvS"
+
+/* 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 0x00800000
+#define CB_BCR_PREFETCH_MEMWIN0 0x01000000
+#define CB_BCR_PREFETCH_MEMWIN1 0x02000000
+#define CB_BCR_WRITE_POST_ENABLE 0x04000000
+
+/* 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 Rx5C46[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/dev/pci/pccbbvar.h b/sys/dev/pci/pccbbvar.h
new file mode 100644
index 00000000000..089f1f5b11c
--- /dev/null
+++ b/sys/dev/pci/pccbbvar.h
@@ -0,0 +1,174 @@
+/* $OpenBSD: pccbbvar.h,v 1.1 2000/04/08 05:50:51 aaron Exp $ */
+/* $NetBSD: pccbbvar.h,v 1.12 2000/03/23 07:01:40 thorpej Exp $ */
+/*
+ * 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.
+ */
+
+/* require sys/device.h */
+/* require sys/queue.h */
+/* require sys/callout.h */
+/* require dev/ic/i82365reg.h */
+/* require dev/ic/i82365var.h */
+
+#ifndef _DEV_PCI_PCCBBVAR_H_
+#define _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_RX5C47X 3 /* RICOH RX5C475/476/477 */
+#define CB_RX5C46X 4 /* RICOH RX5C465/466/467 */
+#define CB_TOPIC95 5 /* Toshiba ToPIC95 */
+#define CB_TOPIC95B 6 /* Toshiba ToPIC95B */
+#define CB_TOPIC97 7 /* Toshiba ToPIC97 */
+#define CB_CIRRUS 8 /* Cirrus Logic CL-PD683X */
+#define CB_CHIPS_LAST 9 /* Sentinel */
+
+#if 0
+static char *cb_chipset_name[CB_CHIPS_LAST] = {
+ "unknown", "TI 113X", "TI 12XX", "RF5C47X", "RF5C46X", "ToPIC95",
+ "ToPIC95B", "ToPIC97", "CL-PD 683X",
+};
+#endif
+
+struct pccbb_softc;
+struct pccbb_intrhand_list;
+
+
+struct cbb_pcic_handle {
+ struct device *ph_parent;
+ bus_space_tag_t ph_base_t;
+ bus_space_handle_t ph_base_h;
+ 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 pccbb_win_chain {
+ bus_addr_t wc_start; /* Caution: region [start, end], */
+ bus_addr_t wc_end; /* instead of [start, end). */
+ int wc_flags;
+ bus_space_handle_t wc_handle;
+ TAILQ_ENTRY(pccbb_win_chain) wc_list;
+};
+#define PCCBB_MEM_CACHABLE 1
+
+TAILQ_HEAD(pccbb_win_chain_head, pccbb_win_chain);
+
+struct pccbb_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+ bus_dma_tag_t sc_dmat;
+
+#if rbus
+ rbus_tag_t sc_rbus_iot; /* rbus for i/o donated from parent */
+ rbus_tag_t sc_rbus_memt; /* rbus for mem donated from parent */
+#endif
+
+ 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_INSERTING 0x01000000
+#define CBB_16BITCARD 0x04
+#define CBB_32BITCARD 0x08
+
+ 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 */
+ bus_addr_t sc_io_start; /* CardBus/PCMCIA io start */
+ bus_addr_t sc_io_end; /* CardBus/PCMCIA io end */
+
+ /* CardBus stuff */
+ struct cardslot_softc *sc_csc;
+
+ struct pccbb_win_chain_head sc_memwindow;
+ struct pccbb_win_chain_head sc_iowindow;
+
+ /* pcmcia stuff */
+ struct pcic_handle sc_pcmcia_h;
+ pcmcia_chipset_tag_t sc_pct;
+ int sc_pcmcia_flags;
+#define PCCBB_PCMCIA_IO_RELOC 0x01 /* IO addr relocatable stuff exists */
+#define PCCBB_PCMCIA_MEM_32 0x02 /* 32-bit memory address ready */
+#define PCCBB_PCMCIA_16BITONLY 0x04 /* 32-bit mode disable */
+
+ struct proc *sc_event_thread;
+ SIMPLEQ_HEAD(, pcic_event) sc_events;
+
+ /* interrupt handler list on the bridge */
+ struct pccbb_intrhand_list *sc_pil;
+ int sc_pil_intr_enable; /* can i call intr handler for child device? */
+};
+
+/*
+ * struct pccbb_intrhand_list holds interrupt handler and argument for
+ * child devices.
+ */
+
+struct pccbb_intrhand_list {
+ int (*pil_func) __P((void *));
+ void *pil_arg;
+ struct pccbb_intrhand_list *pil_next;
+};
+
+#endif /* _DEV_PCI_PCCBBREG_H_ */
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index a852cbc6322..c54a35d137a 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pcmcia,v 1.28 2000/04/03 01:02:00 mickey Exp $
+# $OpenBSD: files.pcmcia,v 1.29 2000/04/08 05:50:51 aaron Exp $
# $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $
#
# Config.new file and device description for machine-independent PCMCIA code.
@@ -10,7 +10,7 @@ file dev/pcmcia/pcmcia_cis.c pcmcia
file dev/pcmcia/pcmcia_cis_quirks.c pcmcia
# device declaration in sys/conf/files
-attach pcmcia at pcic
+attach pcmcia at pcmciabus
# 3Com 3c589 Ethernet, 3c562 multifunction Ethernet, and 3CXEM556
# multifunction Ethernet controllers
diff --git a/sys/dev/pcmcia/pcmcia.c b/sys/dev/pcmcia/pcmcia.c
index 24d2aefff23..f9b5710d5a0 100644
--- a/sys/dev/pcmcia/pcmcia.c
+++ b/sys/dev/pcmcia/pcmcia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcmcia.c,v 1.25 2000/02/05 22:10:50 deraadt Exp $ */
+/* $OpenBSD: pcmcia.c,v 1.26 2000/04/08 05:50:51 aaron Exp $ */
/* $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $ */
/*
@@ -102,6 +102,12 @@ pcmcia_match(parent, match, aux)
struct device *parent;
void *match, *aux;
{
+ struct cfdata *cf = match;
+ struct pcmciabus_attach_args *paa = aux;
+
+ if (strcmp(paa->paa_busname, cf->cf_driver->cd_name))
+ return 0;
+
/* If the autoconfiguration got this far, there's a socket here. */
return (1);
}
diff --git a/sys/dev/pcmcia/pcmciachip.h b/sys/dev/pcmcia/pcmciachip.h
index bbe25659f85..65821a53138 100644
--- a/sys/dev/pcmcia/pcmciachip.h
+++ b/sys/dev/pcmcia/pcmciachip.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: pcmciachip.h,v 1.2 1999/08/08 01:00:14 niklas Exp $ */
-/* $NetBSD: pcmciachip.h,v 1.2 1997/10/16 23:27:36 thorpej Exp $ */
+/* $OpenBSD: pcmciachip.h,v 1.3 2000/04/08 05:50:51 aaron Exp $ */
+/* $NetBSD: pcmciachip.h,v 1.5 2000/01/13 08:58:51 joda Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@@ -48,6 +48,11 @@ typedef int pcmcia_mem_handle_t;
#define PCMCIA_MEM_ATTR 1
#define PCMCIA_MEM_COMMON 2
+#define PCMCIA_WIDTH_MEM8 8
+#define PCMCIA_WIDTH_MEM16 16
+
+#define PCMCIA_WIDTH_MEM_MASK 24
+
#define PCMCIA_WIDTH_AUTO 0
#define PCMCIA_WIDTH_IO8 1
#define PCMCIA_WIDTH_IO16 2
@@ -84,6 +89,9 @@ struct pcmcia_chip_functions {
/* card enable/disable */
void (*socket_enable) __P((pcmcia_chipset_handle_t));
void (*socket_disable) __P((pcmcia_chipset_handle_t));
+
+ /* card detection */
+ int (*card_detect) __P((pcmcia_chipset_handle_t));
};
/* Memory space functions. */
@@ -130,6 +138,7 @@ struct pcmcia_chip_functions {
((*(tag)->socket_disable)((handle)))
struct pcmciabus_attach_args {
+ char *paa_busname; /* Bus name */
pcmcia_chipset_tag_t pct;
pcmcia_chipset_handle_t pch;
bus_addr_t iobase; /* start i/o space allocation here */
diff --git a/sys/kern/Makefile b/sys/kern/Makefile
index b5eeebf62c8..8d0f21f1b62 100644
--- a/sys/kern/Makefile
+++ b/sys/kern/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.7 1997/02/24 14:19:55 niklas Exp $
+# $OpenBSD: Makefile,v 1.8 2000/04/08 05:50:52 aaron Exp $
# Makefile for kernel tags files, init_sysent, etc.
@@ -33,8 +33,8 @@ DGEN= adosfs \
compat/linux compat/osf1 compat/sunos compat/svr4 compat/ultrix \
conf \
ddb \
- dev dev/eisa dev/ic dev/isa dev/pci dev/pcmcia dev/rcons dev/sun \
- dev/tc \
+ dev dev/eisa dev/ic dev/isa dev/pci dev/pcmcia dev/cardbus dev/rcons \
+ dev/sun dev/tc \
gnu \
isofs isofs/cd9660 \
kern \