summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/eisa/files.eisa9
-rw-r--r--sys/dev/eisa/if_ep_eisa.c171
-rw-r--r--sys/dev/ic/elink3.c (renamed from sys/dev/isa/if_ep.c)533
-rw-r--r--sys/dev/ic/elink3reg.h (renamed from sys/dev/isa/if_epreg.h)12
-rw-r--r--sys/dev/ic/elink3var.h61
-rw-r--r--sys/dev/isa/files.isa13
-rw-r--r--sys/dev/isa/if_ep_isa.c216
-rw-r--r--sys/dev/pci/files.pci9
-rw-r--r--sys/dev/pci/if_ep_pci.c188
9 files changed, 671 insertions, 541 deletions
diff --git a/sys/dev/eisa/files.eisa b/sys/dev/eisa/files.eisa
index cc0b5443475..c15670bbcf7 100644
--- a/sys/dev/eisa/files.eisa
+++ b/sys/dev/eisa/files.eisa
@@ -1,5 +1,5 @@
-# $OpenBSD: files.eisa,v 1.3 1996/04/21 22:20:50 deraadt Exp $
-# $NetBSD: files.eisa,v 1.7 1996/03/17 00:47:21 thorpej Exp $
+# $OpenBSD: files.eisa,v 1.4 1996/05/02 13:38:03 deraadt Exp $
+# $NetBSD: files.eisa,v 1.8 1996/04/25 02:16:39 thorpej Exp $
#
# Config.new file and device description for machine-independent EISA code.
# Included by ports that need it. Requires that the SCSI files be
@@ -13,3 +13,8 @@ file dev/eisa/eisa.c eisa needs-flag
device ahb: scsi
attach ahb at eisa
file dev/eisa/aha1742.c ahb
+
+# 3Com 3c579 and 3c509 masquerading as EISA Ethernet Controllers
+# device declaration in sys/conf/files
+attach ep at eisa with ep_eisa
+file dev/eisa/if_ep_eisa.c ep_eisa
diff --git a/sys/dev/eisa/if_ep_eisa.c b/sys/dev/eisa/if_ep_eisa.c
new file mode 100644
index 00000000000..150426bd2d7
--- /dev/null
+++ b/sys/dev/eisa/if_ep_eisa.c
@@ -0,0 +1,171 @@
+/* $NetBSD: if_ep_eisa.c,v 1.1 1996/04/25 02:16:40 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
+ * 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 Herb Peyerl.
+ * 4. The name of Herb Peyerl 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 "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.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
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/pio.h>
+
+#include <dev/ic/elink3var.h>
+#include <dev/ic/elink3reg.h>
+
+#include <dev/eisa/eisareg.h>
+#include <dev/eisa/eisavar.h>
+#include <dev/eisa/eisadevs.h>
+
+int ep_eisa_match __P((struct device *, void *, void *));
+void ep_eisa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach ep_eisa_ca = {
+ sizeof(struct ep_softc), ep_eisa_match, ep_eisa_attach
+};
+
+/* XXX move these somewhere else */
+#define EISA_CONTROL 0x0c84
+#define EISA_RESET 0x04
+#define EISA_ERROR 0x02
+#define EISA_ENABLE 0x01
+
+int
+ep_eisa_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+ struct eisa_attach_args *ea = aux;
+
+ /* must match one of our known ID strings */
+ if (strcmp(ea->ea_idstring, "TCM5091") &&
+ strcmp(ea->ea_idstring, "TCM5092") &&
+ strcmp(ea->ea_idstring, "TCM5093"))
+ return (0);
+
+ return (1);
+}
+
+void
+ep_eisa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ep_softc *sc = (void *)self;
+ struct eisa_attach_args *ea = aux;
+ int iobase, irq, k;
+ u_short conn = 0;
+ eisa_chipset_tag_t ec = ea->ea_ec;
+ eisa_intr_handle_t ih;
+ const char *model, *intrstr;
+
+ sc->ep_iobase = iobase = EISA_SLOT_ADDR(ea->ea_slot);
+ sc->bustype = EP_BUS_EISA;
+
+ /* Reset card. */
+ outb(iobase + EISA_CONTROL, EISA_ENABLE | EISA_RESET);
+ delay(10);
+ outb(iobase + EISA_CONTROL, EISA_ENABLE);
+ /* Wait for reset? */
+ delay(1000);
+
+ /* XXX What is this doing?! */
+ k = inw(iobase + EP_W0_ADDRESS_CFG);
+ k = (k & 0x1f) * 0x10 + 0x200;
+
+ /* Read the IRQ from the card. */
+ irq = inw(iobase + EP_W0_RESOURCE_CFG) >> 12;
+
+ GO_WINDOW(0);
+ conn = inw(iobase + EP_W0_CONFIG_CTRL);
+
+ if (strcmp(ea->ea_idstring, "TCM5091") == 0)
+ model = EISA_PRODUCT_TCM5091;
+ else if (strcmp(ea->ea_idstring, "TCM5092") == 0)
+ model = EISA_PRODUCT_TCM5092;
+ else if (strcmp(ea->ea_idstring, "TCM5093") == 0)
+ model = EISA_PRODUCT_TCM5093;
+ else
+ model = "unknown model!";
+ printf(": %s\n", model);
+
+ if (eisa_intr_map(ec, irq, &ih)) {
+ printf("%s: couldn't map interrupt (%d)\n",
+ sc->sc_dev.dv_xname, irq);
+ return;
+ }
+ intrstr = eisa_intr_string(ec, ih);
+ sc->sc_ih = eisa_intr_establish(ec, ih, IST_EDGE, IPL_NET,
+ epintr, 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;
+ }
+ if (intrstr != NULL)
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname,
+ intrstr);
+
+ epconfig(sc, conn);
+}
diff --git a/sys/dev/isa/if_ep.c b/sys/dev/ic/elink3.c
index f9eab4b8368..783ad4b1f39 100644
--- a/sys/dev/isa/if_ep.c
+++ b/sys/dev/ic/elink3.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: if_ep.c,v 1.12 1996/04/29 14:16:41 hvozda Exp $ */
-/* $NetBSD: if_ep.c,v 1.90 1996/04/11 22:29:15 cgd Exp $ */
+/* $NetBSD: elink3.c,v 1.1 1996/04/25 02:17:34 thorpej Exp $ */
/*
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
@@ -31,9 +30,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "pcmcia.h"
#include "bpfilter.h"
-#include "ep.h"
#include <sys/param.h>
#include <sys/mbuf.h>
@@ -43,7 +40,6 @@
#include <sys/syslog.h>
#include <sys/select.h>
#include <sys/device.h>
-#include <sys/systm.h>
#include <net/if.h>
#include <net/netisr.h>
@@ -69,81 +65,21 @@
#include <net/bpfdesc.h>
#endif
-#include "pci.h"
-
#include <machine/cpu.h>
#include <machine/pio.h>
-#include <dev/isa/isavar.h>
-#include <dev/isa/if_epreg.h>
-#include <dev/isa/elink.h>
-
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcidevs.h>
-
-/* PCI constants */
-#define PCI_VENDORID(x) ((x) & 0xFFFF)
-#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
-#define PCI_CONN 0x48 /* Connector type */
-#define PCI_CBMA 0x10 /* Configuration Base Memory Address */
-
+#include <dev/ic/elink3var.h>
+#include <dev/ic/elink3reg.h>
#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518
#define ETHER_ADDR_LEN 6
-/*
- * Ethernet software status per interface.
- */
-struct ep_softc {
- struct device sc_dev;
- void *sc_ih;
-
- struct arpcom sc_arpcom; /* Ethernet common part */
- int ep_iobase; /* i/o bus address */
- char ep_connectors; /* Connectors on this card. */
-#define MAX_MBS 8 /* # of mbufs we keep around */
- struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
- int next_mb; /* Which mbuf to use next. */
- int last_mb; /* Last mbuf. */
- int tx_start_thresh; /* Current TX_start_thresh. */
- int tx_succ_ok; /* # packets sent in sequence */
- /* w/o underrun */
- u_char bustype;
-#define EP_BUS_ISA 0x0
-#define EP_BUS_PCMCIA 0x1
-#define EP_BUS_EISA 0x2
-#define EP_BUS_PCI 0x3
-
-#define EP_IS_BUS_32(a) ((a) & 0x2)
-
- u_char pcmcia_flags;
-#define EP_REATTACH 0x01
-#define EP_ABSENT 0x02
-};
-
-static int epprobe __P((struct device *, void *, void *));
-static void epattach __P((struct device *, struct device *, void *));
-
-/* XXX the following two structs should be different. */
-#if NEP_ISA > 0
-struct cfattach ep_isa_ca = {
- sizeof(struct ep_softc), epprobe, epattach
-};
-#endif
-
-#if NEP_PCI > 0
-struct cfattach ep_pci_ca = {
- sizeof(struct ep_softc), epprobe, epattach
-};
-#endif
-
struct cfdriver ep_cd = {
NULL, "ep", DV_IFNET
};
-int epintr __P((void *));
+static void epxstat __P((struct ep_softc *));
static int epstatus __P((struct ep_softc *));
void epinit __P((struct ep_softc *));
int epioctl __P((struct ifnet *, u_long, caddr_t));
@@ -152,371 +88,16 @@ void epwatchdog __P((int));
void epreset __P((struct ep_softc *));
void epread __P((struct ep_softc *));
struct mbuf *epget __P((struct ep_softc *, int));
-void epmbuffill __P((void *));
+void epmbuffill __P((struct ep_softc *));
void epmbufempty __P((struct ep_softc *));
void epstop __P((struct ep_softc *));
void epsetfilter __P((struct ep_softc *));
void epsetlink __P((struct ep_softc *));
-static void epconfig __P((struct ep_softc *, u_int));
+u_short epreadeeprom __P((int id_port, int offset));
-static u_short epreadeeprom __P((int id_port, int offset));
static int epbusyeeprom __P((struct ep_softc *));
-#define MAXEPCARDS 20 /* if you have 21 cards in your machine... you lose */
-
-static struct epcard {
- int iobase;
- int irq;
- char available;
- char bustype;
-} epcards[MAXEPCARDS];
-static int nepcards;
-
-static void
-epaddcard(iobase, irq, bustype)
- int iobase;
- int irq;
- char bustype;
-{
-
- if (nepcards >= MAXEPCARDS)
- return;
- epcards[nepcards].iobase = iobase;
- epcards[nepcards].irq = (irq == 2) ? 9 : irq;
- epcards[nepcards].available = 1;
- epcards[nepcards].bustype = bustype;
- nepcards++;
-}
-
-#if NEP_PCMCIA > 0
-#include <dev/pcmcia/pcmciavar.h>
-
-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 *));
-
-static int ep_pcmcia_isa_attach __P((struct device *, void *,
- void *, struct pcmcia_link *));
-static int epmod __P((struct pcmcia_link *, struct device *,
- struct pcmcia_conf *, struct cfdata * cf));
-static int ep_remove __P((struct pcmcia_link *, struct device *));
-
-struct cfattach ep_pcmcia_ca = {
- sizeof(struct ep_softc), ep_pcmcia_match, epattach, ep_pcmcia_detach
-};
-
-/* additional setup needed for pcmcia devices */
-static int
-ep_pcmcia_isa_attach(parent, match, aux, pc_link)
- struct device *parent;
- void *match;
- void *aux;
- struct pcmcia_link *pc_link;
-{
- struct ep_softc *sc = (void *) match;
-/* struct cfdata *cf = sc->sc_dev.dv_cfdata;*/
- struct isa_attach_args *ia = aux;
-/* struct pcmciadevs *dev = pc_link->device;*/
- struct ifnet *ifp = &sc->sc_arpcom.ac_if;
- int i;
- extern int ifqmaxlen;
-
- outw(ia->ia_iobase + EP_COMMAND, WINDOW_SELECT | 0);
- outw(ia->ia_iobase + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
- outw(ia->ia_iobase + EP_W0_RESOURCE_CFG, 0x3f00);
-
- /*
- * ok til here. Now try to figure out which link we have.
- * try coax first...
- */
-#ifdef EP_COAX_DEFAULT
- outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0xC000);
-#else
- /* COAX as default is reported to be a problem */
- outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0x0000);
-#endif
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
-
- epaddcard(ia->ia_iobase, ia->ia_irq, EP_BUS_PCMCIA);
-
- for (i = 0; i < nepcards; i++) {
- if (epcards[i].available == 0)
- continue;
- if (ia->ia_iobase != IOBASEUNK &&
- ia->ia_iobase != epcards[i].iobase)
- continue;
- if (ia->ia_irq != IRQUNK &&
- ia->ia_irq != epcards[i].irq)
- continue;
- goto good;
- }
- return 0;
-
-good:
-
- epcards[i].available = 0;
- ia->ia_iobase = epcards[i].iobase;
- ia->ia_irq = epcards[i].irq;
- ia->ia_iosize = 0x10;
- ia->ia_msize = 0;
-
- sc->bustype = epcards[i].bustype;
- sc->pcmcia_flags = (pc_link->flags & PCMCIA_REATTACH) ? EP_REATTACH:0;
- return 1;
-}
-
-/* modify config entry */
-static int
-epmod(pc_link, self, pc_cf, cf)
- struct pcmcia_link *pc_link;
- struct device *self;
- struct pcmcia_conf *pc_cf;
- struct cfdata *cf;
-{
- 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;
- }
-
- if (pc_cf->io[0].len > 0x10)
- pc_cf->io[0].len = 0x10;
-#if 0
- pc_cf->cfgtype = DOSRESET;
-#endif
- pc_cf->cfgtype = 1;
-
- return 0;
-}
-
-static int
-ep_remove(pc_link, self)
- struct pcmcia_link *pc_link;
- struct device *self;
-{
- 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);
-}
-
-static struct pcmcia_3com {
- struct pcmcia_device pcd;
-} pcmcia_3com = {
- {"PCMCIA 3COM 3C589", epmod, ep_pcmcia_isa_attach, NULL, ep_remove}
-};
-
-struct pcmciadevs pcmcia_ep_devs[] = {
- {
- "ep", 0, "3Com Corporation", "3C589",
-#if 0
- "TP/BNC LAN Card Ver. 1a", "000001",
-#else
- NULL, NULL,
-#endif
- (void *) -1, (void *) &pcmcia_3com
- },
-#if 0
- {
- "ep", 0, "3Com Corporation", "3C589", "TP/BNC LAN Card Ver. 2a", "000002",
- (void *) -1, (void *) &pcmcia_3com
- },
-#endif
- { NULL }
-};
-#define nep_pcmcia_devs sizeof(pcmcia_ep_devs)/sizeof(pcmcia_ep_devs[0])
-
-int
-ep_pcmcia_match(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- return pcmcia_slave_match(parent, match, aux, pcmcia_ep_devs,
- nep_pcmcia_devs);
-}
-
void
-ep_pcmcia_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
- struct pcmcia_attach_args *paa = aux;
-
- printf("ep_pcmcia_attach %p %p %p\n", parent, self, aux);
- delay(2000000);
- if (!pcmcia_configure(parent, self, paa->paa_link)) {
- struct ep_softc *sc = (void *)self;
- sc->pcmcia_flags |= EP_ABSENT;
- printf(": not attached\n");
- }
-}
-
-/*
- * No detach; network devices are too well linked into the rest of the
- * kernel.
- */
-int
-ep_pcmcia_detach(self)
- struct device *self;
-{
- return EBUSY;
-}
-
-#endif
-
-
-/*
- * 3c579 cards on the EISA bus are probed by their slot number. 3c509
- * cards on the ISA bus are probed in ethernet address order. The probe
- * sequence requires careful orchestration, and we'd like like to allow
- * the irq and base address to be wildcarded. So, we probe all the cards
- * the first time epprobe() is called. On subsequent calls we look for
- * matching cards.
- */
-int
-epprobe(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- struct ep_softc *sc = match;
- struct isa_attach_args *ia = aux;
- static int probed;
- int slot, iobase, i;
- u_short vendor, model;
- int k, k2;
-
-#if NPCI > 0
- extern struct cfdriver pci_cd;
-
- if (parent->dv_cfdata->cf_driver == &pci_cd) {
- struct pci_attach_args *pa = (struct pci_attach_args *) aux;
-
- if (PCI_VENDORID(pa->pa_id) != PCI_VENDOR_3COM)
- return 0;
-
- switch (PCI_CHIPID(pa->pa_id)) {
- case PCI_PRODUCT_3COM_3C590:
- case PCI_PRODUCT_3COM_3C595:
- break;
- default:
- return 0;
- }
-
- if (nepcards >= MAXEPCARDS)
- return 0;
-
- epcards[nepcards++].available = 0;
- return 1;
- }
-#endif
-
- if (!probed) {
- probed = 1;
-
- /* find all EISA cards */
- for (slot = 1; slot < 16; slot++) {
- iobase = 0x1000 * slot;
-
- vendor = htons(inw(iobase + EISA_VENDOR));
- if (vendor != MFG_ID)
- continue;
-
- model = htons(inw(iobase + EISA_MODEL));
- if ((model & 0xfff0) != PROD_ID) {
-#ifndef trusted
- printf("epprobe: ignoring model %04x\n", model);
-#endif
- continue;
- }
-
- outb(iobase + EISA_CONTROL, EISA_ENABLE | EISA_RESET);
- delay(10);
- outb(iobase + EISA_CONTROL, EISA_ENABLE);
- /* Wait for reset? */
- delay(1000);
-
- k = inw(iobase + EP_W0_ADDRESS_CFG);
- k = (k & 0x1f) * 0x10 + 0x200;
-
- k2 = inw(iobase + EP_W0_RESOURCE_CFG);
- k2 >>= 12;
- epaddcard(iobase, k2, EP_BUS_EISA);
- }
-
- for (slot = 0; slot < 10; slot++) {
- elink_reset();
- elink_idseq(ELINK_509_POLY);
-
- /* Untag all the adapters so they will talk to us. */
- if (slot == 0)
- outb(ELINK_ID_PORT, TAG_ADAPTER + 0);
-
- vendor =
- htons(epreadeeprom(ELINK_ID_PORT, EEPROM_MFG_ID));
- if (vendor != MFG_ID)
- continue;
-
- model =
- htons(epreadeeprom(ELINK_ID_PORT, EEPROM_PROD_ID));
- if ((model & 0xfff0) != PROD_ID) {
-#ifndef trusted
- printf("epprobe: ignoring model %04x\n", model);
-#endif
- continue;
- }
-
- k = epreadeeprom(ELINK_ID_PORT, EEPROM_ADDR_CFG);
- k = (k & 0x1f) * 0x10 + 0x200;
-
- k2 = epreadeeprom(ELINK_ID_PORT, EEPROM_RESOURCE_CFG);
- k2 >>= 12;
- epaddcard(k, k2, EP_BUS_ISA);
-
- /* so card will not respond to contention again */
- outb(ELINK_ID_PORT, TAG_ADAPTER + 1);
-
- /*
- * XXX: this should probably not be done here
- * because it enables the drq/irq lines from
- * the board. Perhaps it should be done after
- * we have checked for irq/drq collisions?
- */
- outb(ELINK_ID_PORT, ACTIVATE_ADAPTER_TO_CONFIG);
- }
- /* XXX should we sort by ethernet address? */
- }
-
- for (i = 0; i < nepcards; i++) {
- if (epcards[i].available == 0)
- continue;
- if (ia->ia_iobase != IOBASEUNK &&
- ia->ia_iobase != epcards[i].iobase)
- continue;
- if (ia->ia_irq != IRQUNK &&
- ia->ia_irq != epcards[i].irq)
- continue;
- goto good;
- }
- return 0;
-
-good:
- epcards[i].available = 0;
- sc->bustype = epcards[i].bustype;
- ia->ia_iobase = epcards[i].iobase;
- ia->ia_irq = epcards[i].irq;
- ia->ia_iosize = 0x10;
- ia->ia_msize = 0;
- return 1;
-}
-
-static void
epconfig(sc, conn)
struct ep_softc *sc;
u_int conn;
@@ -526,7 +107,7 @@ epconfig(sc, conn)
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
sc->ep_connectors = 0;
- printf(": ");
+ printf("%s: ", sc->sc_dev.dv_xname);
if (conn & IS_AUI) {
printf("aui");
sc->ep_connectors |= AUI;
@@ -571,91 +152,15 @@ epconfig(sc, conn)
ifp->if_flags =
IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
- if ((sc->pcmcia_flags & EP_REATTACH) == 0) {
- if_attach(ifp);
- ether_ifattach(ifp);
+ if_attach(ifp);
+ ether_ifattach(ifp);
#if NBPFILTER > 0
- bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
- sizeof(struct ether_header));
-#endif
- }
- sc->tx_start_thresh = 20; /* probably a good starting point. */
-}
-
-static void
-epattach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
- struct ep_softc *sc = (void *)self;
- u_short conn = 0;
-#if NPCI > 0
- extern struct cfdriver pci_cd;
-
- if (parent->dv_cfdata->cf_driver == &pci_cd) {
- struct pci_attach_args *pa = aux;
- int iobase;
- u_short i;
-
- if (pci_map_io(pa->pa_tag, PCI_CBMA, &iobase)) {
- printf("%s: couldn't map io\n", sc->sc_dev.dv_xname);
- return;
- }
- sc->bustype = EP_BUS_PCI;
- sc->ep_iobase = iobase; /* & 0xfffffff0 */
- i = pci_conf_read(pa->pa_bc, pa->pa_tag, PCI_CONN);
-
- /*
- * Bits 13,12,9 of the isa adapter are the same as bits
- * 5,4,3 of the pci adapter
- */
- if (i & IS_PCI_AUI)
- conn |= IS_AUI;
- if (i & IS_PCI_BNC)
- conn |= IS_BNC;
- if (i & IS_PCI_UTP)
- conn |= IS_UTP;
-
- GO_WINDOW(0);
- }
- else
+ bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
#endif
- {
- struct isa_attach_args *ia = aux;
-
- sc->ep_iobase = ia->ia_iobase;
- GO_WINDOW(0);
- conn = inw(ia->ia_iobase + EP_W0_CONFIG_CTRL);
- }
-
- epconfig(sc, conn);
-
-
-#if NPCI > 0
- if (parent->dv_cfdata->cf_driver == &pci_cd) {
- struct pci_attach_args *pa = aux;
- pci_conf_write(pa->pa_bc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
- pci_conf_read(pa->pa_bc, pa->pa_tag,
- PCI_COMMAND_STATUS_REG) |
- PCI_COMMAND_MASTER_ENABLE);
-
- sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, epintr, sc);
- if (sc->sc_ih == NULL) {
- printf("%s: couldn't map interrupt\n",
- sc->sc_dev.dv_xname);
- return;
- }
- epstop(sc);
- }
- else
-#endif
- {
- struct isa_attach_args *ia = aux;
- sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq,
- IST_EDGE, IPL_NET, epintr, sc, sc->sc_dev.dv_xname);
- }
+ sc->tx_start_thresh = 20; /* probably a good starting point. */
}
/*
@@ -1278,13 +783,6 @@ epioctl(ifp, cmd, data)
int s, error = 0;
s = splnet();
- if (sc->bustype == EP_BUS_PCMCIA &&
- (sc->pcmcia_flags & EP_ABSENT)) {
- if_down(ifp);
- printf("%s: device offline\n", sc->sc_dev.dv_xname);
- splx(s);
- return ENXIO;
- }
switch (cmd) {
@@ -1432,7 +930,7 @@ epstop(sc)
* returned to us by inb(). Hence; we read 16 times getting one
* bit of data with each read.
*/
-static u_short
+u_short
epreadeeprom(id_port, offset)
int id_port;
int offset;
@@ -1478,10 +976,9 @@ epbusyeeprom(sc)
}
void
-epmbuffill(arg)
- void *arg;
+epmbuffill(sc)
+ struct ep_softc *sc;
{
- struct ep_softc *sc = arg;
int s, i;
s = splnet();
diff --git a/sys/dev/isa/if_epreg.h b/sys/dev/ic/elink3reg.h
index e215d7cee43..a125013030e 100644
--- a/sys/dev/isa/if_epreg.h
+++ b/sys/dev/ic/elink3reg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_epreg.h,v 1.14 1995/11/10 19:39:25 christos Exp $ */
+/* $NetBSD: elink3reg.h,v 1.1 1996/04/25 02:17:35 thorpej Exp $ */
/*
* Copyright (c) 1995 Herb Peyerl <hpeyerl@novatel.ca>
@@ -336,13 +336,3 @@
#define IS_PCI_AUI (1<<5)
#define IS_PCI_BNC (1<<4)
#define IS_PCI_UTP (1<<3)
-
-/*
- * EISA registers (offset from slot base)
- */
-#define EISA_VENDOR 0x0c80 /* vendor ID (2 ports) */
-#define EISA_MODEL 0x0c82 /* model number (2 ports) */
-#define EISA_CONTROL 0x0c84
-#define EISA_RESET 0x04
-#define EISA_ERROR 0x02
-#define EISA_ENABLE 0x01
diff --git a/sys/dev/ic/elink3var.h b/sys/dev/ic/elink3var.h
new file mode 100644
index 00000000000..c87e412e061
--- /dev/null
+++ b/sys/dev/ic/elink3var.h
@@ -0,0 +1,61 @@
+/* $NetBSD: elink3var.h,v 1.1 1996/04/25 02:17:36 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
+ * 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 Herb Peyerl.
+ * 4. The name of Herb Peyerl 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.
+ */
+
+/*
+ * Ethernet software status per interface.
+ */
+struct ep_softc {
+ struct device sc_dev;
+ void *sc_ih;
+
+ struct arpcom sc_arpcom; /* Ethernet common part */
+ int ep_iobase; /* i/o bus address */
+ char ep_connectors; /* Connectors on this card. */
+#define MAX_MBS 8 /* # of mbufs we keep around */
+ struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
+ int next_mb; /* Which mbuf to use next. */
+ int last_mb; /* Last mbuf. */
+ int tx_start_thresh; /* Current TX_start_thresh. */
+ int tx_succ_ok; /* # packets sent in sequence */
+ /* w/o underrun */
+ u_char bustype;
+#define EP_BUS_ISA 0x0
+#define EP_BUS_PCMCIA 0x1
+#define EP_BUS_EISA 0x2
+#define EP_BUS_PCI 0x3
+
+#define EP_IS_BUS_32(a) ((a) & 0x2)
+};
+
+u_short epreadeeprom __P((int id_port, int offset));
+void epconfig __P((struct ep_softc *, u_int));
+int epintr __P((void *));
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 63341eb0196..4e0136ea6a7 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,5 +1,5 @@
-# $OpenBSD: files.isa,v 1.12 1996/05/02 07:43:07 niklas Exp $
-# $NetBSD: files.isa,v 1.17 1996/03/29 20:53:30 mycroft Exp $
+# $OpenBSD: files.isa,v 1.13 1996/05/02 13:38:09 deraadt Exp $
+# $NetBSD: files.isa,v 1.18 1996/04/25 02:15:42 thorpej Exp $
#
# Config.new file and device description for machine-independent ISA code.
# Included by ports that need it. Requires that the SCSI files be
@@ -162,12 +162,9 @@ device el: ether, ifnet
attach el at isa
file dev/isa/if_el.c el
-# 3Com 3C5x9, 3c59x (EtherLink III) family
-device ep: ether, ifnet, elink
-attach ep at isa with ep_isa
-attach ep at pci with ep_pci
-attach ep at pcmcia with ep_pcmcia
-file dev/isa/if_ep.c ep & (ep_isa | ep_pci | ep_pcmcia) needs-flag
+# 3Com 3C509 Ethernet controller
+attach ep at isa with ep_isa: elink
+file dev/isa/if_ep_isa.c ep_isa
# Fujitsu MB8696[05]-based boards
# (Allied Telesis AT1700)
diff --git a/sys/dev/isa/if_ep_isa.c b/sys/dev/isa/if_ep_isa.c
new file mode 100644
index 00000000000..a138daa7c03
--- /dev/null
+++ b/sys/dev/isa/if_ep_isa.c
@@ -0,0 +1,216 @@
+/* $NetBSD: if_ep_isa.c,v 1.1 1996/04/25 02:15:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
+ * 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 Herb Peyerl.
+ * 4. The name of Herb Peyerl 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 "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.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
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/pio.h>
+
+#include <dev/ic/elink3var.h>
+#include <dev/ic/elink3reg.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/elink.h>
+
+int ep_isa_probe __P((struct device *, void *, void *));
+void ep_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach ep_isa_ca = {
+ sizeof(struct ep_softc), ep_isa_probe, ep_isa_attach
+};
+
+static void epaddcard __P((int, int));
+
+#define MAXEPCARDS 10 /* 10 ISA slots */
+
+static struct epcard {
+ int iobase;
+ int irq;
+ char available;
+} epcards[MAXEPCARDS];
+static int nepcards;
+
+static void
+epaddcard(iobase, irq)
+ int iobase;
+ int irq;
+{
+
+ if (nepcards >= MAXEPCARDS)
+ return;
+ epcards[nepcards].iobase = iobase;
+ epcards[nepcards].irq = (irq == 2) ? 9 : irq;
+ epcards[nepcards].available = 1;
+ nepcards++;
+}
+
+/*
+ * 3c509 cards on the ISA bus are probed in ethernet address order.
+ * The probe sequence requires careful orchestration, and we'd like
+ * like to allow the irq and base address to be wildcarded. So, we
+ * probe all the cards the first time epprobe() is called. On subsequent
+ * calls we look for matching cards.
+ */
+int
+ep_isa_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+ static int probed;
+ int slot, iobase, irq, i;
+ u_short vendor, model;
+
+ if (!probed) {
+ probed = 1;
+
+ for (slot = 0; slot < MAXEPCARDS; slot++) {
+ elink_reset();
+ elink_idseq(ELINK_509_POLY);
+
+ /* Untag all the adapters so they will talk to us. */
+ if (slot == 0)
+ outb(ELINK_ID_PORT, TAG_ADAPTER + 0);
+
+ vendor =
+ htons(epreadeeprom(ELINK_ID_PORT, EEPROM_MFG_ID));
+ if (vendor != MFG_ID)
+ continue;
+
+ model =
+ htons(epreadeeprom(ELINK_ID_PORT, EEPROM_PROD_ID));
+ if ((model & 0xfff0) != PROD_ID) {
+#ifndef trusted
+ printf(
+ "ep_isa_probe: ignoring model %04x\n", model);
+#endif
+ continue;
+ }
+
+ iobase = epreadeeprom(ELINK_ID_PORT, EEPROM_ADDR_CFG);
+ iobase = (iobase & 0x1f) * 0x10 + 0x200;
+
+ irq = epreadeeprom(ELINK_ID_PORT, EEPROM_RESOURCE_CFG);
+ irq >>= 12;
+ epaddcard(iobase, irq);
+
+ /* so card will not respond to contention again */
+ outb(ELINK_ID_PORT, TAG_ADAPTER + 1);
+
+ /*
+ * XXX: this should probably not be done here
+ * because it enables the drq/irq lines from
+ * the board. Perhaps it should be done after
+ * we have checked for irq/drq collisions?
+ */
+ outb(ELINK_ID_PORT, ACTIVATE_ADAPTER_TO_CONFIG);
+ }
+ /* XXX should we sort by ethernet address? */
+ }
+
+ for (i = 0; i < nepcards; i++) {
+ if (epcards[i].available == 0)
+ continue;
+ if (ia->ia_iobase != IOBASEUNK &&
+ ia->ia_iobase != epcards[i].iobase)
+ continue;
+ if (ia->ia_irq != IRQUNK &&
+ ia->ia_irq != epcards[i].irq)
+ continue;
+ goto good;
+ }
+ return 0;
+
+good:
+ epcards[i].available = 0;
+ ia->ia_iobase = epcards[i].iobase;
+ ia->ia_irq = epcards[i].irq;
+ ia->ia_iosize = 0x10;
+ ia->ia_msize = 0;
+ return 1;
+}
+
+void
+ep_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ep_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ u_short conn = 0;
+ int iobase;
+
+ sc->ep_iobase = iobase = ia->ia_iobase;
+ sc->bustype = EP_BUS_ISA;
+
+ GO_WINDOW(0);
+ conn = inw(iobase + EP_W0_CONFIG_CTRL);
+
+ printf(": 3Com 3C509 Ethernet\n");
+
+ epconfig(sc, conn);
+
+ sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
+ IPL_NET, epintr, sc, sc->sc_dev.dv_xname);
+}
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 149d0d98785..f77d9dddda3 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,5 +1,5 @@
-# $OpenBSD: files.pci,v 1.4 1996/04/21 22:25:06 deraadt Exp $
-# $NetBSD: files.pci,v 1.13 1996/03/17 00:55:24 thorpej Exp $
+# $OpenBSD: files.pci,v 1.5 1996/05/02 13:38:15 deraadt Exp $
+# $NetBSD: files.pci,v 1.14 1996/04/25 02:17:05 thorpej Exp $
#
# Config.new file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@@ -34,3 +34,8 @@ file dev/pci/ncr.c ncr
device ppb: pcibus
attach ppb at pci
file dev/pci/ppb.c ppb
+
+# 3Com 3c590 and 3c595 Ethernet controllers
+# device declaration in sys/conf/files
+attach ep at pci with ep_pci
+file dev/pci/if_ep_pci.c ep_pci
diff --git a/sys/dev/pci/if_ep_pci.c b/sys/dev/pci/if_ep_pci.c
new file mode 100644
index 00000000000..5deec157195
--- /dev/null
+++ b/sys/dev/pci/if_ep_pci.c
@@ -0,0 +1,188 @@
+/* $NetBSD: if_ep_pci.c,v 1.1 1996/04/25 02:17:06 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
+ * 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 Herb Peyerl.
+ * 4. The name of Herb Peyerl 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 "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.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
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/pio.h>
+
+#include <dev/ic/elink3var.h>
+#include <dev/ic/elink3reg.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+/* PCI constants */
+#define PCI_VENDORID(x) ((x) & 0xFFFF)
+#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
+#define PCI_CONN 0x48 /* Connector type */
+#define PCI_CBMA 0x10 /* Configuration Base Memory Address */
+
+int ep_pci_match __P((struct device *, void *, void *));
+void ep_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach ep_pci_ca = {
+ sizeof(struct ep_softc), ep_pci_match, ep_pci_attach
+};
+
+int
+ep_pci_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+ if (PCI_VENDORID(pa->pa_id) != PCI_VENDOR_3COM)
+ return 0;
+
+ switch (PCI_CHIPID(pa->pa_id)) {
+ case PCI_PRODUCT_3COM_3C590:
+ case PCI_PRODUCT_3COM_3C595:
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+ep_pci_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ep_softc *sc = (void *)self;
+ u_short conn = 0;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ int iobase;
+ u_short i;
+ char *model;
+ const char *intrstr = NULL;
+
+ if (pci_map_io(pa->pa_tag, PCI_CBMA, &iobase)) {
+ printf(": couldn't map io\n");
+ return;
+ }
+ sc->bustype = EP_BUS_PCI;
+ sc->ep_iobase = iobase; /* & 0xfffffff0 */
+ i = pci_conf_read(pc, pa->pa_tag, PCI_CONN);
+
+ /*
+ * Bits 13,12,9 of the isa adapter are the same as bits
+ * 5,4,3 of the pci adapter
+ */
+ if (i & IS_PCI_AUI)
+ conn |= IS_AUI;
+ if (i & IS_PCI_BNC)
+ conn |= IS_BNC;
+ if (i & IS_PCI_UTP)
+ conn |= IS_UTP;
+
+ GO_WINDOW(0);
+
+ switch (PCI_CHIPID(pa->pa_id)) {
+ case PCI_PRODUCT_3COM_3C590:
+ model = "3Com 3C590 Ethernet";
+ break;
+
+ case PCI_PRODUCT_3COM_3C595:
+ model = "3Com 3C595 Ethernet";
+ break;
+ default:
+ model = "unknown model!";
+ }
+
+ printf(": %s\n", model);
+
+ epconfig(sc, conn);
+
+ /* Enable the card. */
+ pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
+ PCI_COMMAND_MASTER_ENABLE);
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_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_NET, epintr,
+ 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: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ epstop(sc);
+}