summaryrefslogtreecommitdiffstats
path: root/sys/dev/ep
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ep')
-rw-r--r--sys/dev/ep/if_ep.c1000
-rw-r--r--sys/dev/ep/if_ep_eisa.c266
-rw-r--r--sys/dev/ep/if_ep_isa.c424
-rw-r--r--sys/dev/ep/if_ep_mca.c165
-rw-r--r--sys/dev/ep/if_ep_pccard.c286
-rw-r--r--sys/dev/ep/if_epreg.h434
-rw-r--r--sys/dev/ep/if_epvar.h84
7 files changed, 2659 insertions, 0 deletions
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c
new file mode 100644
index 0000000..fd3d90a
--- /dev/null
+++ b/sys/dev/ep/if_ep.c
@@ -0,0 +1,1000 @@
+/*
+ * 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.
+ *
+ * if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp
+ */
+
+/*
+ * Modified from the FreeBSD 1.1.5.1 version by:
+ * Andres Vega Garcia
+ * INRIA - Sophia Antipolis, France
+ * avega@sophia.inria.fr
+ */
+
+/*
+ * $FreeBSD$
+ *
+ * Promiscuous mode added and interrupt logic slightly changed
+ * to reduce the number of adapter failures. Transceiver select
+ * logic changed to use value from EEPROM. Autoconfiguration
+ * features added.
+ * Done by:
+ * Serge Babkin
+ * Chelindbank (Chelyabinsk, Russia)
+ * babkin@hq.icb.chel.su
+ */
+
+/*
+ * Pccard support for 3C589 by:
+ * HAMADA Naoki
+ * nao@tom-yam.or.jp
+ */
+
+/*
+ * MAINTAINER: Matthew N. Dodd <winter@jurai.net>
+ * <mdodd@FreeBSD.org>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+
+
+#include <dev/ep/if_epreg.h>
+#include <dev/ep/if_epvar.h>
+
+/* Exported variables */
+devclass_t ep_devclass;
+
+#if 0
+static char * ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};
+static int if_media2ep_media[] = { 0, 0, 0, UTP, BNC, AUI };
+#endif
+
+static int ep_media2if_media[] =
+ { IFM_10_T, IFM_10_5, IFM_NONE, IFM_10_2, IFM_NONE };
+
+/* if functions */
+static void ep_if_init (void *);
+static int ep_if_ioctl (struct ifnet *, u_long, caddr_t);
+static void ep_if_start (struct ifnet *);
+static void ep_if_watchdog (struct ifnet *);
+
+/* if_media functions */
+static int ep_ifmedia_upd (struct ifnet *);
+static void ep_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+
+static void epstop (struct ep_softc *);
+static void epread (struct ep_softc *);
+static int eeprom_rdy (struct ep_softc *);
+
+#define EP_FTST(sc, f) (sc->stat & (f))
+#define EP_FSET(sc, f) (sc->stat |= (f))
+#define EP_FRST(sc, f) (sc->stat &= ~(f))
+
+static int
+eeprom_rdy(sc)
+ struct ep_softc *sc;
+{
+ int i;
+
+ for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) {
+ DELAY(100);
+ }
+ if (i >= MAX_EEPROMBUSY) {
+ printf("ep%d: eeprom failed to come ready.\n", sc->unit);
+ return (ENXIO);
+ }
+ return (0);
+}
+
+/*
+ * get_e: gets a 16 bits word from the EEPROM. we must have set the window
+ * before
+ */
+int
+get_e(sc, offset, result)
+ struct ep_softc *sc;
+ u_int16_t offset;
+ u_int16_t *result;
+{
+
+ if (eeprom_rdy(sc))
+ return (ENXIO);
+ outw(BASE + EP_W0_EEPROM_COMMAND,
+ (EEPROM_CMD_RD << sc->epb.cmd_off) | offset);
+ if (eeprom_rdy(sc))
+ return (ENXIO);
+ (*result) = inw(BASE + EP_W0_EEPROM_DATA);
+
+ return (0);
+}
+
+int
+ep_get_macaddr(sc, addr)
+ struct ep_softc * sc;
+ u_char * addr;
+{
+ int i;
+ u_int16_t result;
+ int error;
+ u_int16_t * macaddr;
+
+ macaddr = (u_int16_t *)addr;
+
+ GO_WINDOW(0);
+ for(i = EEPROM_NODE_ADDR_0; i <= EEPROM_NODE_ADDR_2; i++) {
+ error = get_e(sc, i, &result);
+ if (error)
+ return (error);
+ macaddr[i] = htons(result);
+ }
+
+ return (0);
+}
+
+int
+ep_alloc(device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ int rid;
+ int error = 0;
+ u_int16_t result;
+
+ rid = 0;
+ sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->iobase) {
+ device_printf(dev, "No I/O space?!\n");
+ error = ENXIO;
+ goto bad;
+ }
+
+ rid = 0;
+ sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->irq) {
+ device_printf(dev, "No irq?!\n");
+ error = ENXIO;
+ goto bad;
+ }
+
+ sc->dev = dev;
+ sc->unit = device_get_unit(dev);
+ sc->stat = 0; /* 16 bit access */
+
+ sc->ep_io_addr = rman_get_start(sc->iobase);
+
+ sc->ep_btag = rman_get_bustag(sc->iobase);
+ sc->ep_bhandle = rman_get_bushandle(sc->iobase);
+
+ sc->ep_connectors = 0;
+ sc->ep_connector = 0;
+
+ GO_WINDOW(0);
+ sc->epb.cmd_off = 0;
+
+ error = get_e(sc, EEPROM_PROD_ID, &result);
+ if (error)
+ goto bad;
+ sc->epb.prod_id = result;
+
+ error = get_e(sc, EEPROM_RESOURCE_CFG, &result);
+ if (error)
+ goto bad;
+ sc->epb.res_cfg = result;
+
+bad:
+ return (error);
+}
+
+void
+ep_get_media(sc)
+ struct ep_softc * sc;
+{
+ u_int16_t config;
+
+ GO_WINDOW(0);
+ config = inw(BASE + EP_W0_CONFIG_CTRL);
+ if (config & IS_AUI)
+ sc->ep_connectors |= AUI;
+ if (config & IS_BNC)
+ sc->ep_connectors |= BNC;
+ if (config & IS_UTP)
+ sc->ep_connectors |= UTP;
+
+ if (!(sc->ep_connectors & 7)) {
+ if (bootverbose)
+ device_printf(sc->dev, "no connectors!\n");
+ }
+
+ /*
+ * This works for most of the cards so we'll do it here.
+ * The cards that require something different can override
+ * this later on.
+ */
+ sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
+
+ return;
+}
+
+void
+ep_free(device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+
+ if (sc->ep_intrhand)
+ bus_teardown_intr(dev, sc->irq, sc->ep_intrhand);
+ if (sc->iobase)
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
+ if (sc->irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+
+ return;
+}
+
+int
+ep_attach(sc)
+ struct ep_softc * sc;
+{
+ struct ifnet * ifp = NULL;
+ struct ifmedia * ifm = NULL;
+ u_short * p;
+ int i;
+ int attached;
+ int error;
+
+ sc->gone = 0;
+
+ error = ep_get_macaddr(sc, (u_char *)&sc->arpcom.ac_enaddr);
+ if (error) {
+ device_printf(sc->dev, "Unable to retrieve Ethernet address!\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Setup the station address
+ */
+ p = (u_short *)&sc->arpcom.ac_enaddr;
+ GO_WINDOW(2);
+ for (i = 0; i < 3; i++) {
+ outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
+ }
+
+ device_printf(sc->dev, "Ethernet address %6D\n",
+ sc->arpcom.ac_enaddr, ":");
+
+ ifp = &sc->arpcom.ac_if;
+ attached = (ifp->if_softc != 0);
+
+ ifp->if_softc = sc;
+ ifp->if_unit = sc->unit;
+ ifp->if_name = "ep";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_output = ether_output;
+ ifp->if_start = ep_if_start;
+ ifp->if_ioctl = ep_if_ioctl;
+ ifp->if_watchdog = ep_if_watchdog;
+ ifp->if_init = ep_if_init;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ if (!sc->epb.mii_trans) {
+ ifmedia_init(&sc->ifmedia, 0, ep_ifmedia_upd, ep_ifmedia_sts);
+
+ if (sc->ep_connectors & AUI)
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
+ if (sc->ep_connectors & UTP)
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+ if (sc->ep_connectors & BNC)
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
+ if (!sc->ep_connectors)
+ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL);
+
+ ifmedia_set(&sc->ifmedia, IFM_ETHER|ep_media2if_media[sc->ep_connector]);
+
+ ifm = &sc->ifmedia;
+ ifm->ifm_media = ifm->ifm_cur->ifm_media;
+ ep_ifmedia_upd(ifp);
+ }
+
+ if (!attached)
+ ether_ifattach(ifp, sc->arpcom.ac_enaddr);
+
+#ifdef EP_LOCAL_STATS
+ sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc =
+ sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
+#endif
+ EP_FSET(sc, F_RX_FIRST);
+ sc->top = sc->mcur = 0;
+
+ epstop(sc);
+
+ return 0;
+}
+
+int
+ep_detach(device_t dev)
+{
+ struct ep_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ if (sc->gone) {
+ device_printf(dev, "already unloaded\n");
+ return (0);
+ }
+
+ epstop(sc);
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ ether_ifdetach(ifp);
+
+ sc->gone = 1;
+ ep_free(dev);
+
+ return (0);
+}
+
+/*
+ * The order in here seems important. Otherwise we may not receive
+ * interrupts. ?!
+ */
+static void
+ep_if_init(xsc)
+ void *xsc;
+{
+ struct ep_softc *sc = xsc;
+ register struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s, i;
+
+ if (sc->gone)
+ return;
+
+ /*
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
+ */
+
+ s = splimp();
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ GO_WINDOW(0);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
+ GO_WINDOW(0);
+
+ /* Disable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, 0);
+
+ /* Enable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+
+ GO_WINDOW(2);
+
+ /* Reload the ether_addr. */
+ for (i = 0; i < 6; i++)
+ outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ /* Window 1 is operating window */
+ GO_WINDOW(1);
+ for (i = 0; i < 31; i++)
+ inb(BASE + EP_W1_TX_STATUS);
+
+ /* get rid of stray intr's */
+ outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
+
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
+
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
+
+ if (ifp->if_flags & IFF_PROMISC)
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_GROUP | FIL_BRDCST | FIL_ALL);
+ else
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_GROUP | FIL_BRDCST);
+
+ if (!sc->epb.mii_trans) {
+ ep_ifmedia_upd(ifp);
+ }
+
+ outw(BASE + EP_COMMAND, RX_ENABLE);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE; /* just in case */
+
+#ifdef EP_LOCAL_STATS
+ sc->rx_no_first = sc->rx_no_mbuf =
+ sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
+#endif
+ EP_FSET(sc, F_RX_FIRST);
+ if (sc->top) {
+ m_freem(sc->top);
+ sc->top = sc->mcur = 0;
+ }
+ outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
+ outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
+
+ /*
+ * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up
+ * any that we had in case we're being called from intr or somewhere
+ * else.
+ */
+
+ GO_WINDOW(1);
+ ep_if_start(ifp);
+
+ splx(s);
+}
+
+static void
+ep_if_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ep_softc *sc = ifp->if_softc;
+ u_int len;
+ struct mbuf *m;
+ struct mbuf *top;
+ int s, pad;
+
+ if (sc->gone) {
+ return;
+ }
+
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ if (ifp->if_flags & IFF_OACTIVE) {
+ return;
+ }
+
+startagain:
+ /* Sneak a peek at the next packet */
+ m = ifp->if_snd.ifq_head;
+ if (m == 0) {
+ return;
+ }
+ for (len = 0, top = m; m; m = m->m_next)
+ len += m->m_len;
+
+ pad = (4 - len) & 3;
+
+ /*
+ * The 3c509 automatically pads short packets to minimum ethernet length,
+ * but we drop packets that are too large. Perhaps we should truncate
+ * them instead?
+ */
+ if (len + pad > ETHER_MAX_LEN) {
+ /* packet is obviously too large: toss it */
+ ++ifp->if_oerrors;
+ IF_DEQUEUE(&ifp->if_snd, m);
+ m_freem(m);
+ goto readcheck;
+ }
+ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ /* no room in FIFO */
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
+ /* make sure */
+ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+ } else {
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+
+ s = splhigh();
+
+ outw(BASE + EP_W1_TX_PIO_WR_1, len);
+ outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */
+
+ if (EP_FTST(sc, F_ACCESS_32_BITS)) {
+ for (top = m; m != 0; m = m->m_next) {
+ if (m->m_len > 3)
+ outsl(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t), m->m_len / 4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + (m->m_len & (~3)), m->m_len & 3);
+ }
+ } else {
+ for (top = m; m != 0; m = m->m_next) {
+ if (m->m_len > 1)
+ outsw(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t), m->m_len / 2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
+ }
+
+ while (pad--)
+ outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
+
+ splx(s);
+
+ BPF_MTAP(ifp, top);
+
+ ifp->if_timer = 2;
+ ifp->if_opackets++;
+ m_freem(top);
+
+ /*
+ * Is another packet coming in? We don't want to overflow the tiny RX
+ * fifo.
+ */
+readcheck:
+ if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
+ /*
+ * we check if we have packets left, in that case we prepare to come
+ * back later
+ */
+ if (ifp->if_snd.ifq_head) {
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
+ }
+ return;
+ }
+ goto startagain;
+}
+
+void
+ep_intr(arg)
+ void *arg;
+{
+ struct ep_softc *sc;
+ register int status;
+ struct ifnet *ifp;
+ int x;
+
+ x = splbio();
+
+ sc = (struct ep_softc *)arg;
+
+ /*
+ * quick fix: Try to detect an interrupt when the card goes away.
+ */
+ if (sc->gone || inw(BASE + EP_STATUS) == 0xffff) {
+ splx(x);
+ return;
+ }
+
+ ifp = &sc->arpcom.ac_if;
+
+ outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */
+
+rescan:
+
+ while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) {
+
+ /* first acknowledge all interrupt sources */
+ outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK));
+
+ if (status & (S_RX_COMPLETE | S_RX_EARLY))
+ epread(sc);
+ if (status & S_TX_AVAIL) {
+ /* we need ACK */
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ GO_WINDOW(1);
+ inw(BASE + EP_W1_FREE_TX);
+ ep_if_start(ifp);
+ }
+ if (status & S_CARD_FAILURE) {
+ ifp->if_timer = 0;
+#ifdef EP_LOCAL_STATS
+ printf("\nep%d:\n\tStatus: %x\n", sc->unit, status);
+ GO_WINDOW(4);
+ printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));
+ printf("\tStat: %x\n", sc->stat);
+ printf("\tIpackets=%d, Opackets=%d\n",
+ ifp->if_ipackets, ifp->if_opackets);
+ printf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
+ sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf,
+ sc->rx_overrunl, sc->tx_underrun);
+#else
+
+#ifdef DIAGNOSTIC
+ printf("ep%d: Status: %x (input buffer overflow)\n", sc->unit, status);
+#else
+ ++ifp->if_ierrors;
+#endif
+
+#endif
+ ep_if_init(sc);
+ splx(x);
+ return;
+ }
+ if (status & S_TX_COMPLETE) {
+ ifp->if_timer = 0;
+ /* we need ACK. we do it at the end */
+ /*
+ * We need to read TX_STATUS until we get a 0 status in order to
+ * turn off the interrupt flag.
+ */
+ while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
+ if (status & TXS_SUCCES_INTR_REQ);
+ else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) {
+ outw(BASE + EP_COMMAND, TX_RESET);
+ if (status & TXS_UNDERRUN) {
+#ifdef EP_LOCAL_STATS
+ sc->tx_underrun++;
+#endif
+ } else {
+ if (status & TXS_JABBER);
+ else /* TXS_MAX_COLLISION - we shouldn't get here */
+ ++ifp->if_collisions;
+ }
+ ++ifp->if_oerrors;
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+ /*
+ * To have a tx_avail_int but giving the chance to the
+ * Reception
+ */
+ if (ifp->if_snd.ifq_head) {
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
+ }
+ }
+ outb(BASE + EP_W1_TX_STATUS, 0x0); /* pops up the next
+ * status */
+ } /* while */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ GO_WINDOW(1);
+ inw(BASE + EP_W1_FREE_TX);
+ ep_if_start(ifp);
+ } /* end TX_COMPLETE */
+ }
+
+ outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */
+
+ if ((status = inw(BASE + EP_STATUS)) & S_5_INTS)
+ goto rescan;
+
+ /* re-enable Ints */
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
+
+ splx(x);
+}
+
+static void
+epread(sc)
+ register struct ep_softc *sc;
+{
+ struct mbuf *top, *mcur, *m;
+ struct ifnet *ifp;
+ int lenthisone;
+
+ short rx_fifo2, status;
+ register short rx_fifo;
+
+ ifp = &sc->arpcom.ac_if;
+ status = inw(BASE + EP_W1_RX_STATUS);
+
+read_again:
+
+ if (status & ERR_RX) {
+ ++ifp->if_ierrors;
+ if (status & ERR_RX_OVERRUN) {
+ /*
+ * we can think the rx latency is actually greather than we
+ * expect
+ */
+#ifdef EP_LOCAL_STATS
+ if (EP_FTST(sc, F_RX_FIRST))
+ sc->rx_overrunf++;
+ else
+ sc->rx_overrunl++;
+#endif
+ }
+ goto out;
+ }
+ rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;
+
+ if (EP_FTST(sc, F_RX_FIRST)) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (!m)
+ goto out;
+ if (rx_fifo >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+ sc->top = sc->mcur = top = m;
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+ top->m_data += EOFF;
+
+ /* Read what should be the header. */
+ insw(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(top, caddr_t), sizeof(struct ether_header) / 2);
+ top->m_len = sizeof(struct ether_header);
+ rx_fifo -= sizeof(struct ether_header);
+ sc->cur_len = rx_fifo2;
+ } else {
+ /* come here if we didn't have a complete packet last time */
+ top = sc->top;
+ m = sc->mcur;
+ sc->cur_len += rx_fifo2;
+ }
+
+ /* Reads what is left in the RX FIFO */
+ while (rx_fifo > 0) {
+ lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
+ if (lenthisone == 0) { /* no room in this one */
+ mcur = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (!m)
+ goto out;
+ if (rx_fifo >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+ m->m_len = 0;
+ mcur->m_next = m;
+ lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
+ }
+ if (EP_FTST(sc, F_ACCESS_32_BITS)) { /* default for EISA configured cards*/
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
+ rx_fifo -= lenthisone;
+ }
+
+ if (status & ERR_RX_INCOMPLETE) { /* we haven't received the complete
+ * packet */
+ sc->mcur = m;
+#ifdef EP_LOCAL_STATS
+ sc->rx_no_first++; /* to know how often we come here */
+#endif
+ EP_FRST(sc, F_RX_FIRST);
+ if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) {
+ /* we see if by now, the packet has completly arrived */
+ goto read_again;
+ }
+ outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
+ return;
+ }
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ ++ifp->if_ipackets;
+ EP_FSET(sc, F_RX_FIRST);
+ top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ top->m_pkthdr.len = sc->cur_len;
+
+ (*ifp->if_input)(ifp, top);
+ sc->top = 0;
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
+ return;
+
+out:
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ if (sc->top) {
+ m_freem(sc->top);
+ sc->top = 0;
+#ifdef EP_LOCAL_STATS
+ sc->rx_no_mbuf++;
+#endif
+ }
+ EP_FSET(sc, F_RX_FIRST);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
+}
+
+static int
+ep_ifmedia_upd(ifp)
+ struct ifnet * ifp;
+{
+ struct ep_softc * sc = ifp->if_softc;
+ int i = 0, j;
+
+ GO_WINDOW(0);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
+ GO_WINDOW(0);
+
+ switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) {
+ case IFM_10_T:
+ if (sc->ep_connectors & UTP) {
+ i = ACF_CONNECTOR_UTP;
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ }
+ break;
+ case IFM_10_2:
+ if (sc->ep_connectors & BNC) {
+ i = ACF_CONNECTOR_BNC;
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(DELAY_MULTIPLE * 1000);
+ }
+ break;
+ case IFM_10_5:
+ if (sc->ep_connectors & AUI)
+ i = ACF_CONNECTOR_AUI;
+ break;
+ default:
+ i = sc->ep_connector;
+ device_printf(sc->dev,
+ "strange connector type in EEPROM: assuming AUI\n");
+ }
+
+ GO_WINDOW(0);
+ j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff;
+ outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));
+
+ return (0);
+}
+
+static void
+ep_ifmedia_sts(ifp, ifmr)
+ struct ifnet * ifp;
+ struct ifmediareq * ifmr;
+{
+ struct ep_softc * sc = ifp->if_softc;
+
+ ifmr->ifm_active = sc->ifmedia.ifm_media;
+
+ return;
+}
+
+static int
+ep_if_ioctl(ifp, cmd, data)
+ struct ifnet * ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ep_softc * sc = ifp->if_softc;
+ struct ifreq * ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ epstop(sc);
+ } else {
+ /* reinitialize card on any parameter change */
+ ep_if_init(sc);
+ }
+ break;
+#ifdef notdef
+ case SIOCGHWADDR:
+ bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data,
+ sizeof(sc->sc_addr));
+ break;
+#endif
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * The Etherlink III has no programmable multicast
+ * filter. We always initialize the card to be
+ * promiscuous to multicast, since we're always a
+ * member of the ALL-SYSTEMS group, so there's no
+ * need to process SIOC*MULTI requests.
+ */
+ error = 0;
+ break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ if (!sc->epb.mii_trans) {
+ error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
+ } else {
+ error = EINVAL;
+ }
+ break;
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ (void)splx(s);
+
+ return (error);
+}
+
+static void
+ep_if_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct ep_softc *sc = ifp->if_softc;
+
+ /*
+ printf("ep: watchdog\n");
+
+ log(LOG_ERR, "ep%d: watchdog\n", ifp->if_unit);
+ ifp->if_oerrors++;
+ */
+
+ if (sc->gone) {
+ return;
+ }
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ep_if_start(ifp);
+ ep_intr(ifp->if_softc);
+}
+
+static void
+epstop(sc)
+ struct ep_softc *sc;
+{
+ if (sc->gone) {
+ return;
+ }
+
+ outw(BASE + EP_COMMAND, RX_DISABLE);
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ outw(BASE + EP_COMMAND, TX_DISABLE);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ DELAY(800);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK);
+ outw(BASE + EP_COMMAND, SET_RX_FILTER);
+}
diff --git a/sys/dev/ep/if_ep_eisa.c b/sys/dev/ep/if_ep_eisa.c
new file mode 100644
index 0000000..e9b8348
--- /dev/null
+++ b/sys/dev/ep/if_ep_eisa.c
@@ -0,0 +1,266 @@
+/*
+ * Product specific probe and attach routines for:
+ * 3COM 3C579 and 3C509(in eisa config mode) ethernet controllers
+ *
+ * Copyright (c) 1996 Justin T. Gibbs
+ * 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 immediately at the beginning of the file, without modification,
+ * 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. Absolutely no warranty of function or purpose is made by the author
+ * Justin T. Gibbs.
+ * 4. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+
+#include <dev/eisa/eisaconf.h>
+
+#include <dev/ep/if_epreg.h>
+#include <dev/ep/if_epvar.h>
+
+#define EISA_DEVICE_ID_3COM_3C509_TP 0x506d5090
+#define EISA_DEVICE_ID_3COM_3C509_BNC 0x506d5091
+#define EISA_DEVICE_ID_3COM_3C579_TP 0x506d5092
+#define EISA_DEVICE_ID_3COM_3C579_BNC 0x506d5093
+#define EISA_DEVICE_ID_3COM_3C509_COMBO 0x506d5094
+#define EISA_DEVICE_ID_3COM_3C509_TPO 0x506d5095
+
+#define EP_EISA_SLOT_OFFSET 0x0c80
+#define EP_EISA_IOSIZE 0x000a
+
+#define EISA_IOCONF 0x0008
+#define IRQ_CHANNEL 0xf000
+#define INT_3 0x3000
+#define INT_5 0x5000
+#define INT_7 0x7000
+#define INT_9 0x9000
+#define INT_10 0xa000
+#define INT_11 0xb000
+#define INT_12 0xc000
+#define INT_15 0xf000
+#define EISA_BPROM_MEDIA_CONF 0x0006
+#define TRANS_TYPE 0xc000
+#define TRANS_TP 0x0000
+#define TRANS_AUI 0x4000
+#define TRANS_BNC 0xc000
+
+static const char *ep_match(eisa_id_t type);
+
+static const char*
+ep_match(eisa_id_t type)
+{
+ switch(type) {
+ case EISA_DEVICE_ID_3COM_3C509_TP:
+ return "3Com 3C509-TP Network Adapter";
+ break;
+ case EISA_DEVICE_ID_3COM_3C509_BNC:
+ return "3Com 3C509-BNC Network Adapter";
+ break;
+ case EISA_DEVICE_ID_3COM_3C579_TP:
+ return "3Com 3C579-TP EISA Network Adapter";
+ break;
+ case EISA_DEVICE_ID_3COM_3C579_BNC:
+ return "3Com 3C579-BNC EISA Network Adapter";
+ break;
+ case EISA_DEVICE_ID_3COM_3C509_COMBO:
+ return "3Com 3C509-Combo Network Adapter";
+ break;
+ case EISA_DEVICE_ID_3COM_3C509_TPO:
+ return "3Com 3C509-TPO Network Adapter";
+ break;
+ default:
+ break;
+ }
+ return (NULL);
+}
+
+static int
+ep_eisa_probe(device_t dev)
+{
+ const char *desc;
+ u_long iobase;
+ u_short conf;
+ u_long port;
+ int irq;
+ int int_trig;
+
+ desc = ep_match(eisa_get_id(dev));
+ if (!desc)
+ return (ENXIO);
+ device_set_desc(dev, desc);
+
+ port = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
+ iobase = port + EP_EISA_SLOT_OFFSET;
+
+ /* We must be in EISA configuration mode */
+ if ((inw(iobase + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
+ return ENXIO;
+
+ eisa_add_iospace(dev, iobase, EP_EISA_IOSIZE, RESVADDR_NONE);
+ eisa_add_iospace(dev, port, EP_IOSIZE, RESVADDR_NONE);
+
+ conf = inw(iobase + EISA_IOCONF);
+ /* Determine our IRQ */
+ switch (conf & IRQ_CHANNEL) {
+ case INT_3:
+ irq = 3;
+ break;
+ case INT_5:
+ irq = 5;
+ break;
+ case INT_7:
+ irq = 7;
+ break;
+ case INT_9:
+ irq = 9;
+ break;
+ case INT_10:
+ irq = 10;
+ break;
+ case INT_11:
+ irq = 11;
+ break;
+ case INT_12:
+ irq = 12;
+ break;
+ case INT_15:
+ irq = 15;
+ break;
+ default:
+ /* Disabled */
+ printf("ep: 3COM Network Adapter at "
+ "slot %d has its IRQ disabled. "
+ "Probe failed.\n",
+ eisa_get_slot(dev));
+ return ENXIO;
+ }
+
+ switch(eisa_get_id(dev)) {
+ case EISA_DEVICE_ID_3COM_3C579_BNC:
+ case EISA_DEVICE_ID_3COM_3C579_TP:
+ int_trig = EISA_TRIGGER_LEVEL;
+ break;
+ default:
+ int_trig = EISA_TRIGGER_EDGE;
+ break;
+ }
+
+ eisa_add_intr(dev, irq, int_trig);
+
+ return 0;
+}
+
+static int
+ep_eisa_attach(device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ struct resource * eisa_io = NULL;
+ u_int32_t eisa_iobase;
+ int irq;
+ int error = 0;
+ int rid;
+
+ rid = 1;
+ eisa_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!eisa_io) {
+ device_printf(dev, "No I/O space?!\n");
+ error = ENXIO;
+ goto bad;
+ }
+ eisa_iobase = rman_get_start(eisa_io);
+
+ /* Reset and Enable the card */
+ outb(eisa_iobase + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER);
+ DELAY(1000); /* we must wait at least 1 ms */
+ outb(eisa_iobase + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER);
+ /* Now the registers are availible through the lower ioport */
+
+ if ((error = ep_alloc(dev))) {
+ device_printf(dev, "ep_alloc() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ switch(eisa_get_id(dev)) {
+ case EISA_DEVICE_ID_3COM_3C579_BNC:
+ case EISA_DEVICE_ID_3COM_3C579_TP:
+ sc->stat = F_ACCESS_32_BITS;
+ break;
+ default:
+ break;
+ }
+
+ ep_get_media(sc);
+
+ irq = rman_get_start(sc->irq);
+ if (irq == 9)
+ irq = 2;
+
+ GO_WINDOW(0);
+ SET_IRQ(BASE, irq);
+
+ if ((error = ep_attach(sc))) {
+ device_printf(dev, "ep_attach() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, ep_intr,
+ sc, &sc->ep_intrhand))) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ return (0);
+
+ bad:
+ if (eisa_io)
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, eisa_io);
+
+ ep_free(dev);
+ return (error);
+}
+
+static device_method_t ep_eisa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ep_eisa_probe),
+ DEVMETHOD(device_attach, ep_eisa_attach),
+ DEVMETHOD(device_detach, ep_detach),
+
+ { 0, 0 }
+};
+
+static driver_t ep_eisa_driver = {
+ "ep",
+ ep_eisa_methods,
+ sizeof(struct ep_softc),
+};
+
+extern devclass_t ep_devclass;
+
+DRIVER_MODULE(ep, eisa, ep_eisa_driver, ep_devclass, 0, 0);
diff --git a/sys/dev/ep/if_ep_isa.c b/sys/dev/ep/if_ep_isa.c
new file mode 100644
index 0000000..1bef908
--- /dev/null
+++ b/sys/dev/ep/if_ep_isa.c
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <isa/isavar.h>
+
+#include <dev/ep/if_epreg.h>
+#include <dev/ep/if_epvar.h>
+
+#ifdef __i386__
+#include <i386/isa/elink.h>
+#endif
+
+#ifdef __i386__
+static u_int16_t get_eeprom_data (int, int);
+static void ep_isa_identify (driver_t *, device_t);
+#endif
+static int ep_isa_probe (device_t);
+static int ep_isa_attach (device_t);
+static int ep_eeprom_cksum (struct ep_softc *);
+
+struct isa_ident {
+ u_int32_t id;
+ char * name;
+};
+const char * ep_isa_match_id (u_int32_t, struct isa_ident *);
+
+#define ISA_ID_3C509_XXX 0x0506d509
+#define ISA_ID_3C509_TP 0x506d5090
+#define ISA_ID_3C509_BNC 0x506d5091
+#define ISA_ID_3C509_COMBO 0x506d5094
+#define ISA_ID_3C509_TPO 0x506d5095
+#define ISA_ID_3C509_TPC 0x506d5098
+#ifdef PC98
+#define ISA_ID_3C569B_COMBO 0x506d5694
+#define ISA_ID_3C569B_TPO 0x506d5695
+#endif
+
+#ifdef __i386__
+static struct isa_ident ep_isa_devs[] = {
+ { ISA_ID_3C509_TP, "3Com 3C509-TP EtherLink III" },
+ { ISA_ID_3C509_BNC, "3Com 3C509-BNC EtherLink III" },
+ { ISA_ID_3C509_COMBO, "3Com 3C509-Combo EtherLink III" },
+ { ISA_ID_3C509_TPO, "3Com 3C509-TPO EtherLink III" },
+ { ISA_ID_3C509_TPC, "3Com 3C509-TPC EtherLink III" },
+#ifdef PC98
+ { ISA_ID_3C569B_COMBO, "3Com 3C569B-J-Combo EtherLink III" },
+ { ISA_ID_3C569B_TPO, "3Com 3C569B-J-TPO EtherLink III" },
+#endif
+ { 0, NULL },
+};
+#endif
+
+static struct isa_pnp_id ep_ids[] = {
+ { 0x90506d50, "3Com 3C509B-TP EtherLink III (PnP)" }, /* TCM5090 */
+ { 0x91506d50, "3Com 3C509B-BNC EtherLink III (PnP)" },/* TCM5091 */
+ { 0x94506d50, "3Com 3C509B-Combo EtherLink III (PnP)" },/* TCM5094 */
+ { 0x95506d50, "3Com 3C509B-TPO EtherLink III (PnP)" },/* TCM5095 */
+ { 0x98506d50, "3Com 3C509B-TPC EtherLink III (PnP)" },/* TCM5098 */
+ { 0xf780d041, NULL }, /* PNP80f7 */
+ { 0, NULL },
+};
+
+/*
+ * We get eeprom data from the id_port given an offset into the eeprom.
+ * Basically; after the ID_sequence is sent to all of the cards; they enter
+ * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
+ * the eeprom data. We then read the port 16 times and with every read; the
+ * cards check for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
+ * compares the data on the bus; if there is a difference then that card goes
+ * into ID_WAIT state again). In the meantime; one bit of data is returned in
+ * the AX register which is conveniently returned to us by inb(). Hence; we
+ * read 16 times getting one bit of data with each read.
+ */
+#ifdef __i386__
+static u_int16_t
+get_eeprom_data(id_port, offset)
+ int id_port;
+ int offset;
+{
+ int i;
+ u_int16_t data = 0;
+
+ outb(id_port, EEPROM_CMD_RD|offset);
+ DELAY(BIT_DELAY_MULTIPLE * 1000);
+ for (i = 0; i < 16; i++) {
+ DELAY(50);
+ data = (data << 1) | (inw(id_port) & 1);
+ }
+ return (data);
+}
+#endif
+
+const char *
+ep_isa_match_id (id, isa_devs)
+ u_int32_t id;
+ struct isa_ident * isa_devs;
+{
+ struct isa_ident * i = isa_devs;
+ while(i->name != NULL) {
+ if (id == i->id)
+ return (i->name);
+ i++;
+ }
+ /*
+ * If we see a card that is likely to be a 3c509
+ * return something so that it will work; be annoying
+ * so that the user will tell us about it though.
+ */
+ if ((id >> 4) == ISA_ID_3C509_XXX) {
+ return ("Unknown 3c509; notify maintainer!");
+ }
+ return (NULL);
+}
+
+#ifdef __i386__
+static void
+ep_isa_identify (driver_t *driver, device_t parent)
+{
+ int tag = EP_LAST_TAG;
+ int found = 0;
+ int i;
+ int j;
+ const char * desc;
+ u_int16_t data;
+ u_int32_t irq;
+ u_int32_t ioport;
+ u_int32_t isa_id;
+ device_t child;
+
+ outb(ELINK_ID_PORT, 0);
+ outb(ELINK_ID_PORT, 0);
+ elink_idseq(ELINK_509_POLY);
+ elink_reset();
+
+ DELAY(DELAY_MULTIPLE * 10000);
+
+ for (i = 0; i < EP_MAX_BOARDS; i++) {
+
+ outb(ELINK_ID_PORT, 0);
+ outb(ELINK_ID_PORT, 0);
+ elink_idseq(ELINK_509_POLY);
+ DELAY(400);
+
+ /* For the first probe, clear all
+ * board's tag registers.
+ * Otherwise kill off already-found
+ * boards. -- linux 3c509.c
+ */
+ if (i == 0) {
+ outb(ELINK_ID_PORT, 0xd0);
+ } else {
+ outb(ELINK_ID_PORT, 0xd8);
+ }
+
+ /* Get out of loop if we're out of cards. */
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_MFG_ID);
+ if (data != MFG_ID) {
+ break;
+ }
+
+ /* resolve contention using the Ethernet address */
+ for (j = 0; j < 3; j++) {
+ (void)get_eeprom_data(ELINK_ID_PORT, j);
+ }
+
+ /*
+ * Construct an 'isa_id' in 'EISA'
+ * format.
+ */
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_MFG_ID);
+ isa_id = (htons(data) << 16);
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_PROD_ID);
+ isa_id |= htons(data);
+
+ /* Find known ISA boards */
+ desc = ep_isa_match_id(isa_id, ep_isa_devs);
+ if (!desc) {
+ if (bootverbose) {
+ device_printf(parent, "if_ep: unknown ID 0x%08x\n",
+ isa_id);
+ }
+ continue;
+ }
+
+ /* Retreive IRQ */
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_RESOURCE_CFG);
+ irq = (data >> 12);
+
+ /* Retreive IOPORT */
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_ADDR_CFG);
+#ifdef PC98
+ ioport = (((data & ADDR_CFG_MASK) * 0x100) + 0x40d0);
+#else
+ ioport = (((data & ADDR_CFG_MASK) << 4) + 0x200);
+#endif
+
+ if ((data & ADDR_CFG_MASK) == ADDR_CFG_EISA) {
+ device_printf(parent, "if_ep: <%s> at port 0x%03x in EISA mode!\n",
+ desc, ioport);
+ /* Set the adaptor tag so that the next card can be found. */
+ outb(ELINK_ID_PORT, tag--);
+ continue;
+ }
+
+ /* Test for an adapter with PnP support. */
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_CAP);
+ if (data == CAP_ISA) {
+ data = get_eeprom_data(ELINK_ID_PORT, EEPROM_INT_CONFIG_1);
+ if (data & ICW1_IAS_PNP) {
+ if (bootverbose) {
+ device_printf(parent, "if_ep: <%s> at 0x%03x in PnP mode!\n",
+ desc, ioport);
+ }
+ /* Set the adaptor tag so that the next card can be found. */
+ outb(ELINK_ID_PORT, tag--);
+ continue;
+ }
+ }
+
+ /* Set the adaptor tag so that the next card can be found. */
+ outb(ELINK_ID_PORT, tag--);
+
+ /* Activate the adaptor at the EEPROM location. */
+ outb(ELINK_ID_PORT, ACTIVATE_ADAPTER_TO_CONFIG);
+
+ /* Test for an adapter in TEST mode. */
+ outw(ioport + EP_COMMAND, WINDOW_SELECT | 0);
+ data = inw(ioport + EP_W0_EEPROM_COMMAND);
+ if (data & EEPROM_TST_MODE) {
+ device_printf(parent, "if_ep: <%s> at port 0x%03x in TEST mode! Erase pencil mark.\n",
+ desc, ioport);
+ continue;
+ }
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ep", -1);
+ device_set_desc_copy(child, desc);
+ device_set_driver(child, driver);
+ bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EP_IOSIZE);
+
+ if (bootverbose) {
+ device_printf(parent, "if_ep: <%s> at port 0x%03x-0x%03x irq %d\n",
+ desc, ioport, ioport + EP_IOSIZE, irq);
+ }
+
+ found++;
+ }
+
+ return;
+}
+#endif
+
+static int
+ep_isa_probe (device_t dev)
+{
+ int error = 0;
+
+ /* Check isapnp ids */
+ error = ISA_PNP_PROBE(device_get_parent(dev), dev, ep_ids);
+
+ /* If the card had a PnP ID that didn't match any we know about */
+ if (error == ENXIO) {
+ return (error);
+ }
+
+ /* If we had some other problem. */
+ if (!(error == 0 || error == ENOENT)) {
+ return (error);
+ }
+
+ /* If we have the resources we need then we're good to go. */
+ if ((bus_get_resource_start(dev, SYS_RES_IOPORT, 0) != 0) &&
+ (bus_get_resource_start(dev, SYS_RES_IRQ, 0) != 0)) {
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+static int
+ep_isa_attach (device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ int error = 0;
+
+ if ((error = ep_alloc(dev))) {
+ device_printf(dev, "ep_alloc() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ ep_get_media(sc);
+
+ GO_WINDOW(0);
+ SET_IRQ(BASE, rman_get_start(sc->irq));
+
+ if ((error = ep_attach(sc))) {
+ device_printf(dev, "ep_attach() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ error = ep_eeprom_cksum(sc);
+ if (error) {
+ device_printf(sc->dev, "Invalid EEPROM checksum!\n");
+ goto bad;
+ }
+
+ if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, ep_intr,
+ sc, &sc->ep_intrhand))) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ep_free(dev);
+ return (error);
+}
+
+static int
+ep_eeprom_cksum (sc)
+ struct ep_softc * sc;
+{
+ int i;
+ int error;
+ u_int16_t val;
+ u_int16_t cksum;
+ u_int8_t cksum_high = 0;
+ u_int8_t cksum_low = 0;
+
+ error = get_e(sc, 0x0f, &val);
+ if (error)
+ return (ENXIO);
+ cksum = val;
+
+ for (i = 0; i < 0x0f; i++) {
+ error = get_e(sc, i, &val);
+ if (error)
+ return (ENXIO);
+ switch (i) {
+ case 0x08:
+ case 0x09:
+ case 0x0d:
+ cksum_low ^= (u_int8_t)(val & 0x00ff) ^
+ (u_int8_t)((val & 0xff00) >> 8);
+ break;
+ default:
+ cksum_high ^= (u_int8_t)(val & 0x00ff) ^
+ (u_int8_t)((val & 0xff00) >> 8);
+ break;
+ }
+ }
+ return (cksum != ((u_int16_t)cksum_low | (u_int16_t)(cksum_high << 8)));
+}
+
+static device_method_t ep_isa_methods[] = {
+ /* Device interface */
+#ifdef __i386__
+ DEVMETHOD(device_identify, ep_isa_identify),
+#endif
+ DEVMETHOD(device_probe, ep_isa_probe),
+ DEVMETHOD(device_attach, ep_isa_attach),
+ DEVMETHOD(device_detach, ep_detach),
+
+ { 0, 0 }
+};
+
+static driver_t ep_isa_driver = {
+ "ep",
+ ep_isa_methods,
+ sizeof(struct ep_softc),
+};
+
+extern devclass_t ep_devclass;
+
+DRIVER_MODULE(ep, isa, ep_isa_driver, ep_devclass, 0, 0);
+#ifdef __i386__
+MODULE_DEPEND(ep, elink, 1, 1, 1);
+#endif
diff --git a/sys/dev/ep/if_ep_mca.c b/sys/dev/ep/if_ep_mca.c
new file mode 100644
index 0000000..b3a0506
--- /dev/null
+++ b/sys/dev/ep/if_ep_mca.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mca/mca_busreg.h>
+#include <dev/mca/mca_busvar.h>
+
+#include <dev/ep/if_epreg.h>
+#include <dev/ep/if_epvar.h>
+
+#define EP_MCA_627C 0x627C
+#define EP_MCA_627D 0x627D
+#define EP_MCA_62DB 0x62db
+#define EP_MCA_62F6 0x62f6
+#define EP_MCA_62F7 0x62f7
+
+static struct mca_ident ep_mca_devs[] = {
+ { EP_MCA_627C, "3Com 3C529 Network Adapter" },
+ { EP_MCA_627D, "3Com 3C529-TP Network Adapter" },
+
+ /*
+ * These are from the linux 3c509 driver.
+ * I have not seen the ADFs for them and have
+ * not tested or even seen the hardware.
+ * Someone with the ADFs should replace the names with
+ * whatever is in the AdapterName field of the ADF.
+ * (and fix the media setup for the cards as well.)
+ */
+ { EP_MCA_62DB, "3Com 3c529 EtherLink III (test mode)" },
+ { EP_MCA_62F6, "3Com 3c529 EtherLink III (TP or coax)" },
+ { EP_MCA_62F7, "3Com 3c529 EtherLink III (TP)" },
+
+ { 0, NULL },
+};
+
+#define EP_MCA_IOPORT_POS MCA_ADP_POS(MCA_POS2)
+#define EP_MCA_IOPORT_MASK 0xfc
+#define EP_MCA_IOPORT_SIZE EP_IOSIZE
+#define EP_MCA_IOPORT(pos) ((((u_int32_t)pos & EP_MCA_IOPORT_MASK) \
+ | 0x02) << 8)
+
+#define EP_MCA_IRQ_POS MCA_ADP_POS(MCA_POS3)
+#define EP_MCA_IRQ_MASK 0x0f
+#define EP_MCA_IRQ(pos) (pos & EP_MCA_IRQ_MASK)
+
+#define EP_MCA_MEDIA_POS MCA_ADP_POS(MCA_POS2)
+#define EP_MCA_MEDIA_MASK 0x03
+#define EP_MCA_MEDIA(pos) (pos & EP_MCA_MEDIA_MASK)
+
+static int
+ep_mca_probe (device_t dev)
+{
+ const char * desc;
+ u_int32_t iobase = 0;
+ u_int8_t irq = 0;
+ u_int8_t pos;
+
+ desc = mca_match_id(mca_get_id(dev), ep_mca_devs);
+ if (!desc)
+ return (ENXIO);
+ device_set_desc(dev, desc);
+
+ pos = mca_pos_read(dev, EP_MCA_IOPORT_POS);
+ iobase = EP_MCA_IOPORT(pos);
+
+ pos = mca_pos_read(dev, EP_MCA_IRQ_POS);
+ irq = EP_MCA_IRQ(pos);
+
+ mca_add_iospace(dev, iobase, EP_MCA_IOPORT_SIZE);
+ mca_add_irq(dev, irq);
+
+ return (0);
+}
+
+static int
+ep_mca_attach (device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ int error = 0;
+
+ if ((error = ep_alloc(dev))) {
+ device_printf(dev, "ep_alloc() failed! (%d)\n", error);
+ goto bad;
+ }
+ sc->stat = F_ACCESS_32_BITS;
+
+ ep_get_media(sc);
+
+ GO_WINDOW(0);
+ SET_IRQ(BASE, rman_get_start(sc->irq));
+
+ if ((error = ep_attach(sc))) {
+ device_printf(dev, "ep_attach() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, ep_intr,
+ sc, &sc->ep_intrhand))) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ep_free(dev);
+ return (error);
+}
+
+static device_method_t ep_mca_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ep_mca_probe),
+ DEVMETHOD(device_attach, ep_mca_attach),
+ DEVMETHOD(device_detach, ep_detach),
+
+ { 0, 0 }
+};
+
+static driver_t ep_mca_driver = {
+ "ep",
+ ep_mca_methods,
+ sizeof(struct ep_softc),
+};
+
+static devclass_t ep_devclass;
+
+DRIVER_MODULE(ep, mca, ep_mca_driver, ep_devclass, 0, 0);
diff --git a/sys/dev/ep/if_ep_pccard.c b/sys/dev/ep/if_ep_pccard.c
new file mode 100644
index 0000000..5a3e70a
--- /dev/null
+++ b/sys/dev/ep/if_ep_pccard.c
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Pccard support for 3C589 by:
+ * HAMADA Naoki
+ * nao@tom-yam.or.jp
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+
+#include <dev/ep/if_epreg.h>
+#include <dev/ep/if_epvar.h>
+
+#include <dev/pccard/pccardvar.h>
+#include <dev/pccard/pccarddevs.h>
+#include "card_if.h"
+
+static const char *ep_pccard_identify(u_short id);
+
+/*
+ * Initialize the device - called from Slot manager.
+ */
+static int
+ep_pccard_probe(device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ struct ep_board * epb = &sc->epb;
+ const char * desc;
+ u_int16_t result;
+ int error;
+
+ error = ep_alloc(dev);
+ if (error)
+ return error;
+
+ /*
+ * XXX - Certain (newer?) 3Com cards need epb->cmd_off ==
+ * 2. Sadly, you need to have a correct cmd_off in order to
+ * identify the card. So we have to hit it with both and
+ * cross our virtual fingers. There's got to be a better way
+ * to do this. jyoung@accessus.net 09/11/1999
+ */
+
+ epb->cmd_off = 0;
+
+ error = get_e(sc, EEPROM_PROD_ID, &result); /* XXX check return */
+ epb->prod_id = result;
+
+ if ((desc = ep_pccard_identify(epb->prod_id)) == NULL) {
+ if (bootverbose)
+ device_printf(dev, "Pass 1 of 2 detection "
+ "failed (nonfatal) id 0x%x\n", epb->prod_id);
+ epb->cmd_off = 2;
+ error = get_e(sc, EEPROM_PROD_ID, &result); /* XXX check return */
+ epb->prod_id = result;
+ if ((desc = ep_pccard_identify(epb->prod_id)) == NULL) {
+ device_printf(dev, "Unit failed to come ready or "
+ "product ID unknown! (id 0x%x)\n", epb->prod_id);
+ ep_free(dev);
+ return (ENXIO);
+ }
+ }
+ device_set_desc(dev, desc);
+
+ /*
+ * For some reason the 3c574 needs this.
+ */
+ error = ep_get_macaddr(sc, (u_char *)&sc->arpcom.ac_enaddr);
+
+ ep_free(dev);
+ return (0);
+}
+
+static const char *
+ep_pccard_identify(u_short id)
+{
+ /* Determine device type and associated MII capabilities */
+ switch (id) {
+ case 0x6055: /* 3C556 */
+ return ("3Com 3C556");
+ case 0x4057: /* 3C574 */
+ return ("3Com 3C574");
+ case 0x4b57: /* 3C574B */
+ return ("3Com 3C574B, Megahertz 3CCFE574BT or "
+ "Fast Etherlink 3C574-TX");
+ case 0x2b57: /* 3CXSH572BT */
+ return ("3Com OfficeConnect 572BT");
+ case 0x9058: /* 3C589 */
+ return ("3Com Etherlink III 3C589");
+ case 0x2056: /* 3C562/3C563 */
+ return ("3Com 3C562D/3C563D");
+ case 0x0010: /* 3C1 */
+ return ("3Com Megahertz C1");
+ }
+ return (NULL);
+}
+
+static int
+ep_pccard_card_attach(struct ep_board *epb)
+{
+ /* Determine device type and associated MII capabilities */
+ switch (epb->prod_id) {
+ case 0x6055: /* 3C556 */
+ case 0x2b57: /* 3C572BT */
+ case 0x4057: /* 3C574 */
+ case 0x4b57: /* 3C574B */
+ case 0x0010: /* 3C1 */
+ epb->mii_trans = 1;
+ return (1);
+ case 0x2056: /* 3C562D/3C563D */
+ case 0x9058: /* 3C589 */
+ epb->mii_trans = 0;
+ return (1);
+ }
+ return (0);
+}
+
+static int
+ep_pccard_attach(device_t dev)
+{
+ struct ep_softc * sc = device_get_softc(dev);
+ u_int16_t result;
+ int error = 0;
+
+ if ((error = ep_alloc(dev))) {
+ device_printf(dev, "ep_alloc() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ sc->epb.cmd_off = 0;
+
+ error = get_e(sc, EEPROM_PROD_ID, &result); /* XXX check return */
+ sc->epb.prod_id = result;
+
+ if (!ep_pccard_card_attach(&sc->epb)) {
+ sc->epb.cmd_off = 2;
+ error = get_e(sc, EEPROM_PROD_ID, &result);
+ sc->epb.prod_id = result;
+ error = get_e(sc, EEPROM_RESOURCE_CFG, &result);
+ sc->epb.res_cfg = result;
+ if (!ep_pccard_card_attach(&sc->epb)) {
+ device_printf(dev,
+ "Probe found ID, attach failed so ignore card!\n");
+ error = ENXIO;
+ goto bad;
+ }
+ }
+
+ error = get_e(sc, EEPROM_ADDR_CFG, &result);
+
+ /* ROM size = 0, ROM base = 0 */
+ /* For now, ignore AUTO SELECT feature of 3C589B and later. */
+ outw(BASE + EP_W0_ADDRESS_CFG, result & 0xc000);
+
+ /* Fake IRQ must be 3 */
+ outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb.res_cfg & 0x0fff) | 0x3000);
+
+ outw(BASE + EP_W0_PRODUCT_ID, sc->epb.prod_id);
+
+ if (sc->epb.mii_trans) {
+ /*
+ * turn on the MII transciever
+ */
+ GO_WINDOW(3);
+ outw(BASE + EP_W3_OPTIONS, 0x8040);
+ DELAY(1000);
+ outw(BASE + EP_W3_OPTIONS, 0xc040);
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ DELAY(1000);
+ outw(BASE + EP_W3_OPTIONS, 0x8040);
+ } else {
+ ep_get_media(sc);
+ }
+
+ if ((error = ep_attach(sc))) {
+ device_printf(dev, "ep_attach() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, ep_intr,
+ sc, &sc->ep_intrhand))) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ep_free(dev);
+ return (error);
+}
+
+static const struct pccard_product ep_pccard_products[] = {
+ PCMCIA_CARD(3COM, 3C1, 0),
+ PCMCIA_CARD(3COM, 3C562, 0),
+ PCMCIA_CARD(3COM, 3C574, 0), /* ROADRUNNER */
+ PCMCIA_CARD(3COM, 3C589, 0),
+ PCMCIA_CARD(3COM, 3CCFEM556BI, 0), /* ROADRUNNER */
+ PCMCIA_CARD(3COM, 3CXEM556, 0),
+ PCMCIA_CARD(3COM, 3CXEM556INT, 0),
+ { NULL }
+};
+
+static int
+ep_pccard_match(device_t dev)
+{
+ const struct pccard_product *pp;
+
+ if ((pp = pccard_product_lookup(dev, ep_pccard_products,
+ sizeof(ep_pccard_products[0]), NULL)) != NULL) {
+ if (pp->pp_name != NULL)
+ device_set_desc(dev, pp->pp_name);
+ return 0;
+ }
+ return EIO;
+}
+
+static device_method_t ep_pccard_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pccard_compat_probe),
+ DEVMETHOD(device_attach, pccard_compat_attach),
+ DEVMETHOD(device_detach, ep_detach),
+
+ /* Card interface */
+ DEVMETHOD(card_compat_match, ep_pccard_match),
+ DEVMETHOD(card_compat_probe, ep_pccard_probe),
+ DEVMETHOD(card_compat_attach, ep_pccard_attach),
+
+ { 0, 0 }
+};
+
+static driver_t ep_pccard_driver = {
+ "ep",
+ ep_pccard_methods,
+ sizeof(struct ep_softc),
+};
+
+extern devclass_t ep_devclass;
+
+DRIVER_MODULE(ep, pccard, ep_pccard_driver, ep_devclass, 0, 0);
diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h
new file mode 100644
index 0000000..9fb95f5
--- /dev/null
+++ b/sys/dev/ep/if_epreg.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 1993 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. 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * DELAY_MULTIPLE: How much to boost "base" delays, except
+ * for the inter-bit delays in get_eeprom_data. A cyrix Media GX needed this.
+ */
+#define DELAY_MULTIPLE 10
+#define BIT_DELAY_MULTIPLE 10
+
+/*
+ * Some global constants
+ */
+#define TX_INIT_RATE 16
+#define TX_INIT_MAX_RATE 64
+#define RX_INIT_LATENCY 64
+#define RX_INIT_EARLY_THRESH 208 /* not less than MINCLSIZE */
+#define RX_NEXT_EARLY_THRESH 500
+
+#define EEPROMSIZE 0x40
+#define MAX_EEPROMBUSY 1000
+#define EP_LAST_TAG 0xd7
+#define EP_MAX_BOARDS 16
+/*
+ * This `ID' port is a mere hack. There's currently no chance to register
+ * it with config's idea of the ports that are in use.
+ *
+ * "After the automatic configuration is completed, the IDS is in its initial
+ * state (ID-WAIT), and it monitors all write access to I/O port 01x0h, where
+ * 'x' is any hex digit. If a zero is written to any one of these ports, then
+ * that address is remembered and becomes the ID port. A second zero written
+ * to that port resets the ID sequence to its initial state. The IDS watches
+ * for the ID sequence to be written to the ID port."
+ *
+ * We prefer 0x110 over 0x100 so to not conflict with the Plaque&Pray
+ * ports.
+ */
+#define EP_ID_PORT 0x110
+#define EP_IOSIZE 16 /* 16 bytes of I/O space used. */
+
+/*
+ * some macros to acces long named fields
+ */
+#define BASE (sc->ep_io_addr)
+
+/*
+ * Commands to read/write EEPROM trough EEPROM command register (Window 0,
+ * Offset 0xa)
+ */
+#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */
+#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */
+#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */
+#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */
+
+#define EEPROM_BUSY (1<<15)
+#define EEPROM_TST_MODE (1<<14)
+
+/*
+ * Some short functions, worth to let them be a macro
+ */
+#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY)
+#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|(x))
+
+/**************************************************************************
+ * *
+ * These define the EEPROM data structure. They are used in the probe
+ * function to verify the existence of the adapter after having sent
+ * the ID_Sequence.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0 0x0 /* Word */
+#define EEPROM_NODE_ADDR_1 0x1 /* Word */
+#define EEPROM_NODE_ADDR_2 0x2 /* Word */
+#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
+#define EEPROM_MFG_DATE 0x4 /* Manufacturing date */
+#define EEPROM_MFG_DIVSION 0x5 /* Manufacturing division */
+#define EEPROM_MFG_PRODUCT 0x6 /* Product code */
+#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
+#define EEPROM_ADDR_CFG 0x8 /* Base addr */
+# define ADDR_CFG_EISA 0x1f
+# define ADDR_CFG_MASK 0x1f
+#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
+#define EEPROM_OEM_ADDR0 0xa
+#define EEPROM_OEM_ADDR1 0xb
+#define EEPROM_OEM_ADDR2 0xc
+#define EEPROM_SOFTINFO 0xd
+#define EEPROM_COMPAT 0xe
+#define EEPROM_SOFTINFO2 0xf
+#define EEPROM_CAP 0x10
+# define CAP_ISA 0x2083
+# define CAP_PCMCIA 0x2082
+#define EEPROM_INT_CONFIG_0 0x12
+#define EEPROM_INT_CONFIG_1 0x13
+/* RAM Partition TX FIFO/RX FIFO */
+# define ICW1_RAM_PART_MASK 0x03
+# define ICW1_RAM_PART_35 0x00 /* 2:5 (only legal if RAM size == 000b default power-up/reset */
+# define ICW1_RAM_PART_13 0x01 /* 1:3 (only legal if RAM size == 000b) */
+# define ICW1_RAM_PART_11 0x10 /* 1:1 */
+# define ICW1_RAM_PART_RESV 0x11 /* Reserved */
+/* ISA Adapter Selection */
+# define ICW1_IAS_MASK 0x0c
+# define ICW1_IAS_DIS 0x00 /* Both mechanisms disabled (default) */
+# define ICW1_IAS_ISA 0x04 /* ISA contention only */
+# define ICW1_IAS_PNP 0x08 /* ISA Plug and Play only */
+# define ICW1_IAS_BOTH 0x0c /* Both mechanisms enabled */
+
+#define EEPROM_CHECKSUM_EL3 0x17
+
+/**************************************************************************
+ * *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable. They have been taken out the the "EtherLink III Parallel *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com. *
+ * *
+ **************************************************************************/
+
+#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a
+ * command reg. */
+#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status
+ * reg. */
+#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window
+ * reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+/* Write */
+#define EP_W0_EEPROM_DATA 0x0c
+#define EP_W0_EEPROM_COMMAND 0x0a
+#define EP_W0_RESOURCE_CFG 0x08
+#define EP_W0_ADDRESS_CFG 0x06
+#define EP_W0_CONFIG_CTRL 0x04
+/* Read */
+#define EP_W0_PRODUCT_ID 0x02
+#define EP_W0_MFG_ID 0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+/* Write */
+#define EP_W1_TX_PIO_WR_2 0x02
+#define EP_W1_TX_PIO_WR_1 0x00
+/* Read */
+#define EP_W1_FREE_TX 0x0c
+#define EP_W1_TX_STATUS 0x0b /* byte */
+#define EP_W1_TIMER 0x0a /* byte */
+#define EP_W1_RX_STATUS 0x08
+#define EP_W1_RX_PIO_RD_2 0x02
+#define EP_W1_RX_PIO_RD_1 0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+/* Read/Write */
+#define EP_W2_ADDR_5 0x05
+#define EP_W2_ADDR_4 0x04
+#define EP_W2_ADDR_3 0x03
+#define EP_W2_ADDR_2 0x02
+#define EP_W2_ADDR_1 0x01
+#define EP_W2_ADDR_0 0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+/* Read */
+#define EP_W3_FREE_TX 0x0c
+#define EP_W3_FREE_RX 0x0a
+#define EP_W3_OPTIONS 0x08
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+/* Read/Write */
+#define EP_W4_MEDIA_TYPE 0x0a
+#define EP_W4_CTRLR_STATUS 0x08
+#define EP_W4_NET_DIAG 0x06
+#define EP_W4_FIFO_DIAG 0x04
+#define EP_W4_HOST_DIAG 0x02
+#define EP_W4_TX_DIAG 0x00
+
+/*
+ * Window 5 Registers. Results and Internal status.
+ */
+/* Read */
+#define EP_W5_READ_0_MASK 0x0c
+#define EP_W5_INTR_MASK 0x0a
+#define EP_W5_RX_FILTER 0x08
+#define EP_W5_RX_EARLY_THRESH 0x06
+#define EP_W5_TX_AVAIL_THRESH 0x02
+#define EP_W5_TX_START_THRESH 0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+/* Read/Write */
+#define TX_TOTAL_OK 0x0c
+#define RX_TOTAL_OK 0x0a
+#define TX_DEFERRALS 0x08
+#define RX_FRAMES_OK 0x07
+#define TX_FRAMES_OK 0x06
+#define RX_OVERRUNS 0x05
+#define TX_COLLISIONS 0x04
+#define TX_AFTER_1_COLLISION 0x03
+#define TX_AFTER_X_COLLISIONS 0x02
+#define TX_NO_SQE 0x01
+#define TX_CD_LOST 0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command parameter that disables threshold interrupts
+ * PIO (3c509) cards use 2044. The fifo word-oriented and 2044--2047 work.
+ * "busmastering" cards need 8188.
+ * The implicit two-bit upshift done by busmastering cards means
+ * a value of 2047 disables threshold interrupts on both.
+ */
+#define EP_THRESH_DISABLE 2047
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ * 15-11: 5-bit code for command to be executed.
+ * 10-0: 11-bit arg if any. For commands with no args;
+ * this can be set to anything.
+ */
+#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms
+ * after issuing */
+#define WINDOW_SELECT (u_short) (0x1<<11)
+#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to
+ * determine whether
+ * this is needed. If
+ * so; wait 800 uSec
+ * before using trans-
+ * ceiver. */
+#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on
+ * power-up */
+#define RX_ENABLE (u_short) (0x4<<11)
+#define RX_RESET (u_short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11)
+#define TX_ENABLE (u_short) (0x9<<11)
+#define TX_DISABLE (u_short) (0xa<<11)
+#define TX_RESET (u_short) (0xb<<11)
+#define REQ_INTR (u_short) (0xc<<11)
+#define SET_INTR_MASK (u_short) (0xe<<11)
+#define SET_RD_0_MASK (u_short) (0xf<<11)
+#define SET_RX_FILTER (u_short) (0x10<<11)
+#define FIL_INDIVIDUAL (u_short) (0x1)
+#define FIL_GROUP (u_short) (0x2)
+#define FIL_BRDCST (u_short) (0x4)
+#define FIL_ALL (u_short) (0x8)
+#define SET_RX_EARLY_THRESH (u_short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11)
+#define SET_TX_START_THRESH (u_short) (0x13<<11)
+#define STATS_ENABLE (u_short) (0x15<<11)
+#define STATS_DISABLE (u_short) (0x16<<11)
+#define STOP_TRANSCEIVER (u_short) (0x17<<11)
+/*
+ * The following C_* acknowledge the various interrupts. Some of them don't
+ * do anything. See the manual.
+ */
+#define ACK_INTR (u_short) (0x6800)
+#define C_INTR_LATCH (u_short) (ACK_INTR|0x1)
+#define C_CARD_FAILURE (u_short) (ACK_INTR|0x2)
+#define C_TX_COMPLETE (u_short) (ACK_INTR|0x4)
+#define C_TX_AVAIL (u_short) (ACK_INTR|0x8)
+#define C_RX_COMPLETE (u_short) (ACK_INTR|0x10)
+#define C_RX_EARLY (u_short) (ACK_INTR|0x20)
+#define C_INT_RQD (u_short) (ACK_INTR|0x40)
+#define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+#define C_MASK (u_short) 0xFF /* mask of C_* */
+
+/*
+ * Status register. All windows.
+ *
+ * 15-13: Window number(0-7).
+ * 12: Command_in_progress.
+ * 11: reserved.
+ * 10: reserved.
+ * 9: reserved.
+ * 8: reserved.
+ * 7: Update Statistics.
+ * 6: Interrupt Requested.
+ * 5: RX Early.
+ * 4: RX Complete.
+ * 3: TX Available.
+ * 2: TX Complete.
+ * 1: Adapter Failure.
+ * 0: Interrupt Latch.
+ */
+#define S_INTR_LATCH (u_short) (0x1)
+#define S_CARD_FAILURE (u_short) (0x2)
+#define S_TX_COMPLETE (u_short) (0x4)
+#define S_TX_AVAIL (u_short) (0x8)
+#define S_RX_COMPLETE (u_short) (0x10)
+#define S_RX_EARLY (u_short) (0x20)
+#define S_INT_RQD (u_short) (0x40)
+#define S_UPD_STATS (u_short) (0x80)
+#define S_MASK (u_short) 0xFF /* mask of S_* */
+#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\
+ S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY)
+#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+
+/* Address Config. Register.
+ * Window 0/Port 06
+ */
+
+#define ACF_CONNECTOR_BITS 14
+#define ACF_CONNECTOR_UTP 0
+#define ACF_CONNECTOR_AUI 1
+#define ACF_CONNECTOR_BNC 3
+
+/* Resource configuration register.
+ * Window 0/Port 08
+ *
+ */
+
+#define SET_IRQ(base,irq) outw((base) + EP_W0_RESOURCE_CFG, \
+ ((inw((base) + EP_W0_RESOURCE_CFG) & 0x0fff) | \
+ ((u_short)(irq)<<12)) ) /* set IRQ i */
+
+/*
+ * FIFO Registers.
+ * RX Status. Window 1/Port 08
+ *
+ * 15: Incomplete or FIFO empty.
+ * 14: 1: Error in RX Packet 0: Incomplete or no error.
+ * 13-11: Type of error.
+ * 1000 = Overrun.
+ * 1011 = Run Packet Error.
+ * 1100 = Alignment Error.
+ * 1101 = CRC Error.
+ * 1001 = Oversize Packet Error (>1514 bytes)
+ * 0010 = Dribble Bits.
+ * (all other error codes, no errors.)
+ *
+ * 10-0: RX Bytes (0-1514)
+ */
+#define ERR_RX_INCOMPLETE (u_short) (0x1<<15)
+#define ERR_RX (u_short) (0x1<<14)
+#define ERR_RX_OVERRUN (u_short) (0x8<<11)
+#define ERR_RX_RUN_PKT (u_short) (0xb<<11)
+#define ERR_RX_ALIGN (u_short) (0xc<<11)
+#define ERR_RX_CRC (u_short) (0xd<<11)
+#define ERR_RX_OVERSIZE (u_short) (0x9<<11)
+#define ERR_RX_DRIBBLE (u_short) (0x2<<11)
+
+/*
+ * FIFO Registers.
+ * TX Status. Window 1/Port 0B
+ *
+ * Reports the transmit status of a completed transmission. Writing this
+ * register pops the transmit completion stack.
+ *
+ * Window 1/Port 0x0b.
+ *
+ * 7: Complete
+ * 6: Interrupt on successful transmission requested.
+ * 5: Jabber Error (TP Only, TX Reset required. )
+ * 4: Underrun (TX Reset required. )
+ * 3: Maximum Collisions.
+ * 2: TX Status Overflow.
+ * 1-0: Undefined.
+ *
+ */
+#define TXS_COMPLETE 0x80
+#define TXS_SUCCES_INTR_REQ 0x40
+#define TXS_JABBER 0x20
+#define TXS_UNDERRUN 0x10
+#define TXS_MAX_COLLISION 0x8
+#define TXS_STATUS_OVERFLOW 0x4
+
+/*
+ * Configuration control register.
+ * Window 0/Port 04
+ */
+/* Read */
+#define IS_AUI (1<<13)
+#define IS_BNC (1<<12)
+#define IS_UTP (1<<9)
+/* Write */
+#define ENABLE_DRQ_IRQ 0x0001
+#define W0_P4_CMD_RESET_ADAPTER 0x4
+#define W0_P4_CMD_ENABLE_ADAPTER 0x1
+/*
+ * Media type and status.
+ * Window 4/Port 0A
+ */
+#define ENABLE_UTP 0xc0
+#define DISABLE_UTP 0x0
+
+/*
+ * Misc defines for various things.
+ */
+#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */
+#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */
+#define PROD_ID 0x9150
+
+#define AUI 0x1
+#define BNC 0x2
+#define UTP 0x4
+
+#define RX_BYTES_MASK (u_short) (0x07ff)
+
+/*
+ * Config flags
+ */
+#define EP_FLAGS_100TX 0x1
diff --git a/sys/dev/ep/if_epvar.h b/sys/dev/ep/if_epvar.h
new file mode 100644
index 0000000..b9d4107
--- /dev/null
+++ b/sys/dev/ep/if_epvar.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1993 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. 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.
+ *
+ * $FreeBSD$
+ */
+
+struct ep_board {
+ u_short prod_id; /* product ID */
+ int cmd_off; /* command offset (bit shift) */
+ int mii_trans; /* activate MII transiever */
+ u_short res_cfg; /* resource configuration */
+};
+
+/*
+ * Ethernet software status per interface.
+ */
+struct ep_softc {
+ struct arpcom arpcom; /* Ethernet common part */
+ struct ifmedia ifmedia; /* media info */
+
+ device_t dev;
+
+ struct resource * iobase;
+ struct resource * irq;
+
+ bus_space_handle_t ep_bhandle;
+ bus_space_tag_t ep_btag;
+ void * ep_intrhand;
+
+ int ep_io_addr; /* i/o bus address */
+
+ u_short ep_connectors; /* Connectors on this card. */
+ u_char ep_connector; /* Configured connector.*/
+
+ struct mbuf * top;
+ struct mbuf * mcur;
+ short cur_len;
+
+ int stat; /* some flags */
+#define F_RX_FIRST 0x001
+#define F_PROMISC 0x008
+#define F_ACCESS_32_BITS 0x100
+
+ int gone; /* adapter is not present (for PCCARD) */
+
+ struct ep_board epb;
+
+ int unit;
+
+#ifdef EP_LOCAL_STATS
+ short tx_underrun;
+ short rx_no_first;
+ short rx_no_mbuf;
+ short rx_overrunf;
+ short rx_overrunl;
+#endif
+};
+
+int ep_alloc (device_t);
+void ep_free (device_t);
+int ep_detach (device_t);
+void ep_get_media (struct ep_softc *);
+int ep_attach (struct ep_softc *);
+void ep_intr (void *);
+int get_e (struct ep_softc *, u_int16_t, u_int16_t *);
+int ep_get_macaddr (struct ep_softc *, u_char *);
OpenPOWER on IntegriCloud