From 4cccaf7b6e534b99f6c07b76048acfa90e4d8495 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Fri, 11 Sep 1998 10:47:16 +0000 Subject: PCMCIA code ported from NetBSD. Support for aic, ep, pccom and sm. --- sys/dev/pcmcia/if_ep_pcmcia.c | 422 +++++++++++++++++++++++++++++------------- 1 file changed, 294 insertions(+), 128 deletions(-) (limited to 'sys/dev/pcmcia/if_ep_pcmcia.c') diff --git a/sys/dev/pcmcia/if_ep_pcmcia.c b/sys/dev/pcmcia/if_ep_pcmcia.c index aeaa0937ad3..2f43037a872 100644 --- a/sys/dev/pcmcia/if_ep_pcmcia.c +++ b/sys/dev/pcmcia/if_ep_pcmcia.c @@ -1,9 +1,14 @@ -/* $OpenBSD: if_ep_pcmcia.c,v 1.8 1998/03/17 00:00:57 deraadt Exp $ */ +/* $OpenBSD: if_ep_pcmcia.c,v 1.9 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $ */ -/* - * Copyright (c) 1994 Herb Peyerl +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,8 +19,40 @@ * 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 Herb Peyerl. - * 4. The name of Herb Peyerl may not be used to endorse or promote products + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. 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. + */ + +/* + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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 @@ -33,6 +70,7 @@ #include "bpfilter.h" #include +#include #include #include #include @@ -40,10 +78,8 @@ #include #include #include -#include #include -#include #include #include #include @@ -56,6 +92,11 @@ #include #endif +#ifdef NS +#include +#include +#endif + #if NBPFILTER > 0 #include #include @@ -63,164 +104,289 @@ #include #include +#include #include #include -#include /*XXX*/ +#include #include +#include + +int ep_pcmcia_match __P((struct device *, void *, void *)); +void ep_pcmcia_attach __P((struct device *, struct device *, void *)); -int ep_pcmcia_match __P((struct device *, void *, void *)); -void ep_pcmcia_attach __P((struct device *, struct device *, void *)); -int ep_pcmcia_detach __P((struct device *)); +int ep_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); +int ep_pcmcia_enable __P((struct ep_softc *)); +void ep_pcmcia_disable __P((struct ep_softc *)); -int ep_pcmcia_isasetup __P((struct device *, void *, void *, - struct pcmcia_link *)); -int epmod __P((struct pcmcia_link *, struct device *, struct pcmcia_conf *, - struct cfdata *)); -int ep_remove __P((struct pcmcia_link *, struct device *)); +int ep_pcmcia_enable1 __P((struct ep_softc *)); +void ep_pcmcia_disable1 __P((struct ep_softc *)); + +struct ep_pcmcia_softc { + struct ep_softc sc_ep; /* real "ep" softc */ + + /* PCMCIA-specific goo */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ +}; struct cfattach ep_pcmcia_ca = { - sizeof(struct ep_softc), ep_pcmcia_match, ep_pcmcia_attach, - ep_pcmcia_detach + sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach +}; + +struct ep_pcmcia_product { + u_int32_t epp_product; /* PCMCIA product ID */ + u_short epp_chipset; /* 3Com chipset used */ + int epp_flags; /* initial softc flags */ + int epp_expfunc; /* expected function */ + const char *epp_name; /* device name */ +} ep_pcmcia_products[] = { + { PCMCIA_PRODUCT_3COM_3C562, EP_CHIPSET_3C509, + 0, 0, + PCMCIA_STR_3COM_3C562 }, + { PCMCIA_PRODUCT_3COM_3C589, EP_CHIPSET_3C509, + 0, 0, + PCMCIA_STR_3COM_3C589 }, + + { PCMCIA_PRODUCT_3COM_3C574, EP_CHIPSET_BOOMERANG, + EP_FLAGS_MII, 0, + PCMCIA_STR_3COM_3C574 }, + + { 0, 0, + 0, 0, + NULL }, }; -/* additional setup needed for pcmcia devices */ +struct ep_pcmcia_product *ep_pcmcia_lookup __P((struct pcmcia_attach_args *)); + +struct ep_pcmcia_product * +ep_pcmcia_lookup(pa) + struct pcmcia_attach_args *pa; +{ + struct ep_pcmcia_product *epp; + + for (epp = ep_pcmcia_products; epp->epp_name != NULL; epp++) + if (pa->product == epp->epp_product && + pa->pf->number == epp->epp_expfunc) + return (epp); + + return (NULL); +} + int -ep_pcmcia_isasetup(parent, match, aux, pc_link) - struct device *parent; - void *match; - void *aux; - struct pcmcia_link *pc_link; +ep_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; { - struct ep_softc *sc = (void *) match; - struct isa_attach_args *ia = aux; - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - extern int ifqmaxlen; - - bus_space_write_2(iot, ioh, EP_COMMAND, WINDOW_SELECT | 0); - bus_space_write_2(iot, ioh, EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); - bus_space_write_2(iot, ioh, EP_W0_RESOURCE_CFG, 0x3f00); - - /* - * ok til here. Now try to figure out which link we have. - * try coax first... - */ -#ifdef EP_COAX_DEFAULT - bus_space_write_2(iot, ioh, EP_W0_ADDRESS_CFG, 0xC000); -#else - /* COAX as default is reported to be a problem */ - bus_space_write_2(iot, ioh, EP_W0_ADDRESS_CFG, 0x0000); -#endif - ifp->if_snd.ifq_maxlen = ifqmaxlen; + struct pcmcia_attach_args *pa = aux; + + if (pa->manufacturer != PCMCIA_VENDOR_3COM) + return (0); - ia->ia_iosize = 0x10; - ia->ia_msize = 0; + if (ep_pcmcia_lookup(pa) != NULL) + return (1); - sc->bustype = EP_BUS_PCMCIA; - sc->pcmcia_flags = (pc_link->flags & PCMCIA_REATTACH) ? EP_REATTACH:0; - return 1; + return (0); } -/* modify config entry */ int -epmod(pc_link, self, pc_cf, cf) - struct pcmcia_link *pc_link; - struct device *self; - struct pcmcia_conf *pc_cf; - struct cfdata *cf; +ep_pcmcia_enable(sc) + struct ep_softc *sc; { - int err; -/* struct pcmciadevs *dev = pc_link->device;*/ -/* struct ep_softc *sc = (void *) self;*/ - - if ((err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self, pc_cf, - cf)) != 0) { - printf("bus_config failed %d\n", err); - return err; - } + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; - if (pc_cf->io[0].len > 0x10) - pc_cf->io[0].len = 0x10; -#if 0 - pc_cf->cfgtype = DOSRESET; -#endif - pc_cf->cfgtype = 1; + /* establish the interrupt. */ + sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc); + if (sc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + return (1); + } - return 0; + return (ep_pcmcia_enable1(sc)); } int -ep_remove(pc_link, self) - struct pcmcia_link *pc_link; - struct device *self; +ep_pcmcia_enable1(sc) + struct ep_softc *sc; { - struct ep_softc *sc = (void *) self; - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - - if_down(ifp); - epstop(sc); - ifp->if_flags &= ~(IFF_RUNNING | IFF_UP); - sc->pcmcia_flags = EP_ABSENT; - return PCMCIA_BUS_UNCONFIG(pc_link->adapter, pc_link); + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; + int ret; + + if ((ret = pcmcia_function_enable(pf))) + return (ret); + + if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) { + int reg; + + /* turn off the serial-disable bit */ + + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + if (reg & 0x08) { + reg &= ~0x08; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); + } + + } + + return (ret); } -static struct pcmcia_3com { - struct pcmcia_device pcd; -} pcmcia_3com = { - { - "PCMCIA 3COM 3C589", epmod, - ep_pcmcia_isasetup, NULL, ep_remove - }, -}; +void +ep_pcmcia_disable(sc) + struct ep_softc *sc; +{ + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; -struct pcmciadevs pcmcia_ep_devs[] = { - { - "ep", 0, "3Com Corporation", "3C589", - NULL, NULL, - (void *) -1, (void *) &pcmcia_3com - }, -}; + ep_pcmcia_disable1(sc); + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); +} -int -ep_pcmcia_match(parent, match, aux) - struct device *parent; - void *match, *aux; +void +ep_pcmcia_disable1(sc) + struct ep_softc *sc; { - return pcmcia_slave_match(parent, match, aux, pcmcia_ep_devs, - sizeof(pcmcia_ep_devs)/sizeof(pcmcia_ep_devs[0])); + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + + pcmcia_function_disable(psc->sc_pf); } void ep_pcmcia_attach(parent, self, aux) - struct device *parent, *self; - void *aux; + struct device *parent, *self; + void *aux; { - struct ep_softc *sc = (void *)self; - struct isa_attach_args *ia = aux; - bus_space_tag_t iot = ia->ia_iot; - bus_space_handle_t ioh; - - if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) - panic("ep_isa_attach: can't map i/o space"); - - sc->sc_iot = iot; - sc->sc_ioh = ioh; - - epconfig(sc, EP_CHIPSET_3C509); - sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, - IST_EDGE, IPL_NET, epintr, sc, sc->sc_dev.dv_xname); + struct ep_pcmcia_softc *psc = (void *) self; + struct ep_softc *sc = &psc->sc_ep; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + struct ep_pcmcia_product *epp; + u_int8_t myla[ETHER_ADDR_LEN]; + u_int8_t *enaddr = NULL; + int i; + + psc->sc_pf = pa->pf; + cfe = pa->pf->cfe_head.sqh_first; + + /* Enable the card. */ + pcmcia_function_init(pa->pf, cfe); + if (ep_pcmcia_enable1(sc)) + printf(": function enable failed\n"); + +#ifdef notyet + sc->enabled = 1; +#endif + + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + + if (cfe->num_iospace != 1) + printf(": unexpected number of I/O spaces %d should be 1\n", + cfe->num_iospace); + + if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { + bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize); + + for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) { + /* + * the 3c562 can only use 0x??00-0x??7f + * according to the Linux driver + */ + if (i & 0x80) + continue; + if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length, + 0, &psc->sc_pcioh) == 0) + break; + } + if (i >= maxaddr) { + printf(": can't allocate i/o space\n"); + return; + } + } else { + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + } + + sc->sc_iot = psc->sc_pcioh.iot; + sc->sc_ioh = psc->sc_pcioh.ioh; + + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; + } + + switch (pa->product) { + case PCMCIA_PRODUCT_3COM_3C562: + /* + * 3c562a-c use this; 3c562d does it in the regular way. + * we might want to check the revision and produce a warning + * in the future. + */ + /* FALLTHROUGH */ + case PCMCIA_PRODUCT_3COM_3C574: + /* + * Apparently, some 3c574s do it this way, as well. + */ + if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla)) + enaddr = myla; + break; + } + + sc->bustype = EP_BUS_PCMCIA; + + epp = ep_pcmcia_lookup(pa); + if (epp == NULL) + panic("ep_pcmcia_attach: impossible"); + + printf(": %s\n", epp->epp_name); + +#ifdef notyet + sc->enable = ep_pcmcia_enable; + sc->disable = ep_pcmcia_disable; +#endif + + epconfig(sc, epp->epp_chipset, enaddr); + + /* establish the interrupt. */ + sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc); + if (sc->sc_ih == NULL) + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + +#ifdef notyet + sc->enabled = 0; + + ep_pcmcia_disable1(sc); +#endif } -/* - * No detach; network devices are too well linked into the rest of the - * kernel. - */ int -ep_pcmcia_detach(self) - struct device *self; +ep_pcmcia_get_enaddr(tuple, arg) + struct pcmcia_tuple *tuple; + void *arg; { - return EBUSY; + u_int8_t *myla = arg; + int i; + + /* this is 3c562a-c magic */ + if (tuple->code == 0x88) { + if (tuple->length < ETHER_ADDR_LEN) + return (0); + + for (i = 0; i < ETHER_ADDR_LEN; i += 2) { + myla[i] = pcmcia_tuple_read_1(tuple, i + 1); + myla[i + 1] = pcmcia_tuple_read_1(tuple, i); + } + + return (1); + } + return (0); } -- cgit v1.2.3