summaryrefslogtreecommitdiff
path: root/sys/dev/pcmcia/if_ep_pcmcia.c
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>1998-09-11 10:47:16 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>1998-09-11 10:47:16 +0000
commit4cccaf7b6e534b99f6c07b76048acfa90e4d8495 (patch)
tree9485f874b3237996416ecf4fa4d21e3a5c93c57c /sys/dev/pcmcia/if_ep_pcmcia.c
parent27d7305f5dcc8a0f7154c2543c83537e60e654a9 (diff)
PCMCIA code ported from NetBSD.
Support for aic, ep, pccom and sm.
Diffstat (limited to 'sys/dev/pcmcia/if_ep_pcmcia.c')
-rw-r--r--sys/dev/pcmcia/if_ep_pcmcia.c422
1 files changed, 294 insertions, 128 deletions
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 <hpeyerl@novatel.ca>
+/*-
+ * 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 <sys/param.h>
+#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
@@ -40,10 +78,8 @@
#include <sys/syslog.h>
#include <sys/select.h>
#include <sys/device.h>
-#include <sys/systm.h>
#include <net/if.h>
-#include <net/netisr.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/netisr.h>
@@ -56,6 +92,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
@@ -63,164 +104,289 @@
#include <machine/cpu.h>
#include <machine/bus.h>
+#include <machine/intr.h>
#include <dev/ic/elink3var.h>
#include <dev/ic/elink3reg.h>
-#include <dev/isa/isavar.h> /*XXX*/
+#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciadevs.h>
+
+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);
}