diff options
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 \ |