-# $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
# 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
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
-# $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
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
# 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.
-/* $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 $ */
/*-
return (error);
}
+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)
--- /dev/null
+/* $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);
+}
-/* $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 $ */
/*-
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,
--- /dev/null
+/* $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_ */
-# $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
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
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
--- /dev/null
+/* $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
--- /dev/null
+/* $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
--- /dev/null
+/* $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_ */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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_ */
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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_ */
--- /dev/null
+# $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
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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_ */
-/* $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 $ */
/*
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
};
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++;
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++;
* 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],
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;
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 */
/* 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
}
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");
}
}
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();
}
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;
}
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;
h->event_thread = NULL;
/* In case parent is waiting for us to exit. */
- wakeup(h->sc);
+ wakeup(sc);
kthread_exit(0);
}
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.
/* 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);
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);
}
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;
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 =
}
}
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);
}
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 */
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;
}
}
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;
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 {
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) >>
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);
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]));
/* 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;
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;
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)
} 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",
#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. */
/* 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",
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 */
*/
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);
+}
-/* $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 $ */
/*
#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;
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,
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))
--- /dev/null
+/* $OpenBSD: xl.c,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: if_xl.c,v 1.72 2000/01/09 21:12:59 wpaul Exp $
+ */
+
+/*
+ * 3Com 3c90x Etherlink XL PCI NIC driver
+ *
+ * Supports the 3Com "boomerang", "cyclone", and "hurricane" PCI
+ * bus-master chips (3c90x cards and embedded controllers) including
+ * the following:
+ *
+ * 3Com 3c900-TPO 10Mbps/RJ-45
+ * 3Com 3c900-COMBO 10Mbps/RJ-45,AUI,BNC
+ * 3Com 3c905-TX 10/100Mbps/RJ-45
+ * 3Com 3c905-T4 10/100Mbps/RJ-45
+ * 3Com 3c900B-TPO 10Mbps/RJ-45
+ * 3Com 3c900B-COMBO 10Mbps/RJ-45,AUI,BNC
+ * 3Com 3c900B-TPC 10Mbps/RJ-45,BNC
+ * 3Com 3c900B-FL 10Mbps/Fiber-optic
+ * 3Com 3c905B-COMBO 10/100Mbps/RJ-45,AUI,BNC
+ * 3Com 3c905B-TX 10/100Mbps/RJ-45
+ * 3Com 3c900-FL/FX 10/100Mbps/Fiber-optic
+ * 3Com 3c905C-TX 10/100Mbps/RJ-45 (Tornado ASIC)
+ * 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
+ * Dell Precision on-board 3c905B 10/100Mbps/RJ-45
+ * Dell Latitude laptop docking station embedded 3c905-TX
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The 3c90x series chips use a bus-master DMA interface for transfering
+ * packets to and from the controller chip. Some of the "vortex" cards
+ * (3c59x) also supported a bus master mode, however for those chips
+ * you could only DMA packets to/from a contiguous memory buffer. For
+ * transmission this would mean copying the contents of the queued mbuf
+ * chain into a an mbuf cluster and then DMAing the cluster. This extra
+ * copy would sort of defeat the purpose of the bus master support for
+ * any packet that doesn't fit into a single mbuf.
+ *
+ * By contrast, the 3c90x cards support a fragment-based bus master
+ * mode where mbuf chains can be encapsulated using TX descriptors.
+ * This is similar to other PCI chips such as the Texas Instruments
+ * ThunderLAN and the Intel 82557/82558.
+ *
+ * The "vortex" driver (if_vx.c) happens to work for the "boomerang"
+ * bus master chips because they maintain the old PIO interface for
+ * backwards compatibility, but starting with the 3c905B and the
+ * "cyclone" chips, the compatibility interface has been dropped.
+ * Since using bus master DMA is a big win, we use this driver to
+ * support the PCI "boomerang" chips even though they work with the
+ * "vortex" driver in order to obtain better performance.
+ *
+ * This driver is in the /sys/pci directory because it only supports
+ * PCI-based NICs.
+ */
+
+#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 */
+
+#include <dev/ic/xlreg.h>
+
+int xl_newbuf __P((struct xl_softc *, struct xl_chain_onefrag *));
+void xl_stats_update __P((void *));
+int xl_encap __P((struct xl_softc *, struct xl_chain *,
+ struct mbuf * ));
+int xl_encap_90xB __P((struct xl_softc *, struct xl_chain *,
+ struct mbuf * ));
+void xl_rxeof __P((struct xl_softc *));
+int xl_rx_resync __P((struct xl_softc *));
+void xl_txeof __P((struct xl_softc *));
+void xl_txeof_90xB __P((struct xl_softc *));
+void xl_txeoc __P((struct xl_softc *));
+int xl_intr __P((void *));
+void xl_start __P((struct ifnet *));
+void xl_start_90xB __P((struct ifnet *));
+int xl_ioctl __P((struct ifnet *, u_long, caddr_t));
+void xl_init __P((void *));
+void xl_stop __P((struct xl_softc *));
+void xl_watchdog __P((struct ifnet *));
+void xl_shutdown __P((void *));
+int xl_ifmedia_upd __P((struct ifnet *));
+void xl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+
+int xl_eeprom_wait __P((struct xl_softc *));
+int xl_read_eeprom __P((struct xl_softc *, caddr_t, int, int, int));
+void xl_mii_sync __P((struct xl_softc *));
+void xl_mii_send __P((struct xl_softc *, u_int32_t, int));
+int xl_mii_readreg __P((struct xl_softc *, struct xl_mii_frame *));
+int xl_mii_writereg __P((struct xl_softc *, struct xl_mii_frame *));
+
+void xl_setcfg __P((struct xl_softc *));
+void xl_setmode __P((struct xl_softc *, int));
+u_int8_t xl_calchash __P((caddr_t));
+void xl_setmulti __P((struct xl_softc *));
+void xl_setmulti_hash __P((struct xl_softc *));
+void xl_reset __P((struct xl_softc *, int));
+int xl_list_rx_init __P((struct xl_softc *));
+int xl_list_tx_init __P((struct xl_softc *));
+int xl_list_tx_init_90xB __P((struct xl_softc *));
+void xl_wait __P((struct xl_softc *));
+void xl_mediacheck __P((struct xl_softc *));
+void xl_choose_xcvr __P((struct xl_softc *, int));
+#ifdef notdef
+void xl_testpacket __P((struct xl_softc *));
+#endif
+
+int xl_miibus_readreg __P((struct device *, int, int));
+void xl_miibus_writereg __P((struct device *, int, int, int));
+void xl_miibus_statchg __P((struct device *));
+
+/*
+ * Murphy's law says that it's possible the chip can wedge and
+ * the 'command in progress' bit may never clear. Hence, we wait
+ * only a finite amount of time to avoid getting caught in an
+ * infinite loop. Normally this delay routine would be a macro,
+ * but it isn't called during normal operation so we can afford
+ * to make it a function.
+ */
+void xl_wait(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+#ifdef DIAGNOSTIC
+ if (i == XL_TIMEOUT)
+ printf("xl%d: command never completed!\n", sc->xl_unit);
+#endif
+
+ return;
+}
+
+/*
+ * MII access routines are provided for adapters with external
+ * PHYs (3c905-TX, 3c905-T4, 3c905B-T4) and those with built-in
+ * autoneg logic that's faked up to look like a PHY (3c905B-TX).
+ * Note: if you don't perform the MDIO operations just right,
+ * it's possible to end up with code that works correctly with
+ * some chips/CPUs/processor speeds/bus speeds/etc but not
+ * with others.
+ */
+#define MII_SET(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) | x)
+
+#define MII_CLR(x) \
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
+ CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~x)
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+void xl_mii_sync(sc)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(4);
+ MII_SET(XL_MII_DIR|XL_MII_DATA);
+
+ for (i = 0; i < 32; i++) {
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+void xl_mii_send(sc, bits, cnt)
+ struct xl_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ XL_SEL_WIN(4);
+ MII_CLR(XL_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ MII_SET(XL_MII_DATA);
+ } else {
+ MII_CLR(XL_MII_DATA);
+ }
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+int xl_mii_readreg(sc, frame)
+ struct xl_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ int i, ack, s;
+
+ s = splimp();
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Select register window 4.
+ */
+
+ XL_SEL_WIN(4);
+
+ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0);
+ /*
+ * Turn on data xmit.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ MII_CLR((XL_MII_CLK|XL_MII_DATA));
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ MII_CLR(XL_MII_DIR);
+
+ /* Check for ack */
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA;
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+
+ splx(s);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+int xl_mii_writereg(sc, frame)
+ struct xl_softc *sc;
+ struct xl_mii_frame *frame;
+
+{
+ int s;
+
+ s = splimp();
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = XL_MII_STARTDELIM;
+ frame->mii_opcode = XL_MII_WRITEOP;
+ frame->mii_turnaround = XL_MII_TURNAROUND;
+
+ /*
+ * Select the window 4.
+ */
+ XL_SEL_WIN(4);
+
+ /*
+ * Turn on data output.
+ */
+ MII_SET(XL_MII_DIR);
+
+ xl_mii_sync(sc);
+
+ xl_mii_send(sc, frame->mii_stdelim, 2);
+ xl_mii_send(sc, frame->mii_opcode, 2);
+ xl_mii_send(sc, frame->mii_phyaddr, 5);
+ xl_mii_send(sc, frame->mii_regaddr, 5);
+ xl_mii_send(sc, frame->mii_turnaround, 2);
+ xl_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ MII_SET(XL_MII_CLK);
+ DELAY(1);
+ MII_CLR(XL_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ MII_CLR(XL_MII_DIR);
+
+ splx(s);
+
+ return(0);
+}
+
+int
+xl_miibus_readreg(self, phy, reg)
+ struct device *self;
+ int phy, reg;
+{
+ struct xl_softc *sc = (struct xl_softc *)self;
+ struct xl_mii_frame frame;
+
+ if (sc->xl_bustype != XL_BUS_CARDBUS && phy != 24)
+ return (0);
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ xl_mii_readreg(sc, &frame);
+
+ return(frame.mii_data);
+}
+
+void
+xl_miibus_writereg(self, phy, reg, data)
+ struct device *self;
+ int phy, reg, data;
+{
+ struct xl_softc *sc = (struct xl_softc *)self;
+ struct xl_mii_frame frame;
+
+ if (sc->xl_bustype != XL_BUS_CARDBUS && phy != 24)
+ return;
+
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ xl_mii_writereg(sc, &frame);
+}
+
+void
+xl_miibus_statchg(self)
+ struct device *self;
+{
+ struct xl_softc *sc = (struct xl_softc *)self;
+
+ xl_setcfg(sc);
+
+ XL_SEL_WIN(3);
+ if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+ else
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
+ (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
+}
+
+/*
+ * The EEPROM is slow: give it time to come ready after issuing
+ * it a command.
+ */
+int xl_eeprom_wait(sc)
+ struct xl_softc *sc;
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ if (CSR_READ_2(sc, XL_W0_EE_CMD) & XL_EE_BUSY)
+ DELAY(162);
+ else
+ break;
+ }
+
+ if (i == 100) {
+ printf("xl%d: eeprom failed to come ready\n", sc->xl_unit);
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * Read a sequence of words from the EEPROM. Note that ethernet address
+ * data is stored in the EEPROM in network byte order.
+ */
+int xl_read_eeprom(sc, dest, off, cnt, swap)
+ struct xl_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int err = 0, i;
+ u_int16_t word = 0, *ptr;
+
+ XL_SEL_WIN(0);
+
+ if (xl_eeprom_wait(sc))
+ return(1);
+
+ for (i = 0; i < cnt; 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;
+ word = CSR_READ_2(sc, XL_W0_EE_DATA);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return(err ? 1 : 0);
+}
+
+/*
+ * This routine is taken from the 3Com Etherlink XL manual,
+ * page 10-7. It calculates a CRC of the supplied multicast
+ * group address and returns the lower 8 bits, which are used
+ * as the multicast filter position.
+ * Note: the 3c905B currently only supports a 64-bit hash table,
+ * which means we really only need 6 bits, but the manual indicates
+ * that future chip revisions will have a 256-bit hash table,
+ * hence the routine is set up to calculate 8 bits of position
+ * info in case we need it some day.
+ * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a
+ * 256 bit hash table. This means we have to use all 8 bits regardless.
+ * On older cards, the upper 2 bits will be ignored. Grrrr....
+ */
+u_int8_t xl_calchash(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return(crc & 0x000000FF);
+}
+
+/*
+ * NICs older than the 3c905B have only one multicast option, which
+ * is to enable reception of all multicast frames.
+ */
+void xl_setmulti(sc)
+ struct xl_softc *sc;
+{
+ struct ifnet *ifp;
+ struct arpcom *ac = &sc->arpcom;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ u_int8_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ if (ifp->if_flags & IFF_ALLMULTI) {
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ return;
+ }
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ mcnt++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ if (mcnt)
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ else
+ rxfilt &= ~XL_RXFILTER_ALLMULTI;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+
+ return;
+}
+
+/*
+ * 3c905B adapters have a hash filter that we can program.
+ */
+void xl_setmulti_hash(sc)
+ struct xl_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0, i;
+ struct arpcom *ac = &sc->arpcom;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ u_int8_t rxfilt;
+ int mcnt = 0;
+
+ ifp = &sc->arpcom.ac_if;
+
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ if (ifp->if_flags & IFF_ALLMULTI) {
+allmulti:
+ rxfilt |= XL_RXFILTER_ALLMULTI;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ return;
+ } else
+ rxfilt &= ~XL_RXFILTER_ALLMULTI;
+
+
+ /* first, zot all the existing hash bits */
+ for (i = 0; i < XL_HASHFILT_SIZE; i++)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);
+
+ /* now program new ones */
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ goto allmulti;
+ }
+ h = xl_calchash(enm->enm_addrlo);
+ mcnt++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ if (mcnt)
+ rxfilt |= XL_RXFILTER_MULTIHASH;
+ else
+ rxfilt &= ~XL_RXFILTER_MULTIHASH;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+
+ return;
+}
+
+#ifdef notdef
+void xl_testpacket(sc)
+ struct xl_softc *sc;
+{
+ struct mbuf *m;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ if (m == NULL)
+ return;
+
+ bcopy(&sc->arpcom.ac_enaddr,
+ mtod(m, struct ether_header *)->ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&sc->arpcom.ac_enaddr,
+ mtod(m, struct ether_header *)->ether_shost, ETHER_ADDR_LEN);
+ mtod(m, struct ether_header *)->ether_type = htons(3);
+ mtod(m, unsigned char *)[14] = 0;
+ mtod(m, unsigned char *)[15] = 0;
+ mtod(m, unsigned char *)[16] = 0xE3;
+ m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
+ IF_ENQUEUE(&ifp->if_snd, m);
+ xl_start(ifp);
+
+ return;
+}
+#endif
+
+void xl_setcfg(sc)
+ struct xl_softc *sc;
+{
+ u_int32_t icfg;
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ if (sc->xl_media & XL_MEDIAOPT_MII ||
+ sc->xl_media & XL_MEDIAOPT_BT4)
+ icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS);
+ if (sc->xl_media & XL_MEDIAOPT_BTX)
+ icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS);
+
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ CSR_WRITE_4(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+}
+
+void xl_setmode(sc, media)
+ struct xl_softc *sc;
+ int media;
+{
+ u_int32_t icfg;
+ u_int16_t mediastat;
+
+ printf("xl%d: selecting ", sc->xl_unit);
+
+ XL_SEL_WIN(4);
+ mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
+
+ if (sc->xl_media & XL_MEDIAOPT_BT) {
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ printf("10baseT transceiver, ");
+ sc->xl_xcvr = XL_XCVR_10BT;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BFX) {
+ if (IFM_SUBTYPE(media) == IFM_100_FX) {
+ printf("100baseFX port, ");
+ sc->xl_xcvr = XL_XCVR_100BFX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS);
+ mediastat |= XL_MEDIASTAT_LINKBEAT;
+ mediastat &= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ if (IFM_SUBTYPE(media) == IFM_10_5) {
+ printf("AUI port, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ if (IFM_SUBTYPE(media) == IFM_10_FL) {
+ printf("10baseFL transceiver, ");
+ sc->xl_xcvr = XL_XCVR_AUI;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD);
+ mediastat |= ~XL_MEDIASTAT_SQEENB;
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ if (IFM_SUBTYPE(media) == IFM_10_2) {
+ printf("BNC port, ");
+ sc->xl_xcvr = XL_XCVR_COAX;
+ icfg &= ~XL_ICFG_CONNECTOR_MASK;
+ icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS);
+ mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
+ XL_MEDIASTAT_JABGUARD|
+ XL_MEDIASTAT_SQEENB);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX ||
+ IFM_SUBTYPE(media) == IFM_100_FX) {
+ printf("full duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
+ } else {
+ printf("half duplex\n");
+ XL_SEL_WIN(3);
+ CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
+ (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_2)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat);
+ DELAY(800);
+ XL_SEL_WIN(7);
+}
+
+void xl_reset(sc, hard)
+ struct xl_softc *sc;
+{
+ register int i;
+
+ XL_SEL_WIN(0);
+ if (hard)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | 0x0010);
+ xl_wait(sc);
+
+ for (i = 0; i < XL_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
+ break;
+ }
+
+ DELAY(100000);
+
+ /* Reset TX and RX. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(100000);
+ return;
+}
+
+/*
+ * This routine is a kludge to work around possible hardware faults
+ * or manufacturing defects that can cause the media options register
+ * (or reset options register, as it's called for the first generation
+ * 3c90x adapters) to return an incorrect result. I have encountered
+ * one Dell Latitude laptop docking station with an integrated 3c905-TX
+ * which doesn't have any of the 'mediaopt' bits set. This screws up
+ * the attach routine pretty badly because it doesn't know what media
+ * to look for. If we find ourselves in this predicament, this routine
+ * will try to guess the media options values and warn the user of a
+ * possible manufacturing defect with his adapter/system/whatever.
+ */
+void xl_mediacheck(sc)
+ struct xl_softc *sc;
+{
+ /*
+ * If some of the media options bits are set, assume they are
+ * correct. If not, try to figure it out down below.
+ * XXX I should check for 10baseFL, but I don't have an adapter
+ * to test with.
+ */
+ if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) {
+ /*
+ * Check the XCVR value. If it's not in the normal range
+ * of values, we need to fake it up here.
+ */
+ if (sc->xl_xcvr <= XL_XCVR_AUTO)
+ return;
+ else {
+ printf("xl%d: bogus xcvr value "
+ "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr);
+ printf("xl%d: choosing new default based "
+ "on card type\n", sc->xl_unit);
+ }
+ } else {
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media & XL_MEDIAOPT_10FL)
+ return;
+ printf("xl%d: WARNING: no media options bits set in "
+ "the media options register!!\n", sc->xl_unit);
+ printf("xl%d: this could be a manufacturing defect in "
+ "your adapter or system\n", sc->xl_unit);
+ printf("xl%d: attempting to guess media type; you "
+ "should probably consult your vendor\n", sc->xl_unit);
+ }
+
+ xl_choose_xcvr(sc, 1);
+}
+
+void xl_choose_xcvr(sc, verbose)
+ struct xl_softc *sc;
+ int verbose;
+{
+ u_int16_t devid;
+
+ /*
+ * Read the device ID from the EEPROM.
+ * This is what's loaded into the PCI device ID register, so it has
+ * to be correct otherwise we wouldn't have gotten this far.
+ */
+ xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0);
+
+ switch(devid) {
+ case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */
+ case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */
+ sc->xl_media = XL_MEDIAOPT_BT;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing 10BaseT transceiver\n",
+ sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */
+ case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing COMBO (AUI/BNC/TP)\n",
+ sc->xl_unit);
+ break;
+ case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */
+ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC;
+ sc->xl_xcvr = XL_XCVR_10BT;
+ if (verbose)
+ printf("xl%d: guessing TPC (BNC/TP)\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */
+ sc->xl_media = XL_MEDIAOPT_10FL;
+ sc->xl_xcvr = XL_XCVR_AUI;
+ if (verbose)
+ printf("xl%d: guessing 10baseFL\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */
+ sc->xl_media = XL_MEDIAOPT_MII;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printf("xl%d: guessing MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */
+ case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */
+ sc->xl_media = XL_MEDIAOPT_BT4;
+ sc->xl_xcvr = XL_XCVR_MII;
+ if (verbose)
+ printf("xl%d: guessing 100BaseT4/MII\n", sc->xl_unit);
+ break;
+ case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */
+ case TC_DEVICEID_HURRICANE_10_100BT_SERV:/* 3c980-TX */
+ case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */
+ case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */
+ case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */
+ case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */
+ sc->xl_media = XL_MEDIAOPT_BTX;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (verbose)
+ printf("xl%d: guessing 10/100 internal\n",
+ sc->xl_unit);
+ break;
+ case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */
+ sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
+ sc->xl_xcvr = XL_XCVR_AUTO;
+ if (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);
+ sc->xl_media = XL_MEDIAOPT_BT;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+int xl_list_tx_init(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
+ if (i == (XL_TX_LIST_CNT - 1))
+ cd->xl_tx_chain[i].xl_next = NULL;
+ else
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
+ }
+
+ cd->xl_tx_free = &cd->xl_tx_chain[0];
+ cd->xl_tx_tail = cd->xl_tx_head = NULL;
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit desriptors.
+ */
+int
+xl_list_tx_init_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
+ cd->xl_tx_chain[i].xl_phys = vtophys(&ld->xl_tx_list[i]);
+ if (i == (XL_TX_LIST_CNT - 1))
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0];
+ else
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
+ if (i == 0)
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[XL_TX_LIST_CNT - 1];
+ else
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[i - 1];
+ }
+
+ bzero((char *)ld->xl_tx_list, sizeof(struct xl_list) * XL_TX_LIST_CNT);
+ ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY;
+
+ cd->xl_tx_prod = 1;
+ cd->xl_tx_cons = 1;
+ cd->xl_tx_cnt = 0;
+
+ return (0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+int xl_list_rx_init(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ cd->xl_rx_chain[i].xl_ptr =
+ (struct xl_list_onefrag *)&ld->xl_rx_list[i];
+ if (xl_newbuf(sc, &cd->xl_rx_chain[i]) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (XL_RX_LIST_CNT - 1)) {
+ cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0];
+ ld->xl_rx_list[i].xl_next =
+ vtophys(&ld->xl_rx_list[0]);
+ } else {
+ cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1];
+ ld->xl_rx_list[i].xl_next =
+ vtophys(&ld->xl_rx_list[i + 1]);
+ }
+ }
+
+ cd->xl_rx_head = &cd->xl_rx_chain[0];
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+int xl_newbuf(sc, c)
+ struct xl_softc *sc;
+ struct xl_chain_onefrag *c;
+{
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(ENOBUFS);
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+
+ /* Force longword alignment for packet payload. */
+ m_adj(m_new, ETHER_ALIGN);
+
+ c->xl_mbuf = m_new;
+ c->xl_ptr->xl_frag.xl_addr = vtophys(mtod(m_new, caddr_t));
+ c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG;
+ c->xl_ptr->xl_status = 0;
+
+ return(0);
+}
+
+int xl_rx_resync(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_onefrag *pos;
+ int i;
+
+ pos = sc->xl_cdata.xl_rx_head;
+
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ if (pos->xl_ptr->xl_status)
+ break;
+ pos = pos->xl_next;
+ }
+
+ if (i == XL_RX_LIST_CNT)
+ return (0);
+
+ sc->xl_cdata.xl_rx_head = pos;
+
+ return (EAGAIN);
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+void xl_rxeof(sc)
+ struct xl_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct xl_chain_onefrag *cur_rx;
+ int total_len = 0;
+ u_int16_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+
+again:
+
+ while((rxstat = sc->xl_cdata.xl_rx_head->xl_ptr->xl_status)) {
+ cur_rx = sc->xl_cdata.xl_rx_head;
+ sc->xl_cdata.xl_rx_head = cur_rx->xl_next;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & XL_RXSTAT_UP_ERROR) {
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ /*
+ * If there error bit was not set, the upload complete
+ * bit should be set which means we have a valid packet.
+ * If not, something truly strange has happened.
+ */
+ if (!(rxstat & XL_RXSTAT_UP_CMPLT)) {
+ printf("xl%d: bad receive status -- "
+ "packet dropped", sc->xl_unit);
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ /* No errors; receive the packet. */
+ m = cur_rx->xl_mbuf;
+ total_len = cur_rx->xl_ptr->xl_status & XL_RXSTAT_LENMASK;
+
+ /*
+ * Try to conjure up a new mbuf cluster. If that
+ * fails, it means we have an out of memory condition and
+ * should leave the buffer in place and continue. This will
+ * result in a lost packet, but there's little else we
+ * can do in this situation.
+ */
+ if (xl_newbuf(sc, cur_rx) == ENOBUFS) {
+ ifp->if_ierrors++;
+ cur_rx->xl_ptr->xl_status = 0;
+ continue;
+ }
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+ m->m_pkthdr.rcvif = ifp;
+#if NBPFILTER > 0
+ /*
+ * Handle BPF listeners. Let the BPF user see the packet.
+ */
+ if (ifp->if_bpf) {
+ m->m_pkthdr.len = m->m_len = total_len;
+ bpf_mtap(ifp->if_bpf, m);
+ }
+#endif
+ /* Remove header from mbuf and pass it on. */
+ m->m_pkthdr.len = m->m_len =
+ total_len - sizeof(struct ether_header);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+ }
+
+ /*
+ * Handle the 'end of channel' condition. When the upload
+ * engine hits the end of the RX ring, it will stall. This
+ * is our cue to flush the RX ring, reload the uplist pointer
+ * register and unstall the engine.
+ * XXX This is actually a little goofy. With the ThunderLAN
+ * chip, you get an interrupt when the receiver hits the end
+ * of the receive ring, which tells you exactly when you
+ * you need to reload the ring pointer. Here we have to
+ * fake it. I'm mad at myself for not being clever enough
+ * to avoid the use of a goto here.
+ */
+ if (CSR_READ_4(sc, XL_UPLIST_PTR) == 0 ||
+ CSR_READ_4(sc, XL_UPLIST_STATUS) & XL_PKTSTAT_UP_STALLED) {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR,
+ vtophys(&sc->xl_ldata->xl_rx_list[0]));
+ sc->xl_cdata.xl_rx_head = &sc->xl_cdata.xl_rx_chain[0];
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ goto again;
+ }
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+void xl_txeof(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain *cur_tx;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been uploaded. Note: the 3c905B
+ * sets a special bit in the status word to let us
+ * know that a frame has been downloaded, but the
+ * original 3c900/3c905 adapters don't do that.
+ * Consequently, we have to use a different test if
+ * xl_type != XL_TYPE_905B.
+ */
+ while(sc->xl_cdata.xl_tx_head != NULL) {
+ cur_tx = sc->xl_cdata.xl_tx_head;
+
+ if (CSR_READ_4(sc, XL_DOWNLIST_PTR))
+ break;
+
+ sc->xl_cdata.xl_tx_head = cur_tx->xl_next;
+ m_freem(cur_tx->xl_mbuf);
+ cur_tx->xl_mbuf = NULL;
+ ifp->if_opackets++;
+
+ cur_tx->xl_next = sc->xl_cdata.xl_tx_free;
+ sc->xl_cdata.xl_tx_free = cur_tx;
+ }
+
+ if (sc->xl_cdata.xl_tx_head == NULL) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sc->xl_cdata.xl_tx_tail = NULL;
+ } else {
+ if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED ||
+ !CSR_READ_4(sc, XL_DOWNLIST_PTR)) {
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ }
+ }
+
+ return;
+}
+
+void
+xl_txeof_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ idx = sc->xl_cdata.xl_tx_cons;
+ while(idx != sc->xl_cdata.xl_tx_prod) {
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE))
+ break;
+
+ if (cur_tx->xl_mbuf != NULL) {
+ m_freem(cur_tx->xl_mbuf);
+ cur_tx->xl_mbuf = NULL;
+ }
+
+ ifp->if_opackets++;
+
+ sc->xl_cdata.xl_tx_cnt--;
+ XL_INC(idx, XL_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->xl_cdata.xl_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+}
+
+/*
+ * TX 'end of channel' interrupt handler. Actually, we should
+ * only get a 'TX complete' interrupt if there's a transmit error,
+ * so this is really TX error handler.
+ */
+void xl_txeoc(sc)
+ struct xl_softc *sc;
+{
+ u_int8_t txstat;
+
+ while((txstat = CSR_READ_1(sc, XL_TX_STATUS))) {
+ if (txstat & XL_TXSTATUS_UNDERRUN ||
+ txstat & XL_TXSTATUS_JABBER ||
+ txstat & XL_TXSTATUS_RECLAIM) {
+ printf("xl%d: transmission error: %x\n",
+ sc->xl_unit, txstat);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+ if (sc->xl_type == XL_TYPE_905B) {
+ int i;
+ struct xl_chain *c;
+ i = sc->xl_cdata.xl_tx_cons;
+ c = &sc->xl_cdata.xl_tx_chain[i];
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR, c->xl_phys);
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ } else {
+ if (sc->xl_cdata.xl_tx_head != NULL)
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
+ }
+ /*
+ * Remember to set this for the
+ * first generation 3c90X chips.
+ */
+ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
+ if (txstat & XL_TXSTATUS_UNDERRUN &&
+ sc->xl_tx_thresh < XL_PACKET_SIZE) {
+ sc->xl_tx_thresh += XL_MIN_FRAMELEN;
+ printf("xl%d: tx underrun, increasing tx start"
+ " threshold to %d\n", sc->xl_unit,
+ sc->xl_tx_thresh);
+ }
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_TX_SET_START|sc->xl_tx_thresh);
+ if (sc->xl_type == XL_TYPE_905B) {
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ }
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ } else {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ }
+ /*
+ * Write an arbitrary byte to the TX_STATUS register
+ * to clear this interrupt/error and advance to the next.
+ */
+ CSR_WRITE_1(sc, XL_TX_STATUS, 0x01);
+ }
+
+ return;
+}
+
+int xl_intr(arg)
+ void *arg;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+ u_int16_t status;
+ int claimed = 0;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+
+ while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS) {
+
+ claimed = 1;
+
+ 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;
+
+ curpkts = ifp->if_ipackets;
+ xl_rxeof(sc);
+ if (curpkts == ifp->if_ipackets) {
+ while (xl_rx_resync(sc))
+ xl_rxeof(sc);
+ }
+ }
+
+ if (status & XL_STAT_DOWN_COMPLETE) {
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_txeof_90xB(sc);
+ else
+ xl_txeof(sc);
+ }
+
+ if (status & XL_STAT_TX_COMPLETE) {
+ ifp->if_oerrors++;
+ xl_txeoc(sc);
+ }
+
+ if (status & XL_STAT_ADFAIL) {
+ xl_reset(sc, 0);
+ xl_init(sc);
+ }
+
+ if (status & XL_STAT_STATSOFLOW) {
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc);
+ sc->xl_stats_no_timeout = 0;
+ }
+ }
+
+ if (ifp->if_snd.ifq_head != NULL)
+ (*ifp->if_start)(ifp);
+
+ return (claimed);
+}
+
+void xl_stats_update(xsc)
+ void *xsc;
+{
+ struct xl_softc *sc;
+ struct ifnet *ifp;
+ struct xl_stats xl_stats;
+ u_int8_t *p;
+ int i;
+ struct mii_data *mii = NULL;
+
+ bzero((char *)&xl_stats, sizeof(struct xl_stats));
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+ if (sc->xl_hasmii)
+ mii = &sc->sc_mii;
+
+ p = (u_int8_t *)&xl_stats;
+
+ /* Read all the stats registers. */
+ XL_SEL_WIN(6);
+
+ for (i = 0; i < 16; i++)
+ *p++ = CSR_READ_1(sc, XL_W6_CARRIER_LOST + i);
+
+ ifp->if_ierrors += xl_stats.xl_rx_overrun;
+
+ ifp->if_collisions += xl_stats.xl_tx_multi_collision +
+ xl_stats.xl_tx_single_collision +
+ xl_stats.xl_tx_late_collision;
+
+ /*
+ * Boomerang and cyclone chips have an extra stats counter
+ * in window 4 (BadSSD). We have to read this too in order
+ * to clear out all the stats registers and avoid a statsoflow
+ * interrupt.
+ */
+ XL_SEL_WIN(4);
+ CSR_READ_1(sc, XL_W4_BADSSD);
+
+ if (mii != NULL)
+ mii_tick(mii);
+
+ XL_SEL_WIN(7);
+
+ if (!sc->xl_stats_no_timeout)
+ timeout(xl_stats_update, sc, hz);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+int xl_encap(sc, c, m_head)
+ struct xl_softc *sc;
+ struct xl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct xl_frag *f = NULL;
+ int total_len;
+ struct mbuf *m;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ total_len = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == XL_MAXFRAGS)
+ break;
+ total_len+= m->m_len;
+ c->xl_ptr->xl_frag[frag].xl_addr =
+ vtophys(mtod(m, vm_offset_t));
+ c->xl_ptr->xl_frag[frag].xl_len = m->m_len;
+ frag++;
+ }
+ }
+
+ /*
+ * Handle special case: we used up all 63 fragments,
+ * but we have more mbufs left in the chain. Copy the
+ * data into an mbuf cluster. Note that we don't
+ * bother clearing the values in the other fragment
+ * pointers/counters; it wouldn't gain us anything,
+ * and would waste cycles.
+ */
+ if (m != NULL) {
+ struct mbuf *m_new = NULL;
+
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return(1);
+ if (m_head->m_pkthdr.len > MHLEN) {
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ m_freem(m_new);
+ return(1);
+ }
+ }
+ m_copydata(m_head, 0, m_head->m_pkthdr.len,
+ mtod(m_new, caddr_t));
+ m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+ m_freem(m_head);
+ m_head = m_new;
+ f = &c->xl_ptr->xl_frag[0];
+ f->xl_addr = vtophys(mtod(m_new, caddr_t));
+ f->xl_len = total_len = m_new->m_len;
+ frag = 1;
+ }
+
+ c->xl_mbuf = m_head;
+ c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
+ c->xl_ptr->xl_status = total_len;
+ c->xl_ptr->xl_next = 0;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+void xl_start(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+
+ sc = ifp->if_softc;
+
+ /*
+ * Check for an available queue slot. If there are none,
+ * punt.
+ */
+ if (sc->xl_cdata.xl_tx_free == NULL) {
+ xl_txeoc(sc);
+ xl_txeof(sc);
+ if (sc->xl_cdata.xl_tx_free == NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+ }
+
+ start_tx = sc->xl_cdata.xl_tx_free;
+
+ while(sc->xl_cdata.xl_tx_free != NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ /* Pick a descriptor off the free list. */
+ cur_tx = sc->xl_cdata.xl_tx_free;
+ sc->xl_cdata.xl_tx_free = cur_tx->xl_next;
+
+ cur_tx->xl_next = NULL;
+
+ /* Pack the data into the descriptor. */
+ xl_encap(sc, cur_tx, m_head);
+
+ /* Chain it together. */
+ if (prev != NULL) {
+ prev->xl_next = cur_tx;
+ prev->xl_ptr->xl_next = vtophys(cur_tx->xl_ptr);
+ }
+ prev = cur_tx;
+
+#if NBPFILTER > 0
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, cur_tx->xl_mbuf);
+#endif
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL)
+ return;
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
+
+ /*
+ * Queue the packets. If the TX channel is clear, update
+ * the downlist pointer register.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+
+ if (sc->xl_cdata.xl_tx_head != NULL) {
+ sc->xl_cdata.xl_tx_tail->xl_next = start_tx;
+ sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next =
+ vtophys(start_tx->xl_ptr);
+ sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &=
+ ~XL_TXSTAT_DL_INTR;
+ sc->xl_cdata.xl_tx_tail = cur_tx;
+ } else {
+ sc->xl_cdata.xl_tx_head = start_tx;
+ sc->xl_cdata.xl_tx_tail = cur_tx;
+ }
+ if (!CSR_READ_4(sc, XL_DOWNLIST_PTR))
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR, vtophys(start_tx->xl_ptr));
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+
+ XL_SEL_WIN(7);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ /*
+ * XXX Under certain conditions, usually on slower machines
+ * where interrupts may be dropped, it's possible for the
+ * adapter to chew up all the buffers in the receive ring
+ * and stall, without us being able to do anything about it.
+ * To guard against this, we need to make a pass over the
+ * RX queue to make sure there aren't any packets pending.
+ * Doing it here means we can flush the receive ring at the
+ * same time the chip is DMAing the transmit descriptors we
+ * just gave it.
+ *
+ * 3Com goes to some lengths to emphasize the Parallel Tasking (tm)
+ * nature of their chips in all their marketing literature;
+ * we may as well take advantage of it. :)
+ */
+ xl_rxeof(sc);
+
+ return;
+}
+
+int xl_encap_90xB(sc, c, m_head)
+ struct xl_softc *sc;
+ struct xl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct xl_frag *f = NULL;
+ struct mbuf *m;
+ struct xl_list *d;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ d = c->xl_ptr;
+ d->xl_status = 0;
+ d->xl_next = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == XL_MAXFRAGS)
+ break;
+ f = &d->xl_frag[frag];
+ f->xl_addr = vtophys(mtod(m, vm_offset_t));
+ f->xl_len = m->m_len;
+ frag++;
+ }
+ }
+
+ c->xl_mbuf = m_head;
+ c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
+ c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT;
+
+ return(0);
+}
+
+void
+xl_start_90xB(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+ int idx;
+
+ sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ idx = sc->xl_cdata.xl_tx_prod;
+ start_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ while (sc->xl_cdata.xl_tx_chain[idx].xl_mbuf == NULL) {
+
+ if ((XL_TX_LIST_CNT - sc->xl_cdata.xl_tx_cnt) < 3) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ /* Pack the data into the descriptor. */
+ xl_encap_90xB(sc, cur_tx, m_head);
+
+ /* Chain it together. */
+ if (prev != NULL)
+ prev->xl_ptr->xl_next = cur_tx->xl_phys;
+ prev = cur_tx;
+
+#if NBPFILTER > 0
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, cur_tx->xl_mbuf);
+#endif
+
+ XL_INC(idx, XL_TX_LIST_CNT);
+ sc->xl_cdata.xl_tx_cnt++;
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL)
+ return;
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
+
+ /* Start transmission */
+ sc->xl_cdata.xl_tx_prod = idx;
+ start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+}
+
+void xl_init(xsc)
+ void *xsc;
+{
+ struct xl_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s, i;
+ u_int16_t rxfilt = 0;
+ struct mii_data *mii = NULL;
+
+ s = splimp();
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ xl_stop(sc);
+
+ if (sc->xl_hasmii)
+ mii = &sc->sc_mii;
+
+ if (mii == NULL) {
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ }
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+ DELAY(10000);
+
+
+ /* Init our MAC address */
+ XL_SEL_WIN(2);
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ CSR_WRITE_1(sc, XL_W2_STATION_ADDR_LO + i,
+ sc->arpcom.ac_enaddr[i]);
+ }
+
+ /* Clear the station mask. */
+ for (i = 0; i < 3; i++)
+ CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0);
+#ifdef notdef
+ /* Reset TX and RX. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+#endif
+ /* Init circular RX list. */
+ if (xl_list_rx_init(sc) == ENOBUFS) {
+ printf("xl%d: initialization failed: no "
+ "memory for rx buffers\n", sc->xl_unit);
+ xl_stop(sc);
+ return;
+ }
+
+ /* Init TX descriptors. */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_list_tx_init_90xB(sc);
+ else
+ xl_list_tx_init(sc);
+
+ /*
+ * Set the TX freethresh value.
+ * Note that this has no effect on 3c905B "cyclone"
+ * cards but is required for 3c900/3c905 "boomerang"
+ * cards in order to enable the download engine.
+ */
+ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
+
+ /* Set the TX start threshold for best performance. */
+ sc->xl_tx_thresh = XL_MIN_FRAMELEN;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_SET_START|sc->xl_tx_thresh);
+
+ /*
+ * If this is a 3c905B, also set the tx reclaim threshold.
+ * This helps cut down on the number of tx reclaim errors
+ * that could happen on a busy network. The chip multiplies
+ * the register value by 16 to obtain the actual threshold
+ * in bytes, so we divide by 16 when setting the value here.
+ * The existing threshold value can be examined by reading
+ * the register at offset 9 in window 5.
+ */
+ if (sc->xl_type == XL_TYPE_905B) {
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ }
+
+ /* Set RX filter bits. */
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+
+ /* Set the individual bit to receive frames for this host only. */
+ rxfilt |= XL_RXFILTER_INDIVIDUAL;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC) {
+ rxfilt |= XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+ /*
+ * Set capture broadcast bit to capture broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST) {
+ rxfilt |= XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ } else {
+ rxfilt &= ~XL_RXFILTER_BROADCAST;
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+ }
+
+ /*
+ * Program the multicast filter, if necessary.
+ */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_setmulti_hash(sc);
+ else
+ xl_setmulti(sc);
+
+ /*
+ * Load the address of the RX list. We have to
+ * stall the upload engine before we can manipulate
+ * the uplist pointer register, then unstall it when
+ * we're finished. We also have to wait for the
+ * stall command to complete before proceeding.
+ * Note that we have to do this after any RX resets
+ * have completed since the uplist register is cleared
+ * by a reset.
+ */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0]));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ xl_wait(sc);
+
+ if (sc->xl_type == XL_TYPE_905B) {
+ /* Set polling interval */
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ /* Load the address of the TX list */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(&sc->xl_ldata->xl_tx_list[0]));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ xl_wait(sc);
+ }
+
+ /*
+ * If the coax transceiver is on, make sure to enable
+ * the DC-DC converter.
+ */
+ XL_SEL_WIN(3);
+ if (sc->xl_xcvr == XL_XCVR_COAX)
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
+ else
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+
+ /* Clear out the stats counters. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ sc->xl_stats_no_timeout = 1;
+ xl_stats_update(sc);
+ sc->xl_stats_no_timeout = 0;
+ XL_SEL_WIN(4);
+ CSR_WRITE_2(sc, XL_W4_NET_DIAG, XL_NETDIAG_UPPER_BYTES_ENABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_ENABLE);
+
+ /*
+ * 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);
+
+ /* Set the RX early threshold */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2));
+ CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY);
+
+ /* Enable receiver and transmitter. */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
+ xl_wait(sc);
+
+ /* Restore state of BMCR */
+ if (mii != NULL)
+ mii_mediachg(mii);
+
+ /* Select window 7 for normal operations. */
+ XL_SEL_WIN(7);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ (void)splx(s);
+
+ timeout(xl_stats_update, sc, hz);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+int xl_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct ifmedia *ifm = NULL;
+ struct mii_data *mii = NULL;
+
+ sc = ifp->if_softc;
+
+ if (sc->xl_hasmii)
+ mii = &sc->sc_mii;
+ if (mii == NULL)
+ ifm = &sc->ifmedia;
+ else
+ ifm = &mii->mii_media;
+
+ switch(IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_100_FX:
+ case IFM_10_FL:
+ case IFM_10_2:
+ case IFM_10_5:
+ xl_setmode(sc, ifm->ifm_media);
+ return (0);
+ break;
+ default:
+ break;
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX
+ || sc->xl_media & XL_MEDIAOPT_BT4) {
+ xl_init(sc);
+ } else {
+ xl_setmode(sc, ifm->ifm_media);
+ }
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+void xl_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct xl_softc *sc;
+ u_int32_t icfg;
+ struct mii_data *mii = NULL;
+
+ sc = ifp->if_softc;
+ if (sc->xl_hasmii != 0)
+ mii = &sc->sc_mii;
+
+ XL_SEL_WIN(3);
+ icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG) & XL_ICFG_CONNECTOR_MASK;
+ icfg >>= XL_ICFG_CONNECTOR_BITS;
+
+ ifmr->ifm_active = IFM_ETHER;
+
+ switch(icfg) {
+ case XL_XCVR_10BT:
+ ifmr->ifm_active = IFM_ETHER|IFM_10_T;
+ if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ break;
+ case XL_XCVR_AUI:
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ ifmr->ifm_active = IFM_ETHER|IFM_10_FL;
+ if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_FDX;
+ } else
+ ifmr->ifm_active = IFM_ETHER|IFM_10_5;
+ break;
+ case XL_XCVR_COAX:
+ ifmr->ifm_active = IFM_ETHER|IFM_10_2;
+ break;
+ /*
+ * XXX MII and BTX/AUTO should be separate cases.
+ */
+
+ case XL_XCVR_100BTX:
+ case XL_XCVR_AUTO:
+ case XL_XCVR_MII:
+ if (mii != NULL) {
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ }
+ break;
+ case XL_XCVR_100BFX:
+ ifmr->ifm_active = IFM_ETHER|IFM_100_FX;
+ break;
+ default:
+ printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit, icfg);
+ break;
+ }
+
+ return;
+}
+
+int
+xl_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct xl_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+ struct mii_data *mii = NULL;
+ u_int8_t rxfilt;
+
+ s = splimp();
+
+ if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
+ splx(s);
+ return error;
+ }
+
+ switch(command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ xl_init(sc);
+ arp_ifinit(&sc->arpcom, ifa);
+ break;
+#endif /* INET */
+ default:
+ xl_init(sc);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ XL_SEL_WIN(5);
+ rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->xl_if_flags & IFF_PROMISC)) {
+ rxfilt |= XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_RX_SET_FILT|rxfilt);
+ XL_SEL_WIN(7);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->xl_if_flags & IFF_PROMISC) {
+ rxfilt &= ~XL_RXFILTER_ALLFRAMES;
+ CSR_WRITE_2(sc, XL_COMMAND,
+ XL_CMD_RX_SET_FILT|rxfilt);
+ XL_SEL_WIN(7);
+ } else
+ xl_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ xl_stop(sc);
+ }
+ sc->xl_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->arpcom) :
+ ether_delmulti(ifr, &sc->arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly.
+ */
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_setmulti_hash(sc);
+ else
+ xl_setmulti(sc);
+ error = 0;
+ }
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ if (sc->xl_hasmii != 0)
+ mii = &sc->sc_mii;
+ if (mii == NULL)
+ error = ifmedia_ioctl(ifp, ifr,
+ &sc->ifmedia, command);
+ else
+ error = ifmedia_ioctl(ifp, ifr,
+ &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void)splx(s);
+
+ return(error);
+}
+
+void xl_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ u_int16_t status = 0;
+
+ sc = ifp->if_softc;
+
+ ifp->if_oerrors++;
+ XL_SEL_WIN(4);
+ status = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
+ printf("xl%d: watchdog timeout\n", sc->xl_unit);
+
+ if (status & XL_MEDIASTAT_CARRIER)
+ printf("xl%d: no carrier - transceiver cable problem?\n",
+ sc->xl_unit);
+ xl_txeoc(sc);
+ xl_txeof(sc);
+ xl_rxeof(sc);
+ xl_reset(sc, 0);
+ xl_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ (*ifp->if_start)(ifp);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+void xl_stop(sc)
+ struct xl_softc *sc;
+{
+ int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
+ DELAY(800);
+
+#ifdef foo
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
+ xl_wait(sc);
+#endif
+
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
+ 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);
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < XL_RX_LIST_CNT; i++) {
+ if (sc->xl_cdata.xl_rx_chain[i].xl_mbuf != NULL) {
+ m_freem(sc->xl_cdata.xl_rx_chain[i].xl_mbuf);
+ sc->xl_cdata.xl_rx_chain[i].xl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->xl_ldata->xl_rx_list,
+ sizeof(sc->xl_ldata->xl_rx_list));
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ if (sc->xl_cdata.xl_tx_chain[i].xl_mbuf != NULL) {
+ m_freem(sc->xl_cdata.xl_tx_chain[i].xl_mbuf);
+ sc->xl_cdata.xl_tx_chain[i].xl_mbuf = NULL;
+ }
+ }
+ bzero((char *)&sc->xl_ldata->xl_tx_list,
+ sizeof(sc->xl_ldata->xl_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ return;
+}
+
+void
+xl_attach(sc)
+ struct xl_softc *sc;
+{
+ u_int8_t enaddr[ETHER_ADDR_LEN];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ 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;
+ xl_reset(sc, 1);
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ if (xl_read_eeprom(sc, (caddr_t)&enaddr, XL_EE_OEM_ADR0, 3, 1)) {
+ printf("\n%s: failed to read station address\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ bcopy(enaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ 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) {
+ printf("%s: no memory for list buffers\n",sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->xl_ldata = (struct xl_list_data *)sc->xl_ldata_ptr;
+#ifdef __alpha__
+ round = (u_int64_t)sc->xl_ldata_ptr & 0xf;
+#else
+ round = (u_int32_t)sc->xl_ldata_ptr & 0xf;
+#endif
+ roundptr = sc->xl_ldata_ptr;
+ for (i = 0; i < 8; i++) {
+ if (round % 8) {
+ round++;
+ roundptr++;
+ } else
+ break;
+ }
+ sc->xl_ldata = (struct xl_list_data *)roundptr;
+ bzero(sc->xl_ldata, sizeof(struct xl_list_data));
+
+ /*
+ * Figure out the card type. 3c905B adapters have the
+ * 'supportsNoTxLength' bit set in the capabilities
+ * word in the EEPROM.
+ */
+ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
+ if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
+ sc->xl_type = XL_TYPE_905B;
+ else
+ sc->xl_type = XL_TYPE_90X;
+
+ ifp->if_softc = sc;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = xl_ioctl;
+ ifp->if_output = ether_output;
+ if (sc->xl_type == XL_TYPE_905B)
+ ifp->if_start = xl_start_90xB;
+ else
+ ifp->if_start = xl_start;
+ ifp->if_watchdog = xl_watchdog;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = XL_TX_LIST_CNT - 1;
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+
+ XL_SEL_WIN(3);
+ sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT);
+
+ xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0);
+ 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,
+ xl_ifmedia_upd, xl_ifmedia_sts);
+ sc->xl_hasmii = 1;
+ sc->sc_mii.mii_ifp = ifp;
+ sc->sc_mii.mii_readreg = xl_miibus_readreg;
+ sc->sc_mii.mii_writereg = xl_miibus_writereg;
+ sc->sc_mii.mii_statchg = xl_miibus_statchg;
+ xl_setcfg(sc);
+ 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,
+ 0, NULL);
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
+ }
+ else {
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+ }
+ ifm = &sc->sc_mii.mii_media;
+ }
+ else {
+ ifmedia_init(&sc->ifmedia, 0, xl_ifmedia_upd, xl_ifmedia_sts);
+ sc->xl_hasmii = 0;
+ ifm = &sc->ifmedia;
+ }
+
+ /*
+ * Sanity check. If the user has selected "auto" and this isn't
+ * a 10/100 card of some kind, we need to force the transceiver
+ * type to something sane.
+ */
+ if (sc->xl_xcvr == XL_XCVR_AUTO) {
+ xl_choose_xcvr(sc, 0);
+ xl_reset(sc, 0);
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BT) {
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
+ if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
+ ifmedia_add(&sc->ifmedia,
+ IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ }
+
+ if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
+ /*
+ * Check for a 10baseFL board in disguise.
+ */
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_FL, 0, NULL);
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_FL|IFM_HDX,
+ 0, NULL);
+ if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
+ ifmedia_add(ifm,
+ IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
+ } else {
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_5, 0, NULL);
+ }
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BNC) {
+ ifmedia_add(ifm, IFM_ETHER|IFM_10_2, 0, NULL);
+ }
+
+ if (sc->xl_media & XL_MEDIAOPT_BFX) {
+ ifp->if_baudrate = 100000000;
+ ifmedia_add(ifm, IFM_ETHER|IFM_100_FX, 0, NULL);
+ }
+
+ /* Choose a default media. */
+ switch(sc->xl_xcvr) {
+ case XL_XCVR_10BT:
+ media = IFM_ETHER|IFM_10_T;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUI:
+ if (sc->xl_type == XL_TYPE_905B &&
+ sc->xl_media == XL_MEDIAOPT_10FL) {
+ media = IFM_ETHER|IFM_10_FL;
+ xl_setmode(sc, media);
+ } else {
+ media = IFM_ETHER|IFM_10_5;
+ xl_setmode(sc, media);
+ }
+ break;
+ case XL_XCVR_COAX:
+ media = IFM_ETHER|IFM_10_2;
+ xl_setmode(sc, media);
+ break;
+ case XL_XCVR_AUTO:
+ case XL_XCVR_100BTX:
+ case XL_XCVR_MII:
+ /* Chosen by miibus */
+ break;
+ case XL_XCVR_100BFX:
+ media = IFM_ETHER|IFM_100_FX;
+ xl_setmode(sc, media);
+ break;
+ default:
+ printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit,
+ sc->xl_xcvr);
+ /*
+ * This will probably be wrong, but it prevents
+ * the ifmedia code from panicking.
+ */
+ media = IFM_ETHER | IFM_10_T;
+ break;
+ }
+
+ if (sc->xl_hasmii == 0)
+ ifmedia_set(&sc->ifmedia, media);
+
+ /*
+ * Call MI attach routines.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+#if NBPFILTER > 0
+ bpfattach(&sc->arpcom.ac_if.if_bpf, ifp,
+ DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ shutdownhook_establish(xl_shutdown, sc);
+}
+
+void
+xl_shutdown(v)
+ void *v;
+{
+ struct xl_softc *sc = (struct xl_softc *)v;
+
+ xl_reset(sc, 1);
+ xl_stop(sc);
+}
+
+struct cfdriver xl_cd = {
+ 0, "xl", DV_IFNET
+};
--- /dev/null
+/* $OpenBSD: xlreg.h,v 1.1 2000/04/08 05:50:50 aaron Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: 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 */
+#define XL_EE_EWEN 0x0030 /* erase, no data needed */
+#define XL_EE_BUSY 0x8000
+
+#define XL_EE_EADDR0 0x00 /* station address, first word */
+#define XL_EE_EADDR1 0x01 /* station address, next word, */
+#define XL_EE_EADDR2 0x02 /* station address, last word */
+#define XL_EE_PRODID 0x03 /* product ID code */
+#define XL_EE_MDATA_DATE 0x04 /* manufacturing data, date */
+#define XL_EE_MDATA_DIV 0x05 /* manufacturing data, division */
+#define XL_EE_MDATA_PCODE 0x06 /* manufacturing data, product code */
+#define XL_EE_MFG_ID 0x07
+#define XL_EE_PCI_PARM 0x08
+#define XL_EE_ROM_ONFO 0x09
+#define XL_EE_OEM_ADR0 0x0A
+#define XL_EE_OEM_ADR1 0x0B
+#define XL_EE_OEM_ADR2 0x0C
+#define XL_EE_SOFTINFO1 0x0D
+#define XL_EE_COMPAT 0x0E
+#define XL_EE_SOFTINFO2 0x0F
+#define XL_EE_CAPS 0x10 /* capabilities word */
+#define XL_EE_RSVD0 0x11
+#define XL_EE_ICFG_0 0x12
+#define XL_EE_ICFG_1 0x13
+#define XL_EE_RSVD1 0x14
+#define XL_EE_SOFTINFO3 0x15
+#define XL_EE_RSVD_2 0x16
+
+/*
+ * Bits in the capabilities word
+ */
+#define XL_CAPS_PNP 0x0001
+#define XL_CAPS_FULL_DUPLEX 0x0002
+#define XL_CAPS_LARGE_PKTS 0x0004
+#define XL_CAPS_SLAVE_DMA 0x0008
+#define XL_CAPS_SECOND_DMA 0x0010
+#define XL_CAPS_FULL_BM 0x0020
+#define XL_CAPS_FRAG_BM 0x0040
+#define XL_CAPS_CRC_PASSTHRU 0x0080
+#define XL_CAPS_TXDONE 0x0100
+#define XL_CAPS_NO_TXLENGTH 0x0200
+#define XL_CAPS_RX_REPEAT 0x0400
+#define XL_CAPS_SNOOPING 0x0800
+#define XL_CAPS_100MBPS 0x1000
+#define XL_CAPS_PWRMGMT 0x2000
+
+#define XL_PACKET_SIZE 1536
+
+/*
+ * Register layouts.
+ */
+#define XL_COMMAND 0x0E
+#define XL_STATUS 0x0E
+
+#define XL_TX_STATUS 0x1B
+#define XL_TX_FREE 0x1C
+#define XL_DMACTL 0x20
+#define XL_DOWNLIST_PTR 0x24
+#define XL_DOWN_POLL 0x2D /* 3c90xB only */
+#define XL_TX_FREETHRESH 0x2F
+#define XL_UPLIST_PTR 0x38
+#define XL_UPLIST_STATUS 0x30
+#define XL_UP_POLL 0x3D /* 3c90xB only */
+
+#define XL_PKTSTAT_UP_STALLED 0x00002000
+#define XL_PKTSTAT_UP_ERROR 0x00004000
+#define XL_PKTSTAT_UP_CMPLT 0x00008000
+
+#define XL_DMACTL_DN_CMPLT_REQ 0x00000002
+#define XL_DMACTL_DOWN_STALLED 0x00000004
+#define XL_DMACTL_UP_CMPLT 0x00000008
+#define XL_DMACTL_DOWN_CMPLT 0x00000010
+#define XL_DMACTL_UP_RX_EARLY 0x00000020
+#define XL_DMACTL_ARM_COUNTDOWN 0x00000040
+#define XL_DMACTL_DOWN_INPROG 0x00000080
+#define XL_DMACTL_COUNTER_SPEED 0x00000100
+#define XL_DMACTL_DOWNDOWN_MODE 0x00000200
+#define XL_DMACTL_TARGET_ABORT 0x40000000
+#define XL_DMACTL_MASTER_ABORT 0x80000000
+
+/*
+ * Command codes. Some command codes require that we wait for
+ * the CMD_BUSY flag to clear. Those codes are marked as 'mustwait.'
+ */
+#define XL_CMD_RESET 0x0000 /* mustwait */
+#define XL_CMD_WINSEL 0x0800
+#define XL_CMD_COAX_START 0x1000
+#define XL_CMD_RX_DISABLE 0x1800
+#define XL_CMD_RX_ENABLE 0x2000
+#define XL_CMD_RX_RESET 0x2800 /* mustwait */
+#define XL_CMD_UP_STALL 0x3000 /* mustwait */
+#define XL_CMD_UP_UNSTALL 0x3001
+#define XL_CMD_DOWN_STALL 0x3002 /* mustwait */
+#define XL_CMD_DOWN_UNSTALL 0x3003
+#define XL_CMD_RX_DISCARD 0x4000
+#define XL_CMD_TX_ENABLE 0x4800
+#define XL_CMD_TX_DISABLE 0x5000
+#define XL_CMD_TX_RESET 0x5800 /* mustwait */
+#define XL_CMD_INTR_FAKE 0x6000
+#define XL_CMD_INTR_ACK 0x6800
+#define XL_CMD_INTR_ENB 0x7000
+#define XL_CMD_STAT_ENB 0x7800
+#define XL_CMD_RX_SET_FILT 0x8000
+#define XL_CMD_RX_SET_THRESH 0x8800
+#define XL_CMD_TX_SET_THRESH 0x9000
+#define XL_CMD_TX_SET_START 0x9800
+#define XL_CMD_DMA_UP 0xA000
+#define XL_CMD_DMA_STOP 0xA001
+#define XL_CMD_STATS_ENABLE 0xA800
+#define XL_CMD_STATS_DISABLE 0xB000
+#define XL_CMD_COAX_STOP 0xB800
+
+#define XL_CMD_SET_TX_RECLAIM 0xC000 /* 3c905B only */
+#define XL_CMD_RX_SET_HASH 0xC800 /* 3c905B only */
+
+#define XL_HASH_SET 0x0400
+#define XL_HASHFILT_SIZE 256
+
+/*
+ * status codes
+ * Note that bits 15 to 13 indicate the currently visible register window
+ * which may be anything from 0 to 7.
+ */
+#define XL_STAT_INTLATCH 0x0001 /* 0 */
+#define XL_STAT_ADFAIL 0x0002 /* 1 */
+#define XL_STAT_TX_COMPLETE 0x0004 /* 2 */
+#define XL_STAT_TX_AVAIL 0x0008 /* 3 first generation */
+#define XL_STAT_RX_COMPLETE 0x0010 /* 4 */
+#define XL_STAT_RX_EARLY 0x0020 /* 5 */
+#define XL_STAT_INTREQ 0x0040 /* 6 */
+#define XL_STAT_STATSOFLOW 0x0080 /* 7 */
+#define XL_STAT_DMADONE 0x0100 /* 8 first generation */
+#define XL_STAT_LINKSTAT 0x0100 /* 8 3c509B */
+#define XL_STAT_DOWN_COMPLETE 0x0200 /* 9 */
+#define XL_STAT_UP_COMPLETE 0x0400 /* 10 */
+#define XL_STAT_DMABUSY 0x0800 /* 11 first generation */
+#define XL_STAT_CMDBUSY 0x1000 /* 12 */
+
+/*
+ * Interrupts we normally want enabled.
+ */
+#define XL_INTRS \
+ (XL_STAT_UP_COMPLETE|XL_STAT_STATSOFLOW|XL_STAT_ADFAIL| \
+ XL_STAT_DOWN_COMPLETE|XL_STAT_TX_COMPLETE|XL_STAT_INTLATCH)
+
+/*
+ * Window 0 registers
+ */
+#define XL_W0_EE_DATA 0x0C
+#define XL_W0_EE_CMD 0x0A
+#define XL_W0_RSRC_CFG 0x08
+#define XL_W0_ADDR_CFG 0x06
+#define XL_W0_CFG_CTRL 0x04
+
+#define XL_W0_PROD_ID 0x02
+#define XL_W0_MFG_ID 0x00
+
+/*
+ * Window 1
+ */
+
+#define XL_W1_TX_FIFO 0x10
+
+#define XL_W1_FREE_TX 0x0C
+#define XL_W1_TX_STATUS 0x0B
+#define XL_W1_TX_TIMER 0x0A
+#define XL_W1_RX_STATUS 0x08
+#define XL_W1_RX_FIFO 0x00
+
+/*
+ * RX status codes
+ */
+#define XL_RXSTATUS_OVERRUN 0x01
+#define XL_RXSTATUS_RUNT 0x02
+#define XL_RXSTATUS_ALIGN 0x04
+#define XL_RXSTATUS_CRC 0x08
+#define XL_RXSTATUS_OVERSIZE 0x10
+#define XL_RXSTATUS_DRIBBLE 0x20
+
+/*
+ * TX status codes
+ */
+#define XL_TXSTATUS_RECLAIM 0x02 /* 3c905B only */
+#define XL_TXSTATUS_OVERFLOW 0x04
+#define XL_TXSTATUS_MAXCOLS 0x08
+#define XL_TXSTATUS_UNDERRUN 0x10
+#define XL_TXSTATUS_JABBER 0x20
+#define XL_TXSTATUS_INTREQ 0x40
+#define XL_TXSTATUS_COMPLETE 0x80
+
+/*
+ * Window 2
+ */
+#define XL_W2_RESET_OPTIONS 0x0C /* 3c905B only */
+#define XL_W2_STATION_MASK_HI 0x0A
+#define XL_W2_STATION_MASK_MID 0x08
+#define XL_W2_STATION_MASK_LO 0x06
+#define XL_W2_STATION_ADDR_HI 0x04
+#define XL_W2_STATION_ADDR_MID 0x02
+#define XL_W2_STATION_ADDR_LO 0x00
+
+#define XL_RESETOPT_FEATUREMASK 0x0001|0x0002|0x004
+#define XL_RESETOPT_D3RESETDIS 0x0008
+#define XL_RESETOPT_DISADVFD 0x0010
+#define XL_RESETOPT_DISADV100 0x0020
+#define XL_RESETOPT_DISAUTONEG 0x0040
+#define XL_RESETOPT_DEBUGMODE 0x0080
+#define XL_RESETOPT_FASTAUTO 0x0100
+#define XL_RESETOPT_FASTEE 0x0200
+#define XL_RESETOPT_FORCEDCONF 0x0400
+#define XL_RESETOPT_TESTPDTPDR 0x0800
+#define XL_RESETOPT_TEST100TX 0x1000
+#define XL_RESETOPT_TEST100RX 0x2000
+
+/*
+ * Window 3 (fifo management)
+ */
+#define XL_W3_INTERNAL_CFG 0x00
+#define XL_W3_RESET_OPT 0x08
+#define XL_W3_FREE_TX 0x0C
+#define XL_W3_FREE_RX 0x0A
+#define XL_W3_MAC_CTRL 0x06
+
+#define XL_ICFG_CONNECTOR_MASK 0x00F00000
+#define XL_ICFG_CONNECTOR_BITS 20
+
+#define XL_ICFG_RAMSIZE_MASK 0x00000007
+#define XL_ICFG_RAMWIDTH 0x00000008
+#define XL_ICFG_ROMSIZE_MASK (0x00000040|0x00000080)
+#define XL_ICFG_DISABLE_BASSD 0x00000100
+#define XL_ICFG_RAMLOC 0x00000200
+#define XL_ICFG_RAMPART (0x00010000|0x00020000)
+#define XL_ICFG_XCVRSEL (0x00100000|0x00200000|0x00400000)
+#define XL_ICFG_AUTOSEL 0x01000000
+
+#define XL_XCVR_10BT 0x00
+#define XL_XCVR_AUI 0x01
+#define XL_XCVR_RSVD_0 0x02
+#define XL_XCVR_COAX 0x03
+#define XL_XCVR_100BTX 0x04
+#define XL_XCVR_100BFX 0x05
+#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
+#define XL_MACCTRL_DEFER_1 0x0004
+#define XL_MACCTRL_DEFER_2 0x0008
+#define XL_MACCTRL_DEFER_3 0x0010
+#define XL_MACCTRL_DUPLEX 0x0020
+#define XL_MACCTRL_ALLOW_LARGE_PACK 0x0040
+#define XL_MACCTRL_EXTEND_AFTER_COL 0x0080 (3c905B only)
+#define XL_MACCTRL_FLOW_CONTROL_ENB 0x0100 (3c905B only)
+#define XL_MACCTRL_VLT_END 0x0200 (3c905B only)
+
+/*
+ * The 'reset options' register contains power-on reset values
+ * loaded from the EEPROM. This includes the supported media
+ * types on the card. It is also known as the media options register.
+ */
+#define XL_W3_MEDIA_OPT 0x08
+
+#define XL_MEDIAOPT_BT4 0x0001 /* MII */
+#define XL_MEDIAOPT_BTX 0x0002 /* on-chip */
+#define XL_MEDIAOPT_BFX 0x0004 /* on-chip */
+#define XL_MEDIAOPT_BT 0x0008 /* on-chip */
+#define XL_MEDIAOPT_BNC 0x0010 /* on-chip */
+#define XL_MEDIAOPT_AUI 0x0020 /* on-chip */
+#define XL_MEDIAOPT_MII 0x0040 /* MII */
+#define XL_MEDIAOPT_VCO 0x0100 /* 1st gen chip only */
+
+#define XL_MEDIAOPT_10FL 0x0100 /* 3x905B only, on-chip */
+#define XL_MEDIAOPT_MASK 0x01FF
+
+/*
+ * Window 4 (diagnostics)
+ */
+#define XL_W4_UPPERBYTESOK 0x0D
+#define XL_W4_BADSSD 0x0C
+#define XL_W4_MEDIA_STATUS 0x0A
+#define XL_W4_PHY_MGMT 0x08
+#define XL_W4_NET_DIAG 0x06
+#define XL_W4_FIFO_DIAG 0x04
+#define XL_W4_VCO_DIAG 0x02
+
+#define XL_W4_CTRLR_STAT 0x08
+#define XL_W4_TX_DIAG 0x00
+
+#define XL_MII_CLK 0x01
+#define XL_MII_DATA 0x02
+#define XL_MII_DIR 0x04
+
+#define XL_MEDIA_SQE 0x0008
+#define XL_MEDIA_10TP 0x00C0
+#define XL_MEDIA_LNK 0x0080
+#define XL_MEDIA_LNKBEAT 0x0800
+
+#define XL_MEDIASTAT_CRCSTRIP 0x0004
+#define XL_MEDIASTAT_SQEENB 0x0008
+#define XL_MEDIASTAT_COLDET 0x0010
+#define XL_MEDIASTAT_CARRIER 0x0020
+#define XL_MEDIASTAT_JABGUARD 0x0040
+#define XL_MEDIASTAT_LINKBEAT 0x0080
+#define XL_MEDIASTAT_JABDETECT 0x0200
+#define XL_MEDIASTAT_POLREVERS 0x0400
+#define XL_MEDIASTAT_LINKDETECT 0x0800
+#define XL_MEDIASTAT_TXINPROG 0x1000
+#define XL_MEDIASTAT_DCENB 0x4000
+#define XL_MEDIASTAT_AUIDIS 0x8000
+
+#define XL_NETDIAG_TEST_LOWVOLT 0x0001
+#define XL_NETDIAG_ASIC_REVMASK (0x0002|0x0004|0x0008|0x0010|0x0020)
+#define XL_NETDIAG_UPPER_BYTES_ENABLE 0x0040
+#define XL_NETDIAG_STATS_ENABLED 0x0080
+#define XL_NETDIAG_TX_FATALERR 0x0100
+#define XL_NETDIAG_TRANSMITTING 0x0200
+#define XL_NETDIAG_RX_ENABLED 0x0400
+#define XL_NETDIAG_TX_ENABLED 0x0800
+#define XL_NETDIAG_FIFO_LOOPBACK 0x1000
+#define XL_NETDIAG_MAC_LOOPBACK 0x2000
+#define XL_NETDIAG_ENDEC_LOOPBACK 0x4000
+#define XL_NETDIAG_EXTERNAL_LOOP 0x8000
+
+/*
+ * Window 5
+ */
+#define XL_W5_STAT_ENB 0x0C
+#define XL_W5_INTR_ENB 0x0A
+#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */
+#define XL_W5_RX_FILTER 0x08
+#define XL_W5_RX_EARLYTHRESH 0x06
+#define XL_W5_TX_AVAILTHRESH 0x02
+#define XL_W5_TX_STARTTHRESH 0x00
+
+/*
+ * RX filter bits
+ */
+#define XL_RXFILTER_INDIVIDUAL 0x01
+#define XL_RXFILTER_ALLMULTI 0x02
+#define XL_RXFILTER_BROADCAST 0x04
+#define XL_RXFILTER_ALLFRAMES 0x08
+#define XL_RXFILTER_MULTIHASH 0x10 /* 3c905B only */
+
+/*
+ * Window 6 (stats)
+ */
+#define XL_W6_TX_BYTES_OK 0x0C
+#define XL_W6_RX_BYTES_OK 0x0A
+#define XL_W6_UPPER_FRAMES_OK 0x09
+#define XL_W6_DEFERRED 0x08
+#define XL_W6_RX_OK 0x07
+#define XL_W6_TX_OK 0x06
+#define XL_W6_RX_OVERRUN 0x05
+#define XL_W6_COL_LATE 0x04
+#define XL_W6_COL_SINGLE 0x03
+#define XL_W6_COL_MULTIPLE 0x02
+#define XL_W6_SQE_ERRORS 0x01
+#define XL_W6_CARRIER_LOST 0x00
+
+/*
+ * Window 7 (bus master control)
+ */
+#define XL_W7_BM_ADDR 0x00
+#define XL_W7_BM_LEN 0x06
+#define XL_W7_BM_STATUS 0x0B
+#define XL_W7_BM_TIMEr 0x0A
+
+/*
+ * bus master control registers
+ */
+#define XL_BM_PKTSTAT 0x20
+#define XL_BM_DOWNLISTPTR 0x24
+#define XL_BM_FRAGADDR 0x28
+#define XL_BM_FRAGLEN 0x2C
+#define XL_BM_TXFREETHRESH 0x2F
+#define XL_BM_UPPKTSTAT 0x30
+#define XL_BM_UPLISTPTR 0x38
+
+#define XL_LAST_FRAG 0x80000000
+
+/*
+ * Boomerang/Cyclone TX/RX list structure.
+ * For the TX lists, bits 0 to 12 of the status word indicate
+ * length.
+ * This looks suspiciously like the ThunderLAN, doesn't it.
+ */
+struct xl_frag {
+ u_int32_t xl_addr; /* 63 addr/len pairs */
+ u_int32_t xl_len;
+};
+
+struct xl_list {
+ u_int32_t xl_next; /* final entry has 0 nextptr */
+ u_int32_t xl_status;
+ struct xl_frag xl_frag[63];
+};
+
+struct xl_list_onefrag {
+ u_int32_t xl_next; /* final entry has 0 nextptr */
+ u_int32_t xl_status;
+ struct xl_frag xl_frag;
+};
+
+#define XL_MAXFRAGS 63
+#define XL_RX_LIST_CNT 32
+#define XL_TX_LIST_CNT 32
+#define XL_MIN_FRAMELEN 60
+#define XL_INC(x, y) (x) = (x + 1) % (y)
+
+struct xl_list_data {
+ struct xl_list_onefrag xl_rx_list[XL_RX_LIST_CNT];
+ struct xl_list xl_tx_list[XL_TX_LIST_CNT];
+ unsigned char xl_pad[XL_MIN_FRAMELEN];
+};
+
+struct xl_chain {
+ struct xl_list *xl_ptr;
+ struct mbuf *xl_mbuf;
+ struct xl_chain *xl_next;
+ struct xl_chain *xl_prev;
+ u_int32_t xl_phys;
+};
+
+struct xl_chain_onefrag {
+ struct xl_list_onefrag *xl_ptr;
+ struct mbuf *xl_mbuf;
+ struct xl_chain_onefrag *xl_next;
+};
+
+struct xl_chain_data {
+ struct xl_chain_onefrag xl_rx_chain[XL_RX_LIST_CNT];
+ struct xl_chain xl_tx_chain[XL_TX_LIST_CNT];
+
+ struct xl_chain_onefrag *xl_rx_head;
+
+ /* 3c90x "boomerang" queuing stuff */
+ struct xl_chain *xl_tx_head;
+ struct xl_chain *xl_tx_tail;
+ struct xl_chain *xl_tx_free;
+
+ /* 3c90xB "cyclone/hurricane/tornade" stuff */
+ int xl_tx_prod;
+ int xl_tx_cons;
+ int xl_tx_cnt;
+};
+
+#define XL_RXSTAT_LENMASK 0x00001FFF
+#define XL_RXSTAT_UP_ERROR 0x00004000
+#define XL_RXSTAT_UP_CMPLT 0x00008000
+#define XL_RXSTAT_UP_OVERRUN 0x00010000
+#define XL_RXSTAT_RUNT 0x00020000
+#define XL_RXSTAT_ALIGN 0x00040000
+#define XL_RXSTAT_CRC 0x00080000
+#define XL_RXSTAT_OVERSIZE 0x00100000
+#define XL_RXSTAT_DRIBBLE 0x00800000
+#define XL_RXSTAT_UP_OFLOW 0x01000000
+#define XL_RXSTAT_IPCKERR 0x02000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCKERR 0x04000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKERR 0x08000000 /* 3c905B only */
+#define XL_RXSTAT_BUFEN 0x10000000 /* 3c905B only */
+#define XL_RXSTAT_IPCKOK 0x20000000 /* 3c905B only */
+#define XL_RXSTAT_TCPCOK 0x40000000 /* 3c905B only */
+#define XL_RXSTAT_UDPCKOK 0x80000000 /* 3c905B only */
+
+#define XL_TXSTAT_LENMASK 0x00001FFF
+#define XL_TXSTAT_CRCDIS 0x00002000
+#define XL_TXSTAT_TX_INTR 0x00008000
+#define XL_TXSTAT_DL_COMPLETE 0x00010000
+#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */
+#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */
+#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */
+#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */
+#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */
+#define XL_TXSTAT_DL_INTR 0x80000000
+
+#define XL_CAPABILITY_BM 0x20
+
+struct xl_type {
+ u_int16_t xl_vid;
+ u_int16_t xl_did;
+ char *xl_name;
+};
+
+struct xl_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define XL_MII_STARTDELIM 0x01
+#define XL_MII_READOP 0x02
+#define XL_MII_WRITEOP 0x01
+#define XL_MII_TURNAROUND 0x02
+
+/*
+ * The 3C905B adapters implement a few features that we want to
+ * take advantage of, namely the multicast hash filter. With older
+ * chips, you only have the option of turning on reception of all
+ * multicast frames, which is kind of lame.
+ *
+ * We also use this to decide on a transmit strategy. For the 3c90xB
+ * cards, we can use polled descriptor mode, which reduces CPU overhead.
+ */
+#define XL_TYPE_905B 1
+#define XL_TYPE_90X 2
+
+struct xl_softc {
+ struct device sc_dev; /* generic device structure */
+ void * xl_intrhand; /* interrupt handler cookie */
+ struct arpcom arpcom; /* interface info */
+ struct ifmedia ifmedia; /* media info */
+ 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 */
+ u_int8_t xl_type;
+ u_int32_t xl_xcvr;
+ u_int16_t xl_media;
+ 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) \
+ ((x.xl_upper_frames_ok & 0x03) << 8) | x.xl_rx_frames_ok
+
+#define xl_tx_goodframes(x) \
+ ((x.xl_upper_frames_ok & 0x30) << 4) | x.xl_tx_frames_ok
+
+struct xl_stats {
+ u_int8_t xl_carrier_lost;
+ u_int8_t xl_sqe_errs;
+ u_int8_t xl_tx_multi_collision;
+ u_int8_t xl_tx_single_collision;
+ u_int8_t xl_tx_late_collision;
+ u_int8_t xl_rx_overrun;
+ u_int8_t xl_tx_frames_ok;
+ u_int8_t xl_rx_frames_ok;
+ u_int8_t xl_tx_deferred;
+ u_int8_t xl_upper_frames_ok;
+ u_int16_t xl_rx_bytes_ok;
+ u_int16_t xl_tx_bytes_ok;
+ u_int16_t status;
+};
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->xl_btag, sc->xl_bhandle, reg, val)
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->xl_btag, sc->xl_bhandle, reg, val)
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->xl_btag, sc->xl_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->xl_btag, sc->xl_bhandle, reg)
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2(sc->xl_btag, sc->xl_bhandle, reg)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1(sc->xl_btag, sc->xl_bhandle, reg)
+
+#define XL_SEL_WIN(x) \
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)
+#define XL_TIMEOUT 1000
+
+/*
+ * General constants that are fun to know.
+ *
+ * 3Com PCI vendor ID
+ */
+#define TC_VENDORID 0x10B7
+
+/*
+ * 3Com chip device IDs.
+ */
+#define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500
+#define TC_DEVICEID_BOOMERANG_10BT 0x9000
+#define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001
+#define TC_DEVICEID_BOOMERANG_10_100BT 0x9050
+#define TC_DEVICEID_BOOMERANG_100BT4 0x9051
+#define TC_DEVICEID_KRAKATOA_10BT 0x9004
+#define TC_DEVICEID_KRAKATOA_10BT_COMBO 0x9005
+#define TC_DEVICEID_KRAKATOA_10BT_TPC 0x9006
+#define TC_DEVICEID_CYCLONE_10FL 0x900A
+#define TC_DEVICEID_HURRICANE_10_100BT 0x9055
+#define TC_DEVICEID_CYCLONE_10_100BT4 0x9056
+#define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058
+#define TC_DEVICEID_CYCLONE_10_100FX 0x905A
+#define TC_DEVICEID_TORNADO_10_100BT 0x9200
+#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
+ * other PCI registers. Note: some are only available on
+ * the 3c905B, in particular those that related to power management.
+ */
+
+#define XL_PCI_VENDOR_ID 0x00
+#define XL_PCI_DEVICE_ID 0x02
+#define XL_PCI_COMMAND 0x04
+#define XL_PCI_STATUS 0x06
+#define XL_PCI_CLASSCODE 0x09
+#define XL_PCI_LATENCY_TIMER 0x0D
+#define XL_PCI_HEADER_TYPE 0x0E
+#define XL_PCI_LOIO 0x10
+#define XL_PCI_LOMEM 0x14
+#define XL_PCI_BIOSROM 0x30
+#define XL_PCI_INTLINE 0x3C
+#define XL_PCI_INTPIN 0x3D
+#define XL_PCI_MINGNT 0x3E
+#define XL_PCI_MINLAT 0x0F
+#define XL_PCI_RESETOPT 0x48
+#define XL_PCI_EEPROM_DATA 0x4C
+
+/* 3c905B-only registers */
+#define XL_PCI_CAPID 0xDC /* 8 bits */
+#define XL_PCI_NEXTPTR 0xDD /* 8 bits */
+#define XL_PCI_PWRMGMTCAP 0xDE /* 16 bits */
+#define XL_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
+
+#define XL_PSTATE_MASK 0x0003
+#define XL_PSTATE_D0 0x0000
+#define XL_PSTATE_D1 0x0002
+#define XL_PSTATE_D2 0x0002
+#define XL_PSTATE_D3 0x0003
+#define XL_PME_EN 0x0010
+#define XL_PME_STATUS 0x8000
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
+
+#ifndef ETHER_ALIGN
+#define ETHER_ALIGN 2
+#endif
+
+extern int xl_intr __P((void *));
+extern void xl_attach __P((struct xl_softc *));
-/* $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 $ */
/*
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;
else
ist = IST_LEVEL;
- irq = pcic_intr_find(h->sc, ist);
+ irq = pcic_intr_find(sc, ist);
if (!irq)
return (NULL);
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;
-# $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.
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
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
+++ /dev/null
-/* $OpenBSD: if_xl.c,v 1.38 2000/02/15 13:47:52 jason Exp $ */
-
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
- * 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: if_xl.c,v 1.72 2000/01/09 21:12:59 wpaul Exp $
- */
-
-/*
- * 3Com 3c90x Etherlink XL PCI NIC driver
- *
- * Supports the 3Com "boomerang", "cyclone", and "hurricane" PCI
- * bus-master chips (3c90x cards and embedded controllers) including
- * the following:
- *
- * 3Com 3c900-TPO 10Mbps/RJ-45
- * 3Com 3c900-COMBO 10Mbps/RJ-45,AUI,BNC
- * 3Com 3c905-TX 10/100Mbps/RJ-45
- * 3Com 3c905-T4 10/100Mbps/RJ-45
- * 3Com 3c900B-TPO 10Mbps/RJ-45
- * 3Com 3c900B-COMBO 10Mbps/RJ-45,AUI,BNC
- * 3Com 3c900B-TPC 10Mbps/RJ-45,BNC
- * 3Com 3c900B-FL 10Mbps/Fiber-optic
- * 3Com 3c905B-COMBO 10/100Mbps/RJ-45,AUI,BNC
- * 3Com 3c905B-TX 10/100Mbps/RJ-45
- * 3Com 3c900-FL/FX 10/100Mbps/Fiber-optic
- * 3Com 3c905C-TX 10/100Mbps/RJ-45 (Tornado ASIC)
- * 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 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
- * Dell Precision on-board 3c905B 10/100Mbps/RJ-45
- * Dell Latitude laptop docking station embedded 3c905-TX
- *
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The 3c90x series chips use a bus-master DMA interface for transfering
- * packets to and from the controller chip. Some of the "vortex" cards
- * (3c59x) also supported a bus master mode, however for those chips
- * you could only DMA packets to/from a contiguous memory buffer. For
- * transmission this would mean copying the contents of the queued mbuf
- * chain into a an mbuf cluster and then DMAing the cluster. This extra
- * copy would sort of defeat the purpose of the bus master support for
- * any packet that doesn't fit into a single mbuf.
- *
- * By contrast, the 3c90x cards support a fragment-based bus master
- * mode where mbuf chains can be encapsulated using TX descriptors.
- * This is similar to other PCI chips such as the Texas Instruments
- * ThunderLAN and the Intel 82557/82558.
- *
- * The "vortex" driver (if_vx.c) happens to work for the "boomerang"
- * bus master chips because they maintain the old PIO interface for
- * backwards compatibility, but starting with the 3c905B and the
- * "cyclone" chips, the compatibility interface has been dropped.
- * Since using bus master DMA is a big win, we use this driver to
- * support the PCI "boomerang" chips even though they work with the
- * "vortex" driver in order to obtain better performance.
- *
- * This driver is in the /sys/pci directory because it only supports
- * PCI-based NICs.
- */
-
-#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/pci/if_xlreg.h>
-
-int xl_probe __P((struct device *, void *, void *));
-void xl_attach __P((struct device *, struct device *, void *));
-
-int xl_newbuf __P((struct xl_softc *, struct xl_chain_onefrag *));
-void xl_stats_update __P((void *));
-int xl_encap __P((struct xl_softc *, struct xl_chain *,
- struct mbuf * ));
-int xl_encap_90xB __P((struct xl_softc *, struct xl_chain *,
- struct mbuf * ));
-void xl_rxeof __P((struct xl_softc *));
-int xl_rx_resync __P((struct xl_softc *));
-void xl_txeof __P((struct xl_softc *));
-void xl_txeof_90xB __P((struct xl_softc *));
-void xl_txeoc __P((struct xl_softc *));
-int xl_intr __P((void *));
-void xl_start __P((struct ifnet *));
-void xl_start_90xB __P((struct ifnet *));
-int xl_ioctl __P((struct ifnet *, u_long, caddr_t));
-void xl_init __P((void *));
-void xl_stop __P((struct xl_softc *));
-void xl_watchdog __P((struct ifnet *));
-void xl_shutdown __P((void *));
-int xl_ifmedia_upd __P((struct ifnet *));
-void xl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-int xl_eeprom_wait __P((struct xl_softc *));
-int xl_read_eeprom __P((struct xl_softc *, caddr_t, int, int, int));
-void xl_mii_sync __P((struct xl_softc *));
-void xl_mii_send __P((struct xl_softc *, u_int32_t, int));
-int xl_mii_readreg __P((struct xl_softc *, struct xl_mii_frame *));
-int xl_mii_writereg __P((struct xl_softc *, struct xl_mii_frame *));
-
-void xl_setcfg __P((struct xl_softc *));
-void xl_setmode __P((struct xl_softc *, int));
-u_int8_t xl_calchash __P((caddr_t));
-void xl_setmulti __P((struct xl_softc *));
-void xl_setmulti_hash __P((struct xl_softc *));
-void xl_reset __P((struct xl_softc *, int));
-int xl_list_rx_init __P((struct xl_softc *));
-int xl_list_tx_init __P((struct xl_softc *));
-int xl_list_tx_init_90xB __P((struct xl_softc *));
-void xl_wait __P((struct xl_softc *));
-void xl_mediacheck __P((struct xl_softc *));
-void xl_choose_xcvr __P((struct xl_softc *, int));
-#ifdef notdef
-void xl_testpacket __P((struct xl_softc *));
-#endif
-
-int xl_miibus_readreg __P((struct device *, int, int));
-void xl_miibus_writereg __P((struct device *, int, int, int));
-void xl_miibus_statchg __P((struct device *));
-
-/*
- * Murphy's law says that it's possible the chip can wedge and
- * the 'command in progress' bit may never clear. Hence, we wait
- * only a finite amount of time to avoid getting caught in an
- * infinite loop. Normally this delay routine would be a macro,
- * but it isn't called during normal operation so we can afford
- * to make it a function.
- */
-void xl_wait(sc)
- struct xl_softc *sc;
-{
- register int i;
-
- for (i = 0; i < XL_TIMEOUT; i++) {
- if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
- break;
- }
-
-#ifdef DIAGNOSTIC
- if (i == XL_TIMEOUT)
- printf("xl%d: command never completed!\n", sc->xl_unit);
-#endif
-
- return;
-}
-
-/*
- * MII access routines are provided for adapters with external
- * PHYs (3c905-TX, 3c905-T4, 3c905B-T4) and those with built-in
- * autoneg logic that's faked up to look like a PHY (3c905B-TX).
- * Note: if you don't perform the MDIO operations just right,
- * it's possible to end up with code that works correctly with
- * some chips/CPUs/processor speeds/bus speeds/etc but not
- * with others.
- */
-#define MII_SET(x) \
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
- CSR_READ_2(sc, XL_W4_PHY_MGMT) | x)
-
-#define MII_CLR(x) \
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \
- CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~x)
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-void xl_mii_sync(sc)
- struct xl_softc *sc;
-{
- register int i;
-
- XL_SEL_WIN(4);
- MII_SET(XL_MII_DIR|XL_MII_DATA);
-
- for (i = 0; i < 32; i++) {
- MII_SET(XL_MII_CLK);
- DELAY(1);
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- }
-
- return;
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-void xl_mii_send(sc, bits, cnt)
- struct xl_softc *sc;
- u_int32_t bits;
- int cnt;
-{
- int i;
-
- XL_SEL_WIN(4);
- MII_CLR(XL_MII_CLK);
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
- if (bits & i) {
- MII_SET(XL_MII_DATA);
- } else {
- MII_CLR(XL_MII_DATA);
- }
- DELAY(1);
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- MII_SET(XL_MII_CLK);
- }
-}
-
-/*
- * Read an PHY register through the MII.
- */
-int xl_mii_readreg(sc, frame)
- struct xl_softc *sc;
- struct xl_mii_frame *frame;
-
-{
- int i, ack, s;
-
- s = splimp();
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = XL_MII_STARTDELIM;
- frame->mii_opcode = XL_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /*
- * Select register window 4.
- */
-
- XL_SEL_WIN(4);
-
- CSR_WRITE_2(sc, XL_W4_PHY_MGMT, 0);
- /*
- * Turn on data xmit.
- */
- MII_SET(XL_MII_DIR);
-
- xl_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- xl_mii_send(sc, frame->mii_stdelim, 2);
- xl_mii_send(sc, frame->mii_opcode, 2);
- xl_mii_send(sc, frame->mii_phyaddr, 5);
- xl_mii_send(sc, frame->mii_regaddr, 5);
-
- /* Idle bit */
- MII_CLR((XL_MII_CLK|XL_MII_DATA));
- DELAY(1);
- MII_SET(XL_MII_CLK);
- DELAY(1);
-
- /* Turn off xmit. */
- MII_CLR(XL_MII_DIR);
-
- /* Check for ack */
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- MII_SET(XL_MII_CLK);
- DELAY(1);
- ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA;
-
- /*
- * Now try reading data bits. If the ack failed, we still
- * need to clock through 16 cycles to keep the PHY(s) in sync.
- */
- if (ack) {
- for(i = 0; i < 16; i++) {
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- MII_SET(XL_MII_CLK);
- DELAY(1);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- if (!ack) {
- if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA)
- frame->mii_data |= i;
- DELAY(1);
- }
- MII_SET(XL_MII_CLK);
- DELAY(1);
- }
-
-fail:
-
- MII_CLR(XL_MII_CLK);
- DELAY(1);
- MII_SET(XL_MII_CLK);
- DELAY(1);
-
- splx(s);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-int xl_mii_writereg(sc, frame)
- struct xl_softc *sc;
- struct xl_mii_frame *frame;
-
-{
- int s;
-
- s = splimp();
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = XL_MII_STARTDELIM;
- frame->mii_opcode = XL_MII_WRITEOP;
- frame->mii_turnaround = XL_MII_TURNAROUND;
-
- /*
- * Select the window 4.
- */
- XL_SEL_WIN(4);
-
- /*
- * Turn on data output.
- */
- MII_SET(XL_MII_DIR);
-
- xl_mii_sync(sc);
-
- xl_mii_send(sc, frame->mii_stdelim, 2);
- xl_mii_send(sc, frame->mii_opcode, 2);
- xl_mii_send(sc, frame->mii_phyaddr, 5);
- xl_mii_send(sc, frame->mii_regaddr, 5);
- xl_mii_send(sc, frame->mii_turnaround, 2);
- xl_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- MII_SET(XL_MII_CLK);
- DELAY(1);
- MII_CLR(XL_MII_CLK);
- DELAY(1);
-
- /*
- * Turn off xmit.
- */
- MII_CLR(XL_MII_DIR);
-
- splx(s);
-
- return(0);
-}
-
-int
-xl_miibus_readreg(self, phy, reg)
- struct device *self;
- int phy, reg;
-{
- struct xl_softc *sc = (struct xl_softc *)self;
- struct xl_mii_frame frame;
-
- if (phy != 24)
- return (0);
-
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- xl_mii_readreg(sc, &frame);
-
- return(frame.mii_data);
-}
-
-void
-xl_miibus_writereg(self, phy, reg, data)
- struct device *self;
- int phy, reg, data;
-{
- struct xl_softc *sc = (struct xl_softc *)self;
- struct xl_mii_frame frame;
-
- if (phy != 24)
- return;
-
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
-
- xl_mii_writereg(sc, &frame);
-}
-
-void
-xl_miibus_statchg(self)
- struct device *self;
-{
- struct xl_softc *sc = (struct xl_softc *)self;
-
- xl_setcfg(sc);
-
- XL_SEL_WIN(3);
- if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
- CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
- else
- CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
- (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
-}
-
-/*
- * The EEPROM is slow: give it time to come ready after issuing
- * it a command.
- */
-int xl_eeprom_wait(sc)
- struct xl_softc *sc;
-{
- int i;
-
- for (i = 0; i < 100; i++) {
- if (CSR_READ_2(sc, XL_W0_EE_CMD) & XL_EE_BUSY)
- DELAY(162);
- else
- break;
- }
-
- if (i == 100) {
- printf("xl%d: eeprom failed to come ready\n", sc->xl_unit);
- return(1);
- }
-
- return(0);
-}
-
-/*
- * Read a sequence of words from the EEPROM. Note that ethernet address
- * data is stored in the EEPROM in network byte order.
- */
-int xl_read_eeprom(sc, dest, off, cnt, swap)
- struct xl_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int err = 0, i;
- u_int16_t word = 0, *ptr;
-
- XL_SEL_WIN(0);
-
- if (xl_eeprom_wait(sc))
- return(1);
-
- for (i = 0; i < cnt; i++) {
- CSR_WRITE_2(sc, XL_W0_EE_CMD, XL_EE_READ | (off + i));
- err = xl_eeprom_wait(sc);
- if (err)
- break;
- word = CSR_READ_2(sc, XL_W0_EE_DATA);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return(err ? 1 : 0);
-}
-
-/*
- * This routine is taken from the 3Com Etherlink XL manual,
- * page 10-7. It calculates a CRC of the supplied multicast
- * group address and returns the lower 8 bits, which are used
- * as the multicast filter position.
- * Note: the 3c905B currently only supports a 64-bit hash table,
- * which means we really only need 6 bits, but the manual indicates
- * that future chip revisions will have a 256-bit hash table,
- * hence the routine is set up to calculate 8 bits of position
- * info in case we need it some day.
- * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a
- * 256 bit hash table. This means we have to use all 8 bits regardless.
- * On older cards, the upper 2 bits will be ignored. Grrrr....
- */
-u_int8_t xl_calchash(addr)
- caddr_t addr;
-{
- u_int32_t crc, carry;
- int i, j;
- u_int8_t c;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (i = 0; i < 6; i++) {
- c = *(addr + i);
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
- crc <<= 1;
- c >>= 1;
- if (carry)
- crc = (crc ^ 0x04c11db6) | carry;
- }
- }
-
- /* return the filter bit position */
- return(crc & 0x000000FF);
-}
-
-/*
- * NICs older than the 3c905B have only one multicast option, which
- * is to enable reception of all multicast frames.
- */
-void xl_setmulti(sc)
- struct xl_softc *sc;
-{
- struct ifnet *ifp;
- struct arpcom *ac = &sc->arpcom;
- struct ether_multi *enm;
- struct ether_multistep step;
- u_int8_t rxfilt;
- int mcnt = 0;
-
- ifp = &sc->arpcom.ac_if;
-
- XL_SEL_WIN(5);
- rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
-
- if (ifp->if_flags & IFF_ALLMULTI) {
- rxfilt |= XL_RXFILTER_ALLMULTI;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- return;
- }
-
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- mcnt++;
- ETHER_NEXT_MULTI(step, enm);
- }
-
- if (mcnt)
- rxfilt |= XL_RXFILTER_ALLMULTI;
- else
- rxfilt &= ~XL_RXFILTER_ALLMULTI;
-
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-
- return;
-}
-
-/*
- * 3c905B adapters have a hash filter that we can program.
- */
-void xl_setmulti_hash(sc)
- struct xl_softc *sc;
-{
- struct ifnet *ifp;
- int h = 0, i;
- struct arpcom *ac = &sc->arpcom;
- struct ether_multi *enm;
- struct ether_multistep step;
- u_int8_t rxfilt;
- int mcnt = 0;
-
- ifp = &sc->arpcom.ac_if;
-
- XL_SEL_WIN(5);
- rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
-
- if (ifp->if_flags & IFF_ALLMULTI) {
-allmulti:
- rxfilt |= XL_RXFILTER_ALLMULTI;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- return;
- } else
- rxfilt &= ~XL_RXFILTER_ALLMULTI;
-
-
- /* first, zot all the existing hash bits */
- for (i = 0; i < XL_HASHFILT_SIZE; i++)
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);
-
- /* now program new ones */
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
- ifp->if_flags |= IFF_ALLMULTI;
- goto allmulti;
- }
- h = xl_calchash(enm->enm_addrlo);
- mcnt++;
- ETHER_NEXT_MULTI(step, enm);
- }
-
- if (mcnt)
- rxfilt |= XL_RXFILTER_MULTIHASH;
- else
- rxfilt &= ~XL_RXFILTER_MULTIHASH;
-
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-
- return;
-}
-
-#ifdef notdef
-void xl_testpacket(sc)
- struct xl_softc *sc;
-{
- struct mbuf *m;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- MGETHDR(m, M_DONTWAIT, MT_DATA);
-
- if (m == NULL)
- return;
-
- bcopy(&sc->arpcom.ac_enaddr,
- mtod(m, struct ether_header *)->ether_dhost, ETHER_ADDR_LEN);
- bcopy(&sc->arpcom.ac_enaddr,
- mtod(m, struct ether_header *)->ether_shost, ETHER_ADDR_LEN);
- mtod(m, struct ether_header *)->ether_type = htons(3);
- mtod(m, unsigned char *)[14] = 0;
- mtod(m, unsigned char *)[15] = 0;
- mtod(m, unsigned char *)[16] = 0xE3;
- m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
- IF_ENQUEUE(&ifp->if_snd, m);
- xl_start(ifp);
-
- return;
-}
-#endif
-
-void xl_setcfg(sc)
- struct xl_softc *sc;
-{
- u_int32_t icfg;
-
- XL_SEL_WIN(3);
- icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- if (sc->xl_media & XL_MEDIAOPT_MII ||
- sc->xl_media & XL_MEDIAOPT_BT4)
- icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS);
- if (sc->xl_media & XL_MEDIAOPT_BTX)
- icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS);
-
- CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
- CSR_WRITE_4(sc, XL_COMMAND, XL_CMD_COAX_STOP);
-}
-
-void xl_setmode(sc, media)
- struct xl_softc *sc;
- int media;
-{
- u_int32_t icfg;
- u_int16_t mediastat;
-
- printf("xl%d: selecting ", sc->xl_unit);
-
- XL_SEL_WIN(4);
- mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
- XL_SEL_WIN(3);
- icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG);
-
- if (sc->xl_media & XL_MEDIAOPT_BT) {
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- printf("10baseT transceiver, ");
- sc->xl_xcvr = XL_XCVR_10BT;
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS);
- mediastat |= XL_MEDIASTAT_LINKBEAT|
- XL_MEDIASTAT_JABGUARD;
- mediastat &= ~XL_MEDIASTAT_SQEENB;
- }
- }
-
- if (sc->xl_media & XL_MEDIAOPT_BFX) {
- if (IFM_SUBTYPE(media) == IFM_100_FX) {
- printf("100baseFX port, ");
- sc->xl_xcvr = XL_XCVR_100BFX;
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS);
- mediastat |= XL_MEDIASTAT_LINKBEAT;
- mediastat &= ~XL_MEDIASTAT_SQEENB;
- }
- }
-
- if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
- if (IFM_SUBTYPE(media) == IFM_10_5) {
- printf("AUI port, ");
- sc->xl_xcvr = XL_XCVR_AUI;
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
- mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
- XL_MEDIASTAT_JABGUARD);
- mediastat |= ~XL_MEDIASTAT_SQEENB;
- }
- if (IFM_SUBTYPE(media) == IFM_10_FL) {
- printf("10baseFL transceiver, ");
- sc->xl_xcvr = XL_XCVR_AUI;
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS);
- mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
- XL_MEDIASTAT_JABGUARD);
- mediastat |= ~XL_MEDIASTAT_SQEENB;
- }
- }
-
- if (sc->xl_media & XL_MEDIAOPT_BNC) {
- if (IFM_SUBTYPE(media) == IFM_10_2) {
- printf("BNC port, ");
- sc->xl_xcvr = XL_XCVR_COAX;
- icfg &= ~XL_ICFG_CONNECTOR_MASK;
- icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS);
- mediastat &= ~(XL_MEDIASTAT_LINKBEAT|
- XL_MEDIASTAT_JABGUARD|
- XL_MEDIASTAT_SQEENB);
- }
- }
-
- if ((media & IFM_GMASK) == IFM_FDX ||
- IFM_SUBTYPE(media) == IFM_100_FX) {
- printf("full duplex\n");
- XL_SEL_WIN(3);
- CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX);
- } else {
- printf("half duplex\n");
- XL_SEL_WIN(3);
- CSR_WRITE_1(sc, XL_W3_MAC_CTRL,
- (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX));
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_2)
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
- else
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
- CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg);
- XL_SEL_WIN(4);
- CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat);
- DELAY(800);
- XL_SEL_WIN(7);
-}
-
-void xl_reset(sc, hard)
- struct xl_softc *sc;
-{
- register int i;
-
- XL_SEL_WIN(0);
- if (hard)
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET);
- else
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | 0x0010);
- xl_wait(sc);
-
- for (i = 0; i < XL_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY))
- break;
- }
-
- DELAY(100000);
-
- /* Reset TX and RX. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
- xl_wait(sc);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
- xl_wait(sc);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(100000);
- 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
- * (or reset options register, as it's called for the first generation
- * 3c90x adapters) to return an incorrect result. I have encountered
- * one Dell Latitude laptop docking station with an integrated 3c905-TX
- * which doesn't have any of the 'mediaopt' bits set. This screws up
- * the attach routine pretty badly because it doesn't know what media
- * to look for. If we find ourselves in this predicament, this routine
- * will try to guess the media options values and warn the user of a
- * possible manufacturing defect with his adapter/system/whatever.
- */
-void xl_mediacheck(sc)
- struct xl_softc *sc;
-{
- /*
- * If some of the media options bits are set, assume they are
- * correct. If not, try to figure it out down below.
- * XXX I should check for 10baseFL, but I don't have an adapter
- * to test with.
- */
- if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) {
- /*
- * Check the XCVR value. If it's not in the normal range
- * of values, we need to fake it up here.
- */
- if (sc->xl_xcvr <= XL_XCVR_AUTO)
- return;
- else {
- printf("xl%d: bogus xcvr value "
- "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr);
- printf("xl%d: choosing new default based "
- "on card type\n", sc->xl_unit);
- }
- } else {
- if (sc->xl_type == XL_TYPE_905B &&
- sc->xl_media & XL_MEDIAOPT_10FL)
- return;
- printf("xl%d: WARNING: no media options bits set in "
- "the media options register!!\n", sc->xl_unit);
- printf("xl%d: this could be a manufacturing defect in "
- "your adapter or system\n", sc->xl_unit);
- printf("xl%d: attempting to guess media type; you "
- "should probably consult your vendor\n", sc->xl_unit);
- }
-
- xl_choose_xcvr(sc, 1);
-}
-
-void xl_choose_xcvr(sc, verbose)
- struct xl_softc *sc;
- int verbose;
-{
- u_int16_t devid;
-
- /*
- * Read the device ID from the EEPROM.
- * This is what's loaded into the PCI device ID register, so it has
- * to be correct otherwise we wouldn't have gotten this far.
- */
- xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0);
-
- switch(devid) {
- case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */
- case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */
- sc->xl_media = XL_MEDIAOPT_BT;
- sc->xl_xcvr = XL_XCVR_10BT;
- if (verbose)
- printf("xl%d: guessing 10BaseT transceiver\n",
- sc->xl_unit);
- break;
- case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */
- case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */
- sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
- sc->xl_xcvr = XL_XCVR_10BT;
- if (verbose)
- printf("xl%d: guessing COMBO (AUI/BNC/TP)\n",
- sc->xl_unit);
- break;
- case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */
- sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC;
- sc->xl_xcvr = XL_XCVR_10BT;
- if (verbose)
- printf("xl%d: guessing TPC (BNC/TP)\n", sc->xl_unit);
- break;
- case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */
- sc->xl_media = XL_MEDIAOPT_10FL;
- sc->xl_xcvr = XL_XCVR_AUI;
- if (verbose)
- printf("xl%d: guessing 10baseFL\n", sc->xl_unit);
- break;
- case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */
- sc->xl_media = XL_MEDIAOPT_MII;
- sc->xl_xcvr = XL_XCVR_MII;
- if (verbose)
- printf("xl%d: guessing MII\n", sc->xl_unit);
- break;
- case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */
- case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */
- sc->xl_media = XL_MEDIAOPT_BT4;
- sc->xl_xcvr = XL_XCVR_MII;
- if (verbose)
- printf("xl%d: guessing 100BaseT4/MII\n", sc->xl_unit);
- break;
- case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */
- case TC_DEVICEID_HURRICANE_10_100BT_SERV:/* 3c980-TX */
- case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */
- case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */
- case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */
- case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */
- sc->xl_media = XL_MEDIAOPT_BTX;
- sc->xl_xcvr = XL_XCVR_AUTO;
- if (verbose)
- printf("xl%d: guessing 10/100 internal\n",
- sc->xl_unit);
- break;
- case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */
- sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI;
- sc->xl_xcvr = XL_XCVR_AUTO;
- if (verbose)
- printf("xl%d: guessing 10/100 plus BNC/AUI\n",
- sc->xl_unit);
- break;
- default:
- printf("xl%d: unknown device ID: %x -- "
- "defaulting to 10baseT\n", sc->xl_unit, devid);
- sc->xl_media = XL_MEDIAOPT_BT;
- break;
- }
-
- return;
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-int xl_list_tx_init(sc)
- struct xl_softc *sc;
-{
- struct xl_chain_data *cd;
- struct xl_list_data *ld;
- int i;
-
- cd = &sc->xl_cdata;
- ld = sc->xl_ldata;
- for (i = 0; i < XL_TX_LIST_CNT; i++) {
- cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
- if (i == (XL_TX_LIST_CNT - 1))
- cd->xl_tx_chain[i].xl_next = NULL;
- else
- cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
- }
-
- cd->xl_tx_free = &cd->xl_tx_chain[0];
- cd->xl_tx_tail = cd->xl_tx_head = NULL;
-
- return(0);
-}
-
-/*
- * Initialize the transmit desriptors.
- */
-int
-xl_list_tx_init_90xB(sc)
- struct xl_softc *sc;
-{
- struct xl_chain_data *cd;
- struct xl_list_data *ld;
- int i;
-
- cd = &sc->xl_cdata;
- ld = sc->xl_ldata;
- for (i = 0; i < XL_TX_LIST_CNT; i++) {
- cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
- cd->xl_tx_chain[i].xl_phys = vtophys(&ld->xl_tx_list[i]);
- if (i == (XL_TX_LIST_CNT - 1))
- cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0];
- else
- cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
- if (i == 0)
- cd->xl_tx_chain[i].xl_prev =
- &cd->xl_tx_chain[XL_TX_LIST_CNT - 1];
- else
- cd->xl_tx_chain[i].xl_prev =
- &cd->xl_tx_chain[i - 1];
- }
-
- bzero((char *)ld->xl_tx_list, sizeof(struct xl_list) * XL_TX_LIST_CNT);
- ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY;
-
- cd->xl_tx_prod = 1;
- cd->xl_tx_cons = 1;
- cd->xl_tx_cnt = 0;
-
- return (0);
-}
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-int xl_list_rx_init(sc)
- struct xl_softc *sc;
-{
- struct xl_chain_data *cd;
- struct xl_list_data *ld;
- int i;
-
- cd = &sc->xl_cdata;
- ld = sc->xl_ldata;
-
- for (i = 0; i < XL_RX_LIST_CNT; i++) {
- cd->xl_rx_chain[i].xl_ptr =
- (struct xl_list_onefrag *)&ld->xl_rx_list[i];
- if (xl_newbuf(sc, &cd->xl_rx_chain[i]) == ENOBUFS)
- return(ENOBUFS);
- if (i == (XL_RX_LIST_CNT - 1)) {
- cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0];
- ld->xl_rx_list[i].xl_next =
- vtophys(&ld->xl_rx_list[0]);
- } else {
- cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1];
- ld->xl_rx_list[i].xl_next =
- vtophys(&ld->xl_rx_list[i + 1]);
- }
- }
-
- cd->xl_rx_head = &cd->xl_rx_chain[0];
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- */
-int xl_newbuf(sc, c)
- struct xl_softc *sc;
- struct xl_chain_onefrag *c;
-{
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL)
- return(ENOBUFS);
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- return(ENOBUFS);
- }
-
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
-
- /* Force longword alignment for packet payload. */
- m_adj(m_new, ETHER_ALIGN);
-
- c->xl_mbuf = m_new;
- c->xl_ptr->xl_frag.xl_addr = vtophys(mtod(m_new, caddr_t));
- c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG;
- c->xl_ptr->xl_status = 0;
-
- return(0);
-}
-
-int xl_rx_resync(sc)
- struct xl_softc *sc;
-{
- struct xl_chain_onefrag *pos;
- int i;
-
- pos = sc->xl_cdata.xl_rx_head;
-
- for (i = 0; i < XL_RX_LIST_CNT; i++) {
- if (pos->xl_ptr->xl_status)
- break;
- pos = pos->xl_next;
- }
-
- if (i == XL_RX_LIST_CNT)
- return (0);
-
- sc->xl_cdata.xl_rx_head = pos;
-
- return (EAGAIN);
-}
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-void xl_rxeof(sc)
- struct xl_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct xl_chain_onefrag *cur_rx;
- int total_len = 0;
- u_int16_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
-
-again:
-
- while((rxstat = sc->xl_cdata.xl_rx_head->xl_ptr->xl_status)) {
- cur_rx = sc->xl_cdata.xl_rx_head;
- sc->xl_cdata.xl_rx_head = cur_rx->xl_next;
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & XL_RXSTAT_UP_ERROR) {
- ifp->if_ierrors++;
- cur_rx->xl_ptr->xl_status = 0;
- continue;
- }
-
- /*
- * If there error bit was not set, the upload complete
- * bit should be set which means we have a valid packet.
- * If not, something truly strange has happened.
- */
- if (!(rxstat & XL_RXSTAT_UP_CMPLT)) {
- printf("xl%d: bad receive status -- "
- "packet dropped", sc->xl_unit);
- ifp->if_ierrors++;
- cur_rx->xl_ptr->xl_status = 0;
- continue;
- }
-
- /* No errors; receive the packet. */
- m = cur_rx->xl_mbuf;
- total_len = cur_rx->xl_ptr->xl_status & XL_RXSTAT_LENMASK;
-
- /*
- * Try to conjure up a new mbuf cluster. If that
- * fails, it means we have an out of memory condition and
- * should leave the buffer in place and continue. This will
- * result in a lost packet, but there's little else we
- * can do in this situation.
- */
- if (xl_newbuf(sc, cur_rx) == ENOBUFS) {
- ifp->if_ierrors++;
- cur_rx->xl_ptr->xl_status = 0;
- continue;
- }
-
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
- m->m_pkthdr.rcvif = ifp;
-#if NBPFILTER > 0
- /*
- * Handle BPF listeners. Let the BPF user see the packet.
- */
- if (ifp->if_bpf) {
- m->m_pkthdr.len = m->m_len = total_len;
- bpf_mtap(ifp->if_bpf, m);
- }
-#endif
- /* Remove header from mbuf and pass it on. */
- m->m_pkthdr.len = m->m_len =
- total_len - sizeof(struct ether_header);
- m->m_data += sizeof(struct ether_header);
- ether_input(ifp, eh, m);
- }
-
- /*
- * Handle the 'end of channel' condition. When the upload
- * engine hits the end of the RX ring, it will stall. This
- * is our cue to flush the RX ring, reload the uplist pointer
- * register and unstall the engine.
- * XXX This is actually a little goofy. With the ThunderLAN
- * chip, you get an interrupt when the receiver hits the end
- * of the receive ring, which tells you exactly when you
- * you need to reload the ring pointer. Here we have to
- * fake it. I'm mad at myself for not being clever enough
- * to avoid the use of a goto here.
- */
- if (CSR_READ_4(sc, XL_UPLIST_PTR) == 0 ||
- CSR_READ_4(sc, XL_UPLIST_STATUS) & XL_PKTSTAT_UP_STALLED) {
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
- xl_wait(sc);
- CSR_WRITE_4(sc, XL_UPLIST_PTR,
- vtophys(&sc->xl_ldata->xl_rx_list[0]));
- sc->xl_cdata.xl_rx_head = &sc->xl_cdata.xl_rx_chain[0];
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
- goto again;
- }
-
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-void xl_txeof(sc)
- struct xl_softc *sc;
-{
- struct xl_chain *cur_tx;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been uploaded. Note: the 3c905B
- * sets a special bit in the status word to let us
- * know that a frame has been downloaded, but the
- * original 3c900/3c905 adapters don't do that.
- * Consequently, we have to use a different test if
- * xl_type != XL_TYPE_905B.
- */
- while(sc->xl_cdata.xl_tx_head != NULL) {
- cur_tx = sc->xl_cdata.xl_tx_head;
-
- if (CSR_READ_4(sc, XL_DOWNLIST_PTR))
- break;
-
- sc->xl_cdata.xl_tx_head = cur_tx->xl_next;
- m_freem(cur_tx->xl_mbuf);
- cur_tx->xl_mbuf = NULL;
- ifp->if_opackets++;
-
- cur_tx->xl_next = sc->xl_cdata.xl_tx_free;
- sc->xl_cdata.xl_tx_free = cur_tx;
- }
-
- if (sc->xl_cdata.xl_tx_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- sc->xl_cdata.xl_tx_tail = NULL;
- } else {
- if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED ||
- !CSR_READ_4(sc, XL_DOWNLIST_PTR)) {
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
- vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
- }
- }
-
- return;
-}
-
-void
-xl_txeof_90xB(sc)
- struct xl_softc *sc;
-{
- struct xl_chain *cur_tx = NULL;
- struct ifnet *ifp;
- int idx;
-
- ifp = &sc->arpcom.ac_if;
-
- idx = sc->xl_cdata.xl_tx_cons;
- while(idx != sc->xl_cdata.xl_tx_prod) {
-
- cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
-
- if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE))
- break;
-
- if (cur_tx->xl_mbuf != NULL) {
- m_freem(cur_tx->xl_mbuf);
- cur_tx->xl_mbuf = NULL;
- }
-
- ifp->if_opackets++;
-
- sc->xl_cdata.xl_tx_cnt--;
- XL_INC(idx, XL_TX_LIST_CNT);
- ifp->if_timer = 0;
- }
-
- sc->xl_cdata.xl_tx_cons = idx;
-
- if (cur_tx != NULL)
- ifp->if_flags &= ~IFF_OACTIVE;
-}
-
-/*
- * TX 'end of channel' interrupt handler. Actually, we should
- * only get a 'TX complete' interrupt if there's a transmit error,
- * so this is really TX error handler.
- */
-void xl_txeoc(sc)
- struct xl_softc *sc;
-{
- u_int8_t txstat;
-
- while((txstat = CSR_READ_1(sc, XL_TX_STATUS))) {
- if (txstat & XL_TXSTATUS_UNDERRUN ||
- txstat & XL_TXSTATUS_JABBER ||
- txstat & XL_TXSTATUS_RECLAIM) {
- printf("xl%d: transmission error: %x\n",
- sc->xl_unit, txstat);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
- xl_wait(sc);
- if (sc->xl_type == XL_TYPE_905B) {
- int i;
- struct xl_chain *c;
- i = sc->xl_cdata.xl_tx_cons;
- c = &sc->xl_cdata.xl_tx_chain[i];
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR, c->xl_phys);
- CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
- } else {
- if (sc->xl_cdata.xl_tx_head != NULL)
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
- vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
- }
- /*
- * Remember to set this for the
- * first generation 3c90X chips.
- */
- CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
- if (txstat & XL_TXSTATUS_UNDERRUN &&
- sc->xl_tx_thresh < XL_PACKET_SIZE) {
- sc->xl_tx_thresh += XL_MIN_FRAMELEN;
- printf("xl%d: tx underrun, increasing tx start"
- " threshold to %d\n", sc->xl_unit,
- sc->xl_tx_thresh);
- }
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_TX_SET_START|sc->xl_tx_thresh);
- if (sc->xl_type == XL_TYPE_905B) {
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
- }
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
- } else {
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
- }
- /*
- * Write an arbitrary byte to the TX_STATUS register
- * to clear this interrupt/error and advance to the next.
- */
- CSR_WRITE_1(sc, XL_TX_STATUS, 0x01);
- }
-
- return;
-}
-
-int xl_intr(arg)
- void *arg;
-{
- struct xl_softc *sc;
- struct ifnet *ifp;
- u_int16_t status;
- int claimed = 0;
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS) {
-
- claimed = 1;
-
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_INTR_ACK|(status & XL_INTRS));
-
- if (status & XL_STAT_UP_COMPLETE) {
- int curpkts;
-
- curpkts = ifp->if_ipackets;
- xl_rxeof(sc);
- if (curpkts == ifp->if_ipackets) {
- while (xl_rx_resync(sc))
- xl_rxeof(sc);
- }
- }
-
- if (status & XL_STAT_DOWN_COMPLETE) {
- if (sc->xl_type == XL_TYPE_905B)
- xl_txeof_90xB(sc);
- else
- xl_txeof(sc);
- }
-
- if (status & XL_STAT_TX_COMPLETE) {
- ifp->if_oerrors++;
- xl_txeoc(sc);
- }
-
- if (status & XL_STAT_ADFAIL) {
- xl_reset(sc, 0);
- xl_init(sc);
- }
-
- if (status & XL_STAT_STATSOFLOW) {
- sc->xl_stats_no_timeout = 1;
- xl_stats_update(sc);
- sc->xl_stats_no_timeout = 0;
- }
- }
-
- if (ifp->if_snd.ifq_head != NULL)
- (*ifp->if_start)(ifp);
-
- return (claimed);
-}
-
-void xl_stats_update(xsc)
- void *xsc;
-{
- struct xl_softc *sc;
- struct ifnet *ifp;
- struct xl_stats xl_stats;
- u_int8_t *p;
- int i;
- struct mii_data *mii = NULL;
-
- bzero((char *)&xl_stats, sizeof(struct xl_stats));
-
- sc = xsc;
- ifp = &sc->arpcom.ac_if;
- if (sc->xl_hasmii)
- mii = &sc->sc_mii;
-
- p = (u_int8_t *)&xl_stats;
-
- /* Read all the stats registers. */
- XL_SEL_WIN(6);
-
- for (i = 0; i < 16; i++)
- *p++ = CSR_READ_1(sc, XL_W6_CARRIER_LOST + i);
-
- ifp->if_ierrors += xl_stats.xl_rx_overrun;
-
- ifp->if_collisions += xl_stats.xl_tx_multi_collision +
- xl_stats.xl_tx_single_collision +
- xl_stats.xl_tx_late_collision;
-
- /*
- * Boomerang and cyclone chips have an extra stats counter
- * in window 4 (BadSSD). We have to read this too in order
- * to clear out all the stats registers and avoid a statsoflow
- * interrupt.
- */
- XL_SEL_WIN(4);
- CSR_READ_1(sc, XL_W4_BADSSD);
-
- if (mii != NULL)
- mii_tick(mii);
-
- XL_SEL_WIN(7);
-
- if (!sc->xl_stats_no_timeout)
- timeout(xl_stats_update, sc, hz);
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-int xl_encap(sc, c, m_head)
- struct xl_softc *sc;
- struct xl_chain *c;
- struct mbuf *m_head;
-{
- int frag = 0;
- struct xl_frag *f = NULL;
- int total_len;
- struct mbuf *m;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- m = m_head;
- total_len = 0;
-
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if (frag == XL_MAXFRAGS)
- break;
- total_len+= m->m_len;
- c->xl_ptr->xl_frag[frag].xl_addr =
- vtophys(mtod(m, vm_offset_t));
- c->xl_ptr->xl_frag[frag].xl_len = m->m_len;
- frag++;
- }
- }
-
- /*
- * Handle special case: we used up all 63 fragments,
- * but we have more mbufs left in the chain. Copy the
- * data into an mbuf cluster. Note that we don't
- * bother clearing the values in the other fragment
- * pointers/counters; it wouldn't gain us anything,
- * and would waste cycles.
- */
- if (m != NULL) {
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL)
- return(1);
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- return(1);
- }
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- m_freem(m_head);
- m_head = m_new;
- f = &c->xl_ptr->xl_frag[0];
- f->xl_addr = vtophys(mtod(m_new, caddr_t));
- f->xl_len = total_len = m_new->m_len;
- frag = 1;
- }
-
- c->xl_mbuf = m_head;
- c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
- c->xl_ptr->xl_status = total_len;
- c->xl_ptr->xl_next = 0;
-
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-void xl_start(ifp)
- struct ifnet *ifp;
-{
- struct xl_softc *sc;
- struct mbuf *m_head = NULL;
- struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
-
- sc = ifp->if_softc;
-
- /*
- * Check for an available queue slot. If there are none,
- * punt.
- */
- if (sc->xl_cdata.xl_tx_free == NULL) {
- xl_txeoc(sc);
- xl_txeof(sc);
- if (sc->xl_cdata.xl_tx_free == NULL) {
- ifp->if_flags |= IFF_OACTIVE;
- return;
- }
- }
-
- start_tx = sc->xl_cdata.xl_tx_free;
-
- while(sc->xl_cdata.xl_tx_free != NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- /* Pick a descriptor off the free list. */
- cur_tx = sc->xl_cdata.xl_tx_free;
- sc->xl_cdata.xl_tx_free = cur_tx->xl_next;
-
- cur_tx->xl_next = NULL;
-
- /* Pack the data into the descriptor. */
- xl_encap(sc, cur_tx, m_head);
-
- /* Chain it together. */
- if (prev != NULL) {
- prev->xl_next = cur_tx;
- prev->xl_ptr->xl_next = vtophys(cur_tx->xl_ptr);
- }
- prev = cur_tx;
-
-#if NBPFILTER > 0
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, cur_tx->xl_mbuf);
-#endif
- }
-
- /*
- * If there are no packets queued, bail.
- */
- if (cur_tx == NULL)
- return;
-
- /*
- * Place the request for the upload interrupt
- * in the last descriptor in the chain. This way, if
- * we're chaining several packets at once, we'll only
- * get an interupt once for the whole chain rather than
- * once for each packet.
- */
- cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
-
- /*
- * Queue the packets. If the TX channel is clear, update
- * the downlist pointer register.
- */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
- xl_wait(sc);
-
- if (sc->xl_cdata.xl_tx_head != NULL) {
- sc->xl_cdata.xl_tx_tail->xl_next = start_tx;
- sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next =
- vtophys(start_tx->xl_ptr);
- sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &=
- ~XL_TXSTAT_DL_INTR;
- sc->xl_cdata.xl_tx_tail = cur_tx;
- } else {
- sc->xl_cdata.xl_tx_head = start_tx;
- sc->xl_cdata.xl_tx_tail = cur_tx;
- }
- if (!CSR_READ_4(sc, XL_DOWNLIST_PTR))
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR, vtophys(start_tx->xl_ptr));
-
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
-
- XL_SEL_WIN(7);
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- /*
- * XXX Under certain conditions, usually on slower machines
- * where interrupts may be dropped, it's possible for the
- * adapter to chew up all the buffers in the receive ring
- * and stall, without us being able to do anything about it.
- * To guard against this, we need to make a pass over the
- * RX queue to make sure there aren't any packets pending.
- * Doing it here means we can flush the receive ring at the
- * same time the chip is DMAing the transmit descriptors we
- * just gave it.
- *
- * 3Com goes to some lengths to emphasize the Parallel Tasking (tm)
- * nature of their chips in all their marketing literature;
- * we may as well take advantage of it. :)
- */
- xl_rxeof(sc);
-
- return;
-}
-
-int xl_encap_90xB(sc, c, m_head)
- struct xl_softc *sc;
- struct xl_chain *c;
- struct mbuf *m_head;
-{
- int frag = 0;
- struct xl_frag *f = NULL;
- struct mbuf *m;
- struct xl_list *d;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- d = c->xl_ptr;
- d->xl_status = 0;
- d->xl_next = 0;
-
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if (frag == XL_MAXFRAGS)
- break;
- f = &d->xl_frag[frag];
- f->xl_addr = vtophys(mtod(m, vm_offset_t));
- f->xl_len = m->m_len;
- frag++;
- }
- }
-
- c->xl_mbuf = m_head;
- c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
- c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT;
-
- return(0);
-}
-
-void
-xl_start_90xB(ifp)
- struct ifnet *ifp;
-{
- struct xl_softc *sc;
- struct mbuf *m_head = NULL;
- struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
- int idx;
-
- sc = ifp->if_softc;
-
- if (ifp->if_flags & IFF_OACTIVE)
- return;
-
- idx = sc->xl_cdata.xl_tx_prod;
- start_tx = &sc->xl_cdata.xl_tx_chain[idx];
-
- while (sc->xl_cdata.xl_tx_chain[idx].xl_mbuf == NULL) {
-
- if ((XL_TX_LIST_CNT - sc->xl_cdata.xl_tx_cnt) < 3) {
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
-
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
-
- /* Pack the data into the descriptor. */
- xl_encap_90xB(sc, cur_tx, m_head);
-
- /* Chain it together. */
- if (prev != NULL)
- prev->xl_ptr->xl_next = cur_tx->xl_phys;
- prev = cur_tx;
-
-#if NBPFILTER > 0
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, cur_tx->xl_mbuf);
-#endif
-
- XL_INC(idx, XL_TX_LIST_CNT);
- sc->xl_cdata.xl_tx_cnt++;
- }
-
- /*
- * If there are no packets queued, bail.
- */
- if (cur_tx == NULL)
- return;
-
- /*
- * Place the request for the upload interrupt
- * in the last descriptor in the chain. This way, if
- * we're chaining several packets at once, we'll only
- * get an interupt once for the whole chain rather than
- * once for each packet.
- */
- cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
-
- /* Start transmission */
- sc->xl_cdata.xl_tx_prod = idx;
- start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys;
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-}
-
-void xl_init(xsc)
- void *xsc;
-{
- struct xl_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- int s, i;
- u_int16_t rxfilt = 0;
- struct mii_data *mii = NULL;
-
- s = splimp();
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- xl_stop(sc);
-
- if (sc->xl_hasmii)
- mii = &sc->sc_mii;
-
- if (mii == NULL) {
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
- xl_wait(sc);
- }
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
- xl_wait(sc);
- DELAY(10000);
-
-
- /* Init our MAC address */
- XL_SEL_WIN(2);
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
- CSR_WRITE_1(sc, XL_W2_STATION_ADDR_LO + i,
- sc->arpcom.ac_enaddr[i]);
- }
-
- /* Clear the station mask. */
- for (i = 0; i < 3; i++)
- CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0);
-#ifdef notdef
- /* Reset TX and RX. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
- xl_wait(sc);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
- xl_wait(sc);
-#endif
- /* Init circular RX list. */
- if (xl_list_rx_init(sc) == ENOBUFS) {
- printf("xl%d: initialization failed: no "
- "memory for rx buffers\n", sc->xl_unit);
- xl_stop(sc);
- return;
- }
-
- /* Init TX descriptors. */
- if (sc->xl_type == XL_TYPE_905B)
- xl_list_tx_init_90xB(sc);
- else
- xl_list_tx_init(sc);
-
- /*
- * Set the TX freethresh value.
- * Note that this has no effect on 3c905B "cyclone"
- * cards but is required for 3c900/3c905 "boomerang"
- * cards in order to enable the download engine.
- */
- CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8);
-
- /* Set the TX start threshold for best performance. */
- sc->xl_tx_thresh = XL_MIN_FRAMELEN;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_SET_START|sc->xl_tx_thresh);
-
- /*
- * If this is a 3c905B, also set the tx reclaim threshold.
- * This helps cut down on the number of tx reclaim errors
- * that could happen on a busy network. The chip multiplies
- * the register value by 16 to obtain the actual threshold
- * in bytes, so we divide by 16 when setting the value here.
- * The existing threshold value can be examined by reading
- * the register at offset 9 in window 5.
- */
- if (sc->xl_type == XL_TYPE_905B) {
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
- }
-
- /* Set RX filter bits. */
- XL_SEL_WIN(5);
- rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
-
- /* Set the individual bit to receive frames for this host only. */
- rxfilt |= XL_RXFILTER_INDIVIDUAL;
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- rxfilt |= XL_RXFILTER_ALLFRAMES;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- } else {
- rxfilt &= ~XL_RXFILTER_ALLFRAMES;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- }
-
- /*
- * Set capture broadcast bit to capture broadcast frames.
- */
- if (ifp->if_flags & IFF_BROADCAST) {
- rxfilt |= XL_RXFILTER_BROADCAST;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- } else {
- rxfilt &= ~XL_RXFILTER_BROADCAST;
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
- }
-
- /*
- * Program the multicast filter, if necessary.
- */
- if (sc->xl_type == XL_TYPE_905B)
- xl_setmulti_hash(sc);
- else
- xl_setmulti(sc);
-
- /*
- * Load the address of the RX list. We have to
- * stall the upload engine before we can manipulate
- * the uplist pointer register, then unstall it when
- * we're finished. We also have to wait for the
- * stall command to complete before proceeding.
- * Note that we have to do this after any RX resets
- * have completed since the uplist register is cleared
- * by a reset.
- */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
- xl_wait(sc);
- CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0]));
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
- xl_wait(sc);
-
- if (sc->xl_type == XL_TYPE_905B) {
- /* Set polling interval */
- CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
- /* Load the address of the TX list */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
- xl_wait(sc);
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
- vtophys(&sc->xl_ldata->xl_tx_list[0]));
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
- xl_wait(sc);
- }
-
- /*
- * If the coax transceiver is on, make sure to enable
- * the DC-DC converter.
- */
- XL_SEL_WIN(3);
- if (sc->xl_xcvr == XL_XCVR_COAX)
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START);
- else
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
-
- /* Clear out the stats counters. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
- sc->xl_stats_no_timeout = 1;
- xl_stats_update(sc);
- sc->xl_stats_no_timeout = 0;
- XL_SEL_WIN(4);
- CSR_WRITE_2(sc, XL_W4_NET_DIAG, XL_NETDIAG_UPPER_BYTES_ENABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_ENABLE);
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
-
- /* Set the RX early threshold */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2));
- CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY);
-
- /* Enable receiver and transmitter. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
- xl_wait(sc);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
- xl_wait(sc);
-
- /* Restore state of BMCR */
- if (mii != NULL)
- mii_mediachg(mii);
-
- /* Select window 7 for normal operations. */
- XL_SEL_WIN(7);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- timeout(xl_stats_update, sc, hz);
-
- return;
-}
-
-/*
- * Set media options.
- */
-int xl_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct xl_softc *sc;
- struct ifmedia *ifm = NULL;
- struct mii_data *mii = NULL;
-
- sc = ifp->if_softc;
-
- if (sc->xl_hasmii)
- mii = &sc->sc_mii;
- if (mii == NULL)
- ifm = &sc->ifmedia;
- else
- ifm = &mii->mii_media;
-
- switch(IFM_SUBTYPE(ifm->ifm_media)) {
- case IFM_100_FX:
- case IFM_10_FL:
- case IFM_10_2:
- case IFM_10_5:
- xl_setmode(sc, ifm->ifm_media);
- return (0);
- break;
- default:
- break;
- }
-
- if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX
- || sc->xl_media & XL_MEDIAOPT_BT4) {
- xl_init(sc);
- } else {
- xl_setmode(sc, ifm->ifm_media);
- }
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-void xl_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct xl_softc *sc;
- u_int32_t icfg;
- struct mii_data *mii = NULL;
-
- sc = ifp->if_softc;
- if (sc->xl_hasmii != 0)
- mii = &sc->sc_mii;
-
- XL_SEL_WIN(3);
- icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG) & XL_ICFG_CONNECTOR_MASK;
- icfg >>= XL_ICFG_CONNECTOR_BITS;
-
- ifmr->ifm_active = IFM_ETHER;
-
- switch(icfg) {
- case XL_XCVR_10BT:
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- break;
- case XL_XCVR_AUI:
- if (sc->xl_type == XL_TYPE_905B &&
- sc->xl_media == XL_MEDIAOPT_10FL) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_FL;
- if (CSR_READ_1(sc, XL_W3_MAC_CTRL) & XL_MACCTRL_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_FDX;
- } else
- ifmr->ifm_active = IFM_ETHER|IFM_10_5;
- break;
- case XL_XCVR_COAX:
- ifmr->ifm_active = IFM_ETHER|IFM_10_2;
- break;
- /*
- * XXX MII and BTX/AUTO should be separate cases.
- */
-
- case XL_XCVR_100BTX:
- case XL_XCVR_AUTO:
- case XL_XCVR_MII:
- if (mii != NULL) {
- mii_pollstat(mii);
- ifmr->ifm_active = mii->mii_media_active;
- ifmr->ifm_status = mii->mii_media_status;
- }
- break;
- case XL_XCVR_100BFX:
- ifmr->ifm_active = IFM_ETHER|IFM_100_FX;
- break;
- default:
- printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit, icfg);
- break;
- }
-
- return;
-}
-
-int
-xl_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct xl_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *)data;
- struct ifaddr *ifa = (struct ifaddr *)data;
- int s, error = 0;
- struct mii_data *mii = NULL;
- u_int8_t rxfilt;
-
- s = splimp();
-
- if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
- splx(s);
- return error;
- }
-
- switch(command) {
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- xl_init(sc);
- arp_ifinit(&sc->arpcom, ifa);
- break;
-#endif /* INET */
- default:
- xl_init(sc);
- break;
- }
- break;
- case SIOCSIFFLAGS:
- XL_SEL_WIN(5);
- rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
- if (ifp->if_flags & IFF_UP) {
- if (ifp->if_flags & IFF_RUNNING &&
- ifp->if_flags & IFF_PROMISC &&
- !(sc->xl_if_flags & IFF_PROMISC)) {
- rxfilt |= XL_RXFILTER_ALLFRAMES;
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_RX_SET_FILT|rxfilt);
- XL_SEL_WIN(7);
- } else if (ifp->if_flags & IFF_RUNNING &&
- !(ifp->if_flags & IFF_PROMISC) &&
- sc->xl_if_flags & IFF_PROMISC) {
- rxfilt &= ~XL_RXFILTER_ALLFRAMES;
- CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_RX_SET_FILT|rxfilt);
- XL_SEL_WIN(7);
- } else
- xl_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- xl_stop(sc);
- }
- sc->xl_if_flags = ifp->if_flags;
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- error = (command == SIOCADDMULTI) ?
- ether_addmulti(ifr, &sc->arpcom) :
- ether_delmulti(ifr, &sc->arpcom);
-
- if (error == ENETRESET) {
- /*
- * Multicast list has changed; set the hardware
- * filter accordingly.
- */
- if (sc->xl_type == XL_TYPE_905B)
- xl_setmulti_hash(sc);
- else
- xl_setmulti(sc);
- error = 0;
- }
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- if (sc->xl_hasmii != 0)
- mii = &sc->sc_mii;
- if (mii == NULL)
- error = ifmedia_ioctl(ifp, ifr,
- &sc->ifmedia, command);
- else
- error = ifmedia_ioctl(ifp, ifr,
- &mii->mii_media, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-void xl_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct xl_softc *sc;
- u_int16_t status = 0;
-
- sc = ifp->if_softc;
-
- ifp->if_oerrors++;
- XL_SEL_WIN(4);
- status = CSR_READ_2(sc, XL_W4_MEDIA_STATUS);
- printf("xl%d: watchdog timeout\n", sc->xl_unit);
-
- if (status & XL_MEDIASTAT_CARRIER)
- printf("xl%d: no carrier - transceiver cable problem?\n",
- sc->xl_unit);
- xl_txeoc(sc);
- xl_txeof(sc);
- xl_rxeof(sc);
- xl_reset(sc, 0);
- xl_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- (*ifp->if_start)(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-void xl_stop(sc)
- struct xl_softc *sc;
-{
- int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD);
- xl_wait(sc);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
- DELAY(800);
-
-#ifdef foo
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
- xl_wait(sc);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
- xl_wait(sc);
-#endif
-
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
-
- /* Stop the stats updater. */
- untimeout(xl_stats_update, sc);
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < XL_RX_LIST_CNT; i++) {
- if (sc->xl_cdata.xl_rx_chain[i].xl_mbuf != NULL) {
- m_freem(sc->xl_cdata.xl_rx_chain[i].xl_mbuf);
- sc->xl_cdata.xl_rx_chain[i].xl_mbuf = NULL;
- }
- }
- bzero((char *)&sc->xl_ldata->xl_rx_list,
- sizeof(sc->xl_ldata->xl_rx_list));
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < XL_TX_LIST_CNT; i++) {
- if (sc->xl_cdata.xl_tx_chain[i].xl_mbuf != NULL) {
- m_freem(sc->xl_cdata.xl_tx_chain[i].xl_mbuf);
- sc->xl_cdata.xl_tx_chain[i].xl_mbuf = NULL;
- }
- }
- bzero((char *)&sc->xl_ldata->xl_tx_list,
- sizeof(sc->xl_ldata->xl_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-void
-xl_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;
- 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);
-
- /*
- * Get station address from the EEPROM.
- */
- if (xl_read_eeprom(sc, (caddr_t)&enaddr, XL_EE_OEM_ADR0, 3, 1)) {
- printf("\n%s: failed to read station address\n",
- sc->sc_dev.dv_xname);
- return;
- }
- bcopy(enaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
-
- sc->xl_ldata_ptr = malloc(sizeof(struct xl_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->xl_ldata_ptr == NULL) {
- printf("%s: no memory for list buffers\n",sc->sc_dev.dv_xname);
- return;
- }
-
- sc->xl_ldata = (struct xl_list_data *)sc->xl_ldata_ptr;
-#ifdef __alpha__
- round = (u_int64_t)sc->xl_ldata_ptr & 0xf;
-#else
- round = (u_int32_t)sc->xl_ldata_ptr & 0xf;
-#endif
- roundptr = sc->xl_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->xl_ldata = (struct xl_list_data *)roundptr;
- bzero(sc->xl_ldata, sizeof(struct xl_list_data));
-
- /*
- * Figure out the card type. 3c905B adapters have the
- * 'supportsNoTxLength' bit set in the capabilities
- * word in the EEPROM.
- */
- xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
- if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
- sc->xl_type = XL_TYPE_905B;
- else
- sc->xl_type = XL_TYPE_90X;
-
- ifp->if_softc = sc;
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = xl_ioctl;
- ifp->if_output = ether_output;
- if (sc->xl_type == XL_TYPE_905B)
- ifp->if_start = xl_start_90xB;
- else
- ifp->if_start = xl_start;
- ifp->if_watchdog = xl_watchdog;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = XL_TX_LIST_CNT - 1;
- bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
-
- XL_SEL_WIN(3);
- sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT);
-
- xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0);
- sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK;
- sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS;
-
- xl_mediacheck(sc);
-
- 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,
- xl_ifmedia_upd, xl_ifmedia_sts);
- sc->xl_hasmii = 1;
- sc->sc_mii.mii_ifp = ifp;
- sc->sc_mii.mii_readreg = xl_miibus_readreg;
- 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);
-
- if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
- ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE,
- 0, NULL);
- ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
- }
- else {
- ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
- }
- ifm = &sc->sc_mii.mii_media;
- }
- else {
- ifmedia_init(&sc->ifmedia, 0, xl_ifmedia_upd, xl_ifmedia_sts);
- sc->xl_hasmii = 0;
- ifm = &sc->ifmedia;
- }
-
- /*
- * Sanity check. If the user has selected "auto" and this isn't
- * a 10/100 card of some kind, we need to force the transceiver
- * type to something sane.
- */
- if (sc->xl_xcvr == XL_XCVR_AUTO) {
- xl_choose_xcvr(sc, 0);
- xl_reset(sc, 0);
- }
-
- if (sc->xl_media & XL_MEDIAOPT_BT) {
- ifmedia_add(ifm, IFM_ETHER|IFM_10_T, 0, NULL);
- ifmedia_add(ifm, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- }
-
- if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) {
- /*
- * Check for a 10baseFL board in disguise.
- */
- if (sc->xl_type == XL_TYPE_905B &&
- sc->xl_media == XL_MEDIAOPT_10FL) {
- ifmedia_add(ifm, IFM_ETHER|IFM_10_FL, 0, NULL);
- ifmedia_add(ifm, IFM_ETHER|IFM_10_FL|IFM_HDX,
- 0, NULL);
- if (sc->xl_caps & XL_CAPS_FULL_DUPLEX)
- ifmedia_add(ifm,
- IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
- } else {
- ifmedia_add(ifm, IFM_ETHER|IFM_10_5, 0, NULL);
- }
- }
-
- if (sc->xl_media & XL_MEDIAOPT_BNC) {
- ifmedia_add(ifm, IFM_ETHER|IFM_10_2, 0, NULL);
- }
-
- if (sc->xl_media & XL_MEDIAOPT_BFX) {
- ifp->if_baudrate = 100000000;
- ifmedia_add(ifm, IFM_ETHER|IFM_100_FX, 0, NULL);
- }
-
- /* Choose a default media. */
- switch(sc->xl_xcvr) {
- case XL_XCVR_10BT:
- media = IFM_ETHER|IFM_10_T;
- xl_setmode(sc, media);
- break;
- case XL_XCVR_AUI:
- if (sc->xl_type == XL_TYPE_905B &&
- sc->xl_media == XL_MEDIAOPT_10FL) {
- media = IFM_ETHER|IFM_10_FL;
- xl_setmode(sc, media);
- } else {
- media = IFM_ETHER|IFM_10_5;
- xl_setmode(sc, media);
- }
- break;
- case XL_XCVR_COAX:
- media = IFM_ETHER|IFM_10_2;
- xl_setmode(sc, media);
- break;
- case XL_XCVR_AUTO:
- case XL_XCVR_100BTX:
- case XL_XCVR_MII:
- /* Chosen by miibus */
- break;
- case XL_XCVR_100BFX:
- media = IFM_ETHER|IFM_100_FX;
- xl_setmode(sc, media);
- break;
- default:
- printf("xl%d: unknown XCVR type: %d\n", sc->xl_unit,
- sc->xl_xcvr);
- /*
- * This will probably be wrong, but it prevents
- * the ifmedia code from panicking.
- */
- media = IFM_ETHER | IFM_10_T;
- break;
- }
-
- if (sc->xl_hasmii == 0)
- ifmedia_set(&sc->ifmedia, media);
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
-#if NBPFILTER > 0
- bpfattach(&sc->arpcom.ac_if.if_bpf, ifp,
- DLT_EN10MB, sizeof(struct ether_header));
-#endif
- shutdownhook_establish(xl_shutdown, sc);
-}
-
-void
-xl_shutdown(v)
- void *v;
-{
- struct xl_softc *sc = (struct xl_softc *)v;
-
- xl_reset(sc, 1);
- xl_stop(sc);
-}
-
-struct cfattach xl_ca = {
- sizeof(struct xl_softc), xl_probe, xl_attach,
-};
-
-struct cfdriver xl_cd = {
- 0, "xl", DV_IFNET
-};
--- /dev/null
+/* $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,
+};
+++ /dev/null
-/* $OpenBSD: if_xlreg.h,v 1.17 1999/12/16 22:15:45 deraadt Exp $ */
-
-/*
- * Copyright (c) 1997, 1998
- * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
- * 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: if_xlreg.h,v 1.17 1999/05/30 18:09:17 wpaul Exp $
- */
-
-#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 */
-#define XL_EE_EWEN 0x0030 /* erase, no data needed */
-#define XL_EE_BUSY 0x8000
-
-#define XL_EE_EADDR0 0x00 /* station address, first word */
-#define XL_EE_EADDR1 0x01 /* station address, next word, */
-#define XL_EE_EADDR2 0x02 /* station address, last word */
-#define XL_EE_PRODID 0x03 /* product ID code */
-#define XL_EE_MDATA_DATE 0x04 /* manufacturing data, date */
-#define XL_EE_MDATA_DIV 0x05 /* manufacturing data, division */
-#define XL_EE_MDATA_PCODE 0x06 /* manufacturing data, product code */
-#define XL_EE_MFG_ID 0x07
-#define XL_EE_PCI_PARM 0x08
-#define XL_EE_ROM_ONFO 0x09
-#define XL_EE_OEM_ADR0 0x0A
-#define XL_EE_OEM_ADR1 0x0B
-#define XL_EE_OEM_ADR2 0x0C
-#define XL_EE_SOFTINFO1 0x0D
-#define XL_EE_COMPAT 0x0E
-#define XL_EE_SOFTINFO2 0x0F
-#define XL_EE_CAPS 0x10 /* capabilities word */
-#define XL_EE_RSVD0 0x11
-#define XL_EE_ICFG_0 0x12
-#define XL_EE_ICFG_1 0x13
-#define XL_EE_RSVD1 0x14
-#define XL_EE_SOFTINFO3 0x15
-#define XL_EE_RSVD_2 0x16
-
-/*
- * Bits in the capabilities word
- */
-#define XL_CAPS_PNP 0x0001
-#define XL_CAPS_FULL_DUPLEX 0x0002
-#define XL_CAPS_LARGE_PKTS 0x0004
-#define XL_CAPS_SLAVE_DMA 0x0008
-#define XL_CAPS_SECOND_DMA 0x0010
-#define XL_CAPS_FULL_BM 0x0020
-#define XL_CAPS_FRAG_BM 0x0040
-#define XL_CAPS_CRC_PASSTHRU 0x0080
-#define XL_CAPS_TXDONE 0x0100
-#define XL_CAPS_NO_TXLENGTH 0x0200
-#define XL_CAPS_RX_REPEAT 0x0400
-#define XL_CAPS_SNOOPING 0x0800
-#define XL_CAPS_100MBPS 0x1000
-#define XL_CAPS_PWRMGMT 0x2000
-
-#define XL_PACKET_SIZE 1536
-
-/*
- * Register layouts.
- */
-#define XL_COMMAND 0x0E
-#define XL_STATUS 0x0E
-
-#define XL_TX_STATUS 0x1B
-#define XL_TX_FREE 0x1C
-#define XL_DMACTL 0x20
-#define XL_DOWNLIST_PTR 0x24
-#define XL_DOWN_POLL 0x2D /* 3c90xB only */
-#define XL_TX_FREETHRESH 0x2F
-#define XL_UPLIST_PTR 0x38
-#define XL_UPLIST_STATUS 0x30
-#define XL_UP_POLL 0x3D /* 3c90xB only */
-
-#define XL_PKTSTAT_UP_STALLED 0x00002000
-#define XL_PKTSTAT_UP_ERROR 0x00004000
-#define XL_PKTSTAT_UP_CMPLT 0x00008000
-
-#define XL_DMACTL_DN_CMPLT_REQ 0x00000002
-#define XL_DMACTL_DOWN_STALLED 0x00000004
-#define XL_DMACTL_UP_CMPLT 0x00000008
-#define XL_DMACTL_DOWN_CMPLT 0x00000010
-#define XL_DMACTL_UP_RX_EARLY 0x00000020
-#define XL_DMACTL_ARM_COUNTDOWN 0x00000040
-#define XL_DMACTL_DOWN_INPROG 0x00000080
-#define XL_DMACTL_COUNTER_SPEED 0x00000100
-#define XL_DMACTL_DOWNDOWN_MODE 0x00000200
-#define XL_DMACTL_TARGET_ABORT 0x40000000
-#define XL_DMACTL_MASTER_ABORT 0x80000000
-
-/*
- * Command codes. Some command codes require that we wait for
- * the CMD_BUSY flag to clear. Those codes are marked as 'mustwait.'
- */
-#define XL_CMD_RESET 0x0000 /* mustwait */
-#define XL_CMD_WINSEL 0x0800
-#define XL_CMD_COAX_START 0x1000
-#define XL_CMD_RX_DISABLE 0x1800
-#define XL_CMD_RX_ENABLE 0x2000
-#define XL_CMD_RX_RESET 0x2800 /* mustwait */
-#define XL_CMD_UP_STALL 0x3000 /* mustwait */
-#define XL_CMD_UP_UNSTALL 0x3001
-#define XL_CMD_DOWN_STALL 0x3002 /* mustwait */
-#define XL_CMD_DOWN_UNSTALL 0x3003
-#define XL_CMD_RX_DISCARD 0x4000
-#define XL_CMD_TX_ENABLE 0x4800
-#define XL_CMD_TX_DISABLE 0x5000
-#define XL_CMD_TX_RESET 0x5800 /* mustwait */
-#define XL_CMD_INTR_FAKE 0x6000
-#define XL_CMD_INTR_ACK 0x6800
-#define XL_CMD_INTR_ENB 0x7000
-#define XL_CMD_STAT_ENB 0x7800
-#define XL_CMD_RX_SET_FILT 0x8000
-#define XL_CMD_RX_SET_THRESH 0x8800
-#define XL_CMD_TX_SET_THRESH 0x9000
-#define XL_CMD_TX_SET_START 0x9800
-#define XL_CMD_DMA_UP 0xA000
-#define XL_CMD_DMA_STOP 0xA001
-#define XL_CMD_STATS_ENABLE 0xA800
-#define XL_CMD_STATS_DISABLE 0xB000
-#define XL_CMD_COAX_STOP 0xB800
-
-#define XL_CMD_SET_TX_RECLAIM 0xC000 /* 3c905B only */
-#define XL_CMD_RX_SET_HASH 0xC800 /* 3c905B only */
-
-#define XL_HASH_SET 0x0400
-#define XL_HASHFILT_SIZE 256
-
-/*
- * status codes
- * Note that bits 15 to 13 indicate the currently visible register window
- * which may be anything from 0 to 7.
- */
-#define XL_STAT_INTLATCH 0x0001 /* 0 */
-#define XL_STAT_ADFAIL 0x0002 /* 1 */
-#define XL_STAT_TX_COMPLETE 0x0004 /* 2 */
-#define XL_STAT_TX_AVAIL 0x0008 /* 3 first generation */
-#define XL_STAT_RX_COMPLETE 0x0010 /* 4 */
-#define XL_STAT_RX_EARLY 0x0020 /* 5 */
-#define XL_STAT_INTREQ 0x0040 /* 6 */
-#define XL_STAT_STATSOFLOW 0x0080 /* 7 */
-#define XL_STAT_DMADONE 0x0100 /* 8 first generation */
-#define XL_STAT_LINKSTAT 0x0100 /* 8 3c509B */
-#define XL_STAT_DOWN_COMPLETE 0x0200 /* 9 */
-#define XL_STAT_UP_COMPLETE 0x0400 /* 10 */
-#define XL_STAT_DMABUSY 0x0800 /* 11 first generation */
-#define XL_STAT_CMDBUSY 0x1000 /* 12 */
-
-/*
- * Interrupts we normally want enabled.
- */
-#define XL_INTRS \
- (XL_STAT_UP_COMPLETE|XL_STAT_STATSOFLOW|XL_STAT_ADFAIL| \
- XL_STAT_DOWN_COMPLETE|XL_STAT_TX_COMPLETE|XL_STAT_INTLATCH)
-
-/*
- * Window 0 registers
- */
-#define XL_W0_EE_DATA 0x0C
-#define XL_W0_EE_CMD 0x0A
-#define XL_W0_RSRC_CFG 0x08
-#define XL_W0_ADDR_CFG 0x06
-#define XL_W0_CFG_CTRL 0x04
-
-#define XL_W0_PROD_ID 0x02
-#define XL_W0_MFG_ID 0x00
-
-/*
- * Window 1
- */
-
-#define XL_W1_TX_FIFO 0x10
-
-#define XL_W1_FREE_TX 0x0C
-#define XL_W1_TX_STATUS 0x0B
-#define XL_W1_TX_TIMER 0x0A
-#define XL_W1_RX_STATUS 0x08
-#define XL_W1_RX_FIFO 0x00
-
-/*
- * RX status codes
- */
-#define XL_RXSTATUS_OVERRUN 0x01
-#define XL_RXSTATUS_RUNT 0x02
-#define XL_RXSTATUS_ALIGN 0x04
-#define XL_RXSTATUS_CRC 0x08
-#define XL_RXSTATUS_OVERSIZE 0x10
-#define XL_RXSTATUS_DRIBBLE 0x20
-
-/*
- * TX status codes
- */
-#define XL_TXSTATUS_RECLAIM 0x02 /* 3c905B only */
-#define XL_TXSTATUS_OVERFLOW 0x04
-#define XL_TXSTATUS_MAXCOLS 0x08
-#define XL_TXSTATUS_UNDERRUN 0x10
-#define XL_TXSTATUS_JABBER 0x20
-#define XL_TXSTATUS_INTREQ 0x40
-#define XL_TXSTATUS_COMPLETE 0x80
-
-/*
- * Window 2
- */
-#define XL_W2_RESET_OPTIONS 0x0C /* 3c905B only */
-#define XL_W2_STATION_MASK_HI 0x0A
-#define XL_W2_STATION_MASK_MID 0x08
-#define XL_W2_STATION_MASK_LO 0x06
-#define XL_W2_STATION_ADDR_HI 0x04
-#define XL_W2_STATION_ADDR_MID 0x02
-#define XL_W2_STATION_ADDR_LO 0x00
-
-#define XL_RESETOPT_FEATUREMASK 0x0001|0x0002|0x004
-#define XL_RESETOPT_D3RESETDIS 0x0008
-#define XL_RESETOPT_DISADVFD 0x0010
-#define XL_RESETOPT_DISADV100 0x0020
-#define XL_RESETOPT_DISAUTONEG 0x0040
-#define XL_RESETOPT_DEBUGMODE 0x0080
-#define XL_RESETOPT_FASTAUTO 0x0100
-#define XL_RESETOPT_FASTEE 0x0200
-#define XL_RESETOPT_FORCEDCONF 0x0400
-#define XL_RESETOPT_TESTPDTPDR 0x0800
-#define XL_RESETOPT_TEST100TX 0x1000
-#define XL_RESETOPT_TEST100RX 0x2000
-
-/*
- * Window 3 (fifo management)
- */
-#define XL_W3_INTERNAL_CFG 0x00
-#define XL_W3_RESET_OPT 0x08
-#define XL_W3_FREE_TX 0x0C
-#define XL_W3_FREE_RX 0x0A
-#define XL_W3_MAC_CTRL 0x06
-
-#define XL_ICFG_CONNECTOR_MASK 0x00F00000
-#define XL_ICFG_CONNECTOR_BITS 20
-
-#define XL_ICFG_RAMSIZE_MASK 0x00000007
-#define XL_ICFG_RAMWIDTH 0x00000008
-#define XL_ICFG_ROMSIZE_MASK (0x00000040|0x00000080)
-#define XL_ICFG_DISABLE_BASSD 0x00000100
-#define XL_ICFG_RAMLOC 0x00000200
-#define XL_ICFG_RAMPART (0x00010000|0x00020000)
-#define XL_ICFG_XCVRSEL (0x00100000|0x00200000|0x00400000)
-#define XL_ICFG_AUTOSEL 0x01000000
-
-#define XL_XCVR_10BT 0x00
-#define XL_XCVR_AUI 0x01
-#define XL_XCVR_RSVD_0 0x02
-#define XL_XCVR_COAX 0x03
-#define XL_XCVR_100BTX 0x04
-#define XL_XCVR_100BFX 0x05
-#define XL_XCVR_MII 0x06
-#define XL_XCVR_RSVD_1 0x07
-#define XL_XCVR_AUTO 0x08 /* 3c905B only */
-
-#define XL_MACCTRL_DEFER_EXT_END 0x0001
-#define XL_MACCTRL_DEFER_0 0x0002
-#define XL_MACCTRL_DEFER_1 0x0004
-#define XL_MACCTRL_DEFER_2 0x0008
-#define XL_MACCTRL_DEFER_3 0x0010
-#define XL_MACCTRL_DUPLEX 0x0020
-#define XL_MACCTRL_ALLOW_LARGE_PACK 0x0040
-#define XL_MACCTRL_EXTEND_AFTER_COL 0x0080 (3c905B only)
-#define XL_MACCTRL_FLOW_CONTROL_ENB 0x0100 (3c905B only)
-#define XL_MACCTRL_VLT_END 0x0200 (3c905B only)
-
-/*
- * The 'reset options' register contains power-on reset values
- * loaded from the EEPROM. This includes the supported media
- * types on the card. It is also known as the media options register.
- */
-#define XL_W3_MEDIA_OPT 0x08
-
-#define XL_MEDIAOPT_BT4 0x0001 /* MII */
-#define XL_MEDIAOPT_BTX 0x0002 /* on-chip */
-#define XL_MEDIAOPT_BFX 0x0004 /* on-chip */
-#define XL_MEDIAOPT_BT 0x0008 /* on-chip */
-#define XL_MEDIAOPT_BNC 0x0010 /* on-chip */
-#define XL_MEDIAOPT_AUI 0x0020 /* on-chip */
-#define XL_MEDIAOPT_MII 0x0040 /* MII */
-#define XL_MEDIAOPT_VCO 0x0100 /* 1st gen chip only */
-
-#define XL_MEDIAOPT_10FL 0x0100 /* 3x905B only, on-chip */
-#define XL_MEDIAOPT_MASK 0x01FF
-
-/*
- * Window 4 (diagnostics)
- */
-#define XL_W4_UPPERBYTESOK 0x0D
-#define XL_W4_BADSSD 0x0C
-#define XL_W4_MEDIA_STATUS 0x0A
-#define XL_W4_PHY_MGMT 0x08
-#define XL_W4_NET_DIAG 0x06
-#define XL_W4_FIFO_DIAG 0x04
-#define XL_W4_VCO_DIAG 0x02
-
-#define XL_W4_CTRLR_STAT 0x08
-#define XL_W4_TX_DIAG 0x00
-
-#define XL_MII_CLK 0x01
-#define XL_MII_DATA 0x02
-#define XL_MII_DIR 0x04
-
-#define XL_MEDIA_SQE 0x0008
-#define XL_MEDIA_10TP 0x00C0
-#define XL_MEDIA_LNK 0x0080
-#define XL_MEDIA_LNKBEAT 0x0800
-
-#define XL_MEDIASTAT_CRCSTRIP 0x0004
-#define XL_MEDIASTAT_SQEENB 0x0008
-#define XL_MEDIASTAT_COLDET 0x0010
-#define XL_MEDIASTAT_CARRIER 0x0020
-#define XL_MEDIASTAT_JABGUARD 0x0040
-#define XL_MEDIASTAT_LINKBEAT 0x0080
-#define XL_MEDIASTAT_JABDETECT 0x0200
-#define XL_MEDIASTAT_POLREVERS 0x0400
-#define XL_MEDIASTAT_LINKDETECT 0x0800
-#define XL_MEDIASTAT_TXINPROG 0x1000
-#define XL_MEDIASTAT_DCENB 0x4000
-#define XL_MEDIASTAT_AUIDIS 0x8000
-
-#define XL_NETDIAG_TEST_LOWVOLT 0x0001
-#define XL_NETDIAG_ASIC_REVMASK (0x0002|0x0004|0x0008|0x0010|0x0020)
-#define XL_NETDIAG_UPPER_BYTES_ENABLE 0x0040
-#define XL_NETDIAG_STATS_ENABLED 0x0080
-#define XL_NETDIAG_TX_FATALERR 0x0100
-#define XL_NETDIAG_TRANSMITTING 0x0200
-#define XL_NETDIAG_RX_ENABLED 0x0400
-#define XL_NETDIAG_TX_ENABLED 0x0800
-#define XL_NETDIAG_FIFO_LOOPBACK 0x1000
-#define XL_NETDIAG_MAC_LOOPBACK 0x2000
-#define XL_NETDIAG_ENDEC_LOOPBACK 0x4000
-#define XL_NETDIAG_EXTERNAL_LOOP 0x8000
-
-/*
- * Window 5
- */
-#define XL_W5_STAT_ENB 0x0C
-#define XL_W5_INTR_ENB 0x0A
-#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */
-#define XL_W5_RX_FILTER 0x08
-#define XL_W5_RX_EARLYTHRESH 0x06
-#define XL_W5_TX_AVAILTHRESH 0x02
-#define XL_W5_TX_STARTTHRESH 0x00
-
-/*
- * RX filter bits
- */
-#define XL_RXFILTER_INDIVIDUAL 0x01
-#define XL_RXFILTER_ALLMULTI 0x02
-#define XL_RXFILTER_BROADCAST 0x04
-#define XL_RXFILTER_ALLFRAMES 0x08
-#define XL_RXFILTER_MULTIHASH 0x10 /* 3c905B only */
-
-/*
- * Window 6 (stats)
- */
-#define XL_W6_TX_BYTES_OK 0x0C
-#define XL_W6_RX_BYTES_OK 0x0A
-#define XL_W6_UPPER_FRAMES_OK 0x09
-#define XL_W6_DEFERRED 0x08
-#define XL_W6_RX_OK 0x07
-#define XL_W6_TX_OK 0x06
-#define XL_W6_RX_OVERRUN 0x05
-#define XL_W6_COL_LATE 0x04
-#define XL_W6_COL_SINGLE 0x03
-#define XL_W6_COL_MULTIPLE 0x02
-#define XL_W6_SQE_ERRORS 0x01
-#define XL_W6_CARRIER_LOST 0x00
-
-/*
- * Window 7 (bus master control)
- */
-#define XL_W7_BM_ADDR 0x00
-#define XL_W7_BM_LEN 0x06
-#define XL_W7_BM_STATUS 0x0B
-#define XL_W7_BM_TIMEr 0x0A
-
-/*
- * bus master control registers
- */
-#define XL_BM_PKTSTAT 0x20
-#define XL_BM_DOWNLISTPTR 0x24
-#define XL_BM_FRAGADDR 0x28
-#define XL_BM_FRAGLEN 0x2C
-#define XL_BM_TXFREETHRESH 0x2F
-#define XL_BM_UPPKTSTAT 0x30
-#define XL_BM_UPLISTPTR 0x38
-
-#define XL_LAST_FRAG 0x80000000
-
-/*
- * Boomerang/Cyclone TX/RX list structure.
- * For the TX lists, bits 0 to 12 of the status word indicate
- * length.
- * This looks suspiciously like the ThunderLAN, doesn't it.
- */
-struct xl_frag {
- u_int32_t xl_addr; /* 63 addr/len pairs */
- u_int32_t xl_len;
-};
-
-struct xl_list {
- u_int32_t xl_next; /* final entry has 0 nextptr */
- u_int32_t xl_status;
- struct xl_frag xl_frag[63];
-};
-
-struct xl_list_onefrag {
- u_int32_t xl_next; /* final entry has 0 nextptr */
- u_int32_t xl_status;
- struct xl_frag xl_frag;
-};
-
-#define XL_MAXFRAGS 63
-#define XL_RX_LIST_CNT 32
-#define XL_TX_LIST_CNT 32
-#define XL_MIN_FRAMELEN 60
-#define XL_INC(x, y) (x) = (x + 1) % (y)
-
-struct xl_list_data {
- struct xl_list_onefrag xl_rx_list[XL_RX_LIST_CNT];
- struct xl_list xl_tx_list[XL_TX_LIST_CNT];
- unsigned char xl_pad[XL_MIN_FRAMELEN];
-};
-
-struct xl_chain {
- struct xl_list *xl_ptr;
- struct mbuf *xl_mbuf;
- struct xl_chain *xl_next;
- struct xl_chain *xl_prev;
- u_int32_t xl_phys;
-};
-
-struct xl_chain_onefrag {
- struct xl_list_onefrag *xl_ptr;
- struct mbuf *xl_mbuf;
- struct xl_chain_onefrag *xl_next;
-};
-
-struct xl_chain_data {
- struct xl_chain_onefrag xl_rx_chain[XL_RX_LIST_CNT];
- struct xl_chain xl_tx_chain[XL_TX_LIST_CNT];
-
- struct xl_chain_onefrag *xl_rx_head;
-
- /* 3c90x "boomerang" queuing stuff */
- struct xl_chain *xl_tx_head;
- struct xl_chain *xl_tx_tail;
- struct xl_chain *xl_tx_free;
-
- /* 3c90xB "cyclone/hurricane/tornade" stuff */
- int xl_tx_prod;
- int xl_tx_cons;
- int xl_tx_cnt;
-};
-
-#define XL_RXSTAT_LENMASK 0x00001FFF
-#define XL_RXSTAT_UP_ERROR 0x00004000
-#define XL_RXSTAT_UP_CMPLT 0x00008000
-#define XL_RXSTAT_UP_OVERRUN 0x00010000
-#define XL_RXSTAT_RUNT 0x00020000
-#define XL_RXSTAT_ALIGN 0x00040000
-#define XL_RXSTAT_CRC 0x00080000
-#define XL_RXSTAT_OVERSIZE 0x00100000
-#define XL_RXSTAT_DRIBBLE 0x00800000
-#define XL_RXSTAT_UP_OFLOW 0x01000000
-#define XL_RXSTAT_IPCKERR 0x02000000 /* 3c905B only */
-#define XL_RXSTAT_TCPCKERR 0x04000000 /* 3c905B only */
-#define XL_RXSTAT_UDPCKERR 0x08000000 /* 3c905B only */
-#define XL_RXSTAT_BUFEN 0x10000000 /* 3c905B only */
-#define XL_RXSTAT_IPCKOK 0x20000000 /* 3c905B only */
-#define XL_RXSTAT_TCPCOK 0x40000000 /* 3c905B only */
-#define XL_RXSTAT_UDPCKOK 0x80000000 /* 3c905B only */
-
-#define XL_TXSTAT_LENMASK 0x00001FFF
-#define XL_TXSTAT_CRCDIS 0x00002000
-#define XL_TXSTAT_TX_INTR 0x00008000
-#define XL_TXSTAT_DL_COMPLETE 0x00010000
-#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */
-#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */
-#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */
-#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */
-#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */
-#define XL_TXSTAT_DL_INTR 0x80000000
-
-#define XL_CAPABILITY_BM 0x20
-
-struct xl_type {
- u_int16_t xl_vid;
- u_int16_t xl_did;
- char *xl_name;
-};
-
-struct xl_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define XL_MII_STARTDELIM 0x01
-#define XL_MII_READOP 0x02
-#define XL_MII_WRITEOP 0x01
-#define XL_MII_TURNAROUND 0x02
-
-/*
- * The 3C905B adapters implement a few features that we want to
- * take advantage of, namely the multicast hash filter. With older
- * chips, you only have the option of turning on reception of all
- * multicast frames, which is kind of lame.
- *
- * We also use this to decide on a transmit strategy. For the 3c90xB
- * cards, we can use polled descriptor mode, which reduces CPU overhead.
- */
-#define XL_TYPE_905B 1
-#define XL_TYPE_90X 2
-
-struct xl_softc {
- struct device sc_dev; /* generic device structure */
- void * xl_intrhand; /* interrupt handler cookie */
- struct arpcom arpcom; /* interface info */
- struct ifmedia ifmedia; /* media info */
- mii_data_t sc_mii; /* mii bus */
- bus_space_handle_t xl_bhandle;
- bus_space_tag_t xl_btag;
- 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 */
- u_int8_t xl_type;
- u_int32_t xl_xcvr;
- u_int16_t xl_media;
- u_int16_t xl_caps;
- u_int8_t xl_stats_no_timeout;
- u_int16_t xl_tx_thresh;
- int xl_if_flags;
- caddr_t xl_ldata_ptr;
- struct xl_list_data *xl_ldata;
- struct xl_chain_data xl_cdata;
-};
-
-#define xl_rx_goodframes(x) \
- ((x.xl_upper_frames_ok & 0x03) << 8) | x.xl_rx_frames_ok
-
-#define xl_tx_goodframes(x) \
- ((x.xl_upper_frames_ok & 0x30) << 4) | x.xl_tx_frames_ok
-
-struct xl_stats {
- u_int8_t xl_carrier_lost;
- u_int8_t xl_sqe_errs;
- u_int8_t xl_tx_multi_collision;
- u_int8_t xl_tx_single_collision;
- u_int8_t xl_tx_late_collision;
- u_int8_t xl_rx_overrun;
- u_int8_t xl_tx_frames_ok;
- u_int8_t xl_rx_frames_ok;
- u_int8_t xl_tx_deferred;
- u_int8_t xl_upper_frames_ok;
- u_int16_t xl_rx_bytes_ok;
- u_int16_t xl_tx_bytes_ok;
- u_int16_t status;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->xl_btag, sc->xl_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->xl_btag, sc->xl_bhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->xl_btag, sc->xl_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->xl_btag, sc->xl_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->xl_btag, sc->xl_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->xl_btag, sc->xl_bhandle, reg)
-
-#define XL_SEL_WIN(x) \
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_WINSEL | x)
-#define XL_TIMEOUT 1000
-
-/*
- * General constants that are fun to know.
- *
- * 3Com PCI vendor ID
- */
-#define TC_VENDORID 0x10B7
-
-/*
- * 3Com chip device IDs.
- */
-#define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500
-#define TC_DEVICEID_BOOMERANG_10BT 0x9000
-#define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001
-#define TC_DEVICEID_BOOMERANG_10_100BT 0x9050
-#define TC_DEVICEID_BOOMERANG_100BT4 0x9051
-#define TC_DEVICEID_KRAKATOA_10BT 0x9004
-#define TC_DEVICEID_KRAKATOA_10BT_COMBO 0x9005
-#define TC_DEVICEID_KRAKATOA_10BT_TPC 0x9006
-#define TC_DEVICEID_CYCLONE_10FL 0x900A
-#define TC_DEVICEID_HURRICANE_10_100BT 0x9055
-#define TC_DEVICEID_CYCLONE_10_100BT4 0x9056
-#define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058
-#define TC_DEVICEID_CYCLONE_10_100FX 0x905A
-#define TC_DEVICEID_TORNADO_10_100BT 0x9200
-#define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800
-#define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805
-#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers. Note: some are only available on
- * the 3c905B, in particular those that related to power management.
- */
-
-#define XL_PCI_VENDOR_ID 0x00
-#define XL_PCI_DEVICE_ID 0x02
-#define XL_PCI_COMMAND 0x04
-#define XL_PCI_STATUS 0x06
-#define XL_PCI_CLASSCODE 0x09
-#define XL_PCI_LATENCY_TIMER 0x0D
-#define XL_PCI_HEADER_TYPE 0x0E
-#define XL_PCI_LOIO 0x10
-#define XL_PCI_LOMEM 0x14
-#define XL_PCI_BIOSROM 0x30
-#define XL_PCI_INTLINE 0x3C
-#define XL_PCI_INTPIN 0x3D
-#define XL_PCI_MINGNT 0x3E
-#define XL_PCI_MINLAT 0x0F
-#define XL_PCI_RESETOPT 0x48
-#define XL_PCI_EEPROM_DATA 0x4C
-
-/* 3c905B-only registers */
-#define XL_PCI_CAPID 0xDC /* 8 bits */
-#define XL_PCI_NEXTPTR 0xDD /* 8 bits */
-#define XL_PCI_PWRMGMTCAP 0xDE /* 16 bits */
-#define XL_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
-
-#define XL_PSTATE_MASK 0x0003
-#define XL_PSTATE_D0 0x0000
-#define XL_PSTATE_D1 0x0002
-#define XL_PSTATE_D2 0x0002
-#define XL_PSTATE_D3 0x0003
-#define XL_PME_EN 0x0010
-#define XL_PME_STATUS 0x8000
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
-
-#ifndef ETHER_ALIGN
-#define ETHER_ALIGN 2
-#endif
--- /dev/null
+/* $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);
+ }
+}
--- /dev/null
+/* $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_ */
--- /dev/null
+/* $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_ */
-# $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.
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
-/* $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 $ */
/*
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);
}
-/* $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.
#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
/* 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. */
((*(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 */
-# $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.
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 \