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