summaryrefslogtreecommitdiffstats
path: root/sys/dev/snc
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2000-10-02 14:27:20 +0000
committernyan <nyan@FreeBSD.org>2000-10-02 14:27:20 +0000
commitbd4026ebae55d49b9834d42c7bae7f1a6f7b4d26 (patch)
tree7b40f1f273ca32e8c8eaf31dc2de4a944e5022f8 /sys/dev/snc
parentca9093b327311b17a6c77820abb0c66abf6a94f4 (diff)
downloadFreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.zip
FreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.tar.gz
Added NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and PC-9801N-J02R
support which use National Semiconductor DP8393X (SONIC) as ethernet controller. Currently, this driver is used on only PC-98. Submitted by: Motomichi Matsuzaki <mzaki@e-mail.ne.jp> Obtained from: NetBSD/pc98
Diffstat (limited to 'sys/dev/snc')
-rw-r--r--sys/dev/snc/dp83932.c1231
-rw-r--r--sys/dev/snc/dp83932reg.h271
-rw-r--r--sys/dev/snc/dp83932subr.c902
-rw-r--r--sys/dev/snc/dp83932subr.h78
-rw-r--r--sys/dev/snc/dp83932var.h307
-rw-r--r--sys/dev/snc/if_snc.c258
-rw-r--r--sys/dev/snc/if_snc_cbus.c224
-rw-r--r--sys/dev/snc/if_snc_pccard.c160
-rw-r--r--sys/dev/snc/if_sncreg.h140
-rw-r--r--sys/dev/snc/if_sncvar.h47
10 files changed, 3618 insertions, 0 deletions
diff --git a/sys/dev/snc/dp83932.c b/sys/dev/snc/dp83932.c
new file mode 100644
index 0000000..a27a332
--- /dev/null
+++ b/sys/dev/snc/dp83932.c
@@ -0,0 +1,1231 @@
+/* $FreeBSD$ */
+/* $NecBSD: dp83932.c,v 1.5 1999/07/29 05:08:44 kmatsuda Exp $ */
+/* $NetBSD: if_snc.c,v 1.18 1998/04/25 21:27:40 scottr Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Kouichi Matsuda. 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 Kouichi Matsuda for
+ * NetBSD/pc98.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki.
+ */
+
+/*
+ * Modified for NetBSD/pc98 1.2G from NetBSD/mac68k 1.2G by Kouichi Matsuda.
+ * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and
+ * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as
+ * Ethernet Controller and National Semiconductor NS46C46 as
+ * (64 * 16 bits) Microwire Serial EEPROM.
+ */
+
+/*
+ * National Semiconductor DP8393X SONIC Driver
+ * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
+ * You may use, copy, and modify this program so long as you retain the
+ * copyright line.
+ *
+ * This driver has been substantially modified since Algorithmics donated
+ * it.
+ *
+ * Denton Gentry <denny1@home.com>
+ * and also
+ * Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>
+ * did the work to get this running on the Macintosh.
+ */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <dev/snc/dp83932reg.h>
+#include <dev/snc/dp83932var.h>
+
+hide void sncwatchdog __P((struct ifnet *));
+hide void sncinit __P((void *));
+hide int sncstop __P((struct snc_softc *sc));
+hide int sncioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+hide void sncstart __P((struct ifnet *ifp));
+hide void sncreset __P((struct snc_softc *sc));
+
+hide void caminitialise __P((struct snc_softc *));
+hide void camentry __P((struct snc_softc *, int, u_char *ea));
+hide void camprogram __P((struct snc_softc *));
+hide void initialise_tda __P((struct snc_softc *));
+hide void initialise_rda __P((struct snc_softc *));
+hide void initialise_rra __P((struct snc_softc *));
+#ifdef SNCDEBUG
+hide void camdump __P((struct snc_softc *sc));
+#endif
+
+hide void sonictxint __P((struct snc_softc *));
+hide void sonicrxint __P((struct snc_softc *));
+
+hide u_int sonicput __P((struct snc_softc *sc, struct mbuf *m0,
+ int mtd_next));
+hide int sonic_read __P((struct snc_softc *, u_int32_t, int));
+hide struct mbuf *sonic_get __P((struct snc_softc *,
+ u_int32_t, int));
+
+int snc_enable __P((struct snc_softc *));
+void snc_disable __P((struct snc_softc *));
+
+int snc_mediachange __P((struct ifnet *));
+void snc_mediastatus __P((struct ifnet *, struct ifmediareq *));
+
+#ifdef NetBSD
+#if NetBSD <= 199714
+struct cfdriver snc_cd = {
+ NULL, "snc", DV_IFNET
+};
+#endif
+#endif
+
+#undef assert
+#undef _assert
+
+#ifdef NDEBUG
+#define assert(e) ((void)0)
+#define _assert(e) ((void)0)
+#else
+#define _assert(e) assert(e)
+#ifdef __STDC__
+#define assert(e) ((e) ? (void)0 : __assert("snc ", __FILE__, __LINE__, #e))
+#else /* PCC */
+#define assert(e) ((e) ? (void)0 : __assert("snc "__FILE__, __LINE__, "e"))
+#endif
+#endif
+
+#ifdef SNCDEBUG
+#define SNC_SHOWTXHDR 0x01 /* show tx ether_header */
+#define SNC_SHOWRXHDR 0x02 /* show rx ether_header */
+#define SNC_SHOWCAMENT 0x04 /* show CAM entry */
+#endif /* SNCDEBUG */
+int sncdebug = 0;
+
+
+void
+sncconfig(sc, media, nmedia, defmedia, myea)
+ struct snc_softc *sc;
+ int *media, nmedia, defmedia;
+ u_int8_t *myea;
+{
+ struct ifnet *ifp = &sc->sc_if;
+ int i;
+
+#ifdef SNCDEBUG
+ if ((sncdebug & SNC_SHOWCAMENT) != 0) {
+ camdump(sc);
+ }
+#endif
+ device_printf(sc->sc_dev, "address %6D\n", myea, ":");
+
+#ifdef SNCDEBUG
+ device_printf(sc->sc_dev,
+ "buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x\n",
+ sc->v_rra[0], sc->v_cda,
+ sc->v_rda, sc->mtda[0].mtd_vtxp);
+#endif
+
+ ifp->if_softc = sc;
+ ifp->if_unit = device_get_unit(sc->sc_dev);
+ ifp->if_name = "snc";
+ ifp->if_ioctl = sncioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = sncstart;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_watchdog = sncwatchdog;
+ ifp->if_init = sncinit;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ bcopy(myea, sc->sc_ethercom.ac_enaddr, ETHER_ADDR_LEN);
+
+ /* Initialize media goo. */
+ ifmedia_init(&sc->sc_media, 0, snc_mediachange,
+ snc_mediastatus);
+ if (media != NULL) {
+ for (i = 0; i < nmedia; i++)
+ ifmedia_add(&sc->sc_media, media[i], 0, NULL);
+ ifmedia_set(&sc->sc_media, defmedia);
+ } else {
+ ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
+ ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
+ }
+
+ ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
+
+#if NRND > 0
+ rnd_attach_source(&sc->rnd_source, device_get_nameunit(sc->sc_dev),
+ RND_TYPE_NET, 0);
+#endif
+}
+
+void
+sncshutdown(arg)
+ void *arg;
+{
+
+ sncstop((struct snc_softc *)arg);
+}
+
+/*
+ * Media change callback.
+ */
+int
+snc_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ struct snc_softc *sc = ifp->if_softc;
+
+ if (sc->sc_mediachange)
+ return ((*sc->sc_mediachange)(sc));
+ return (EINVAL);
+}
+
+/*
+ * Media status callback.
+ */
+void
+snc_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct snc_softc *sc = ifp->if_softc;
+
+ if (sc->sc_enabled == 0) {
+ ifmr->ifm_active = IFM_ETHER | IFM_NONE;
+ ifmr->ifm_status = 0;
+ return;
+ }
+
+ if (sc->sc_mediastatus)
+ (*sc->sc_mediastatus)(sc, ifmr);
+}
+
+
+hide int
+sncioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifreq *ifr;
+ struct snc_softc *sc = ifp->if_softc;
+ int s = splnet(), err = 0;
+ int temp;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ err = ether_ioctl(ifp, cmd, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running,
+ * then stop it.
+ */
+ sncstop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ snc_disable(sc);
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped,
+ * then start it.
+ */
+ if ((err = snc_enable(sc)) != 0)
+ break;
+ sncinit(sc);
+ } else if (sc->sc_enabled) {
+ /*
+ * reset the interface to pick up any other changes
+ * in flags
+ */
+ temp = ifp->if_flags & IFF_UP;
+ sncreset(sc);
+ ifp->if_flags |= temp;
+ sncstart(ifp);
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (sc->sc_enabled == 0) {
+ err = EIO;
+ break;
+ }
+ temp = ifp->if_flags & IFF_UP;
+ sncreset(sc);
+ ifp->if_flags |= temp;
+ err = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ ifr = (struct ifreq *) data;
+ err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ break;
+ default:
+ err = EINVAL;
+ }
+ splx(s);
+ return (err);
+}
+
+/*
+ * Encapsulate a packet of type family for the local net.
+ */
+hide void
+sncstart(ifp)
+ struct ifnet *ifp;
+{
+ struct snc_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+ int mtd_next;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+outloop:
+ /* Check for room in the xmit buffer. */
+ if ((mtd_next = (sc->mtd_free + 1)) == NTDA)
+ mtd_next = 0;
+
+ if (mtd_next == sc->mtd_hw) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ return;
+
+ /* We need the header for m_pkthdr.len. */
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("%s: sncstart: no header mbuf",
+ device_get_nameunit(sc->sc_dev));
+
+ /*
+ * If bpf is listening on this interface, let it
+ * see the packet before we commit it to the wire.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m);
+
+ /*
+ * If there is nothing in the o/p queue, and there is room in
+ * the Tx ring, then send the packet directly. Otherwise append
+ * it to the o/p queue.
+ */
+ if ((sonicput(sc, m, mtd_next)) == 0) {
+ IF_PREPEND(&ifp->if_snd, m);
+ return;
+ }
+
+ sc->mtd_prev = sc->mtd_free;
+ sc->mtd_free = mtd_next;
+
+ ifp->if_opackets++; /* # of pkts */
+
+ /* Jump back for possibly more punishment. */
+ goto outloop;
+}
+
+/*
+ * reset and restart the SONIC. Called in case of fatal
+ * hardware/software errors.
+ */
+hide void
+sncreset(sc)
+ struct snc_softc *sc;
+{
+ sncstop(sc);
+ sncinit(sc);
+}
+
+hide void
+sncinit(xsc)
+ void *xsc;
+{
+ struct snc_softc *sc = xsc;
+ u_long s_rcr;
+ int s;
+
+ if (sc->sc_if.if_flags & IFF_RUNNING)
+ /* already running */
+ return;
+
+ s = splnet();
+
+ NIC_PUT(sc, SNCR_CR, CR_RST); /* DCR only accessable in reset mode! */
+
+ /* config it */
+ NIC_PUT(sc, SNCR_DCR, (sc->sncr_dcr |
+ (sc->bitmode ? DCR_DW32 : DCR_DW16)));
+ NIC_PUT(sc, SNCR_DCR2, sc->sncr_dcr2);
+
+ s_rcr = RCR_BRD | RCR_LBNONE;
+ if (sc->sc_if.if_flags & IFF_PROMISC)
+ s_rcr |= RCR_PRO;
+ if (sc->sc_if.if_flags & IFF_ALLMULTI)
+ s_rcr |= RCR_AMC;
+ NIC_PUT(sc, SNCR_RCR, s_rcr);
+
+ NIC_PUT(sc, SNCR_IMR, (IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_LCDEN));
+
+ /* clear pending interrupts */
+ NIC_PUT(sc, SNCR_ISR, ISR_ALL);
+
+ /* clear tally counters */
+ NIC_PUT(sc, SNCR_CRCT, -1);
+ NIC_PUT(sc, SNCR_FAET, -1);
+ NIC_PUT(sc, SNCR_MPT, -1);
+
+ initialise_tda(sc);
+ initialise_rda(sc);
+ initialise_rra(sc);
+
+ /* enable the chip */
+ NIC_PUT(sc, SNCR_CR, 0);
+ wbflush();
+
+ /* program the CAM */
+ camprogram(sc);
+
+ /* get it to read resource descriptors */
+ NIC_PUT(sc, SNCR_CR, CR_RRRA);
+ wbflush();
+ while ((NIC_GET(sc, SNCR_CR)) & CR_RRRA)
+ continue;
+
+ /* enable rx */
+ NIC_PUT(sc, SNCR_CR, CR_RXEN);
+ wbflush();
+
+ /* flag interface as "running" */
+ sc->sc_if.if_flags |= IFF_RUNNING;
+ sc->sc_if.if_flags &= ~IFF_OACTIVE;
+
+ splx(s);
+ return;
+}
+
+/*
+ * close down an interface and free its buffers
+ * Called on final close of device, or if sncinit() fails
+ * part way through.
+ */
+hide int
+sncstop(sc)
+ struct snc_softc *sc;
+{
+ struct mtd *mtd;
+ int s = splnet();
+
+ /* stick chip in reset */
+ NIC_PUT(sc, SNCR_CR, CR_RST);
+ wbflush();
+
+ /* free all receive buffers (currently static so nothing to do) */
+
+ /* free all pending transmit mbufs */
+ while (sc->mtd_hw != sc->mtd_free) {
+ mtd = &sc->mtda[sc->mtd_hw];
+ if (mtd->mtd_mbuf)
+ m_freem(mtd->mtd_mbuf);
+ if (++sc->mtd_hw == NTDA) sc->mtd_hw = 0;
+ }
+
+ sc->sc_if.if_timer = 0;
+ sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Called if any Tx packets remain unsent after 5 seconds,
+ * In all cases we just reset the chip, and any retransmission
+ * will be handled by higher level protocol timeouts.
+ */
+hide void
+sncwatchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct snc_softc *sc = ifp->if_softc;
+ struct mtd *mtd;
+ int temp;
+
+ if (sc->mtd_hw != sc->mtd_free) {
+ /* something still pending for transmit */
+ mtd = &sc->mtda[sc->mtd_hw];
+ if (SRO(sc, mtd->mtd_vtxp, TXP_STATUS) == 0)
+ log(LOG_ERR, "%s: Tx - timeout\n",
+ device_get_nameunit(sc->sc_dev));
+ else
+ log(LOG_ERR, "%s: Tx - lost interrupt\n",
+ device_get_nameunit(sc->sc_dev));
+ temp = ifp->if_flags & IFF_UP;
+ sncreset(sc);
+ ifp->if_flags |= temp;
+ }
+}
+
+/*
+ * stuff packet into sonic (at splnet)
+ */
+hide u_int
+sonicput(sc, m0, mtd_next)
+ struct snc_softc *sc;
+ struct mbuf *m0;
+ int mtd_next;
+{
+ struct mtd *mtdp;
+ struct mbuf *m;
+ u_int32_t buff;
+ u_int32_t txp;
+ u_int len = 0;
+ u_int totlen = 0;
+
+#ifdef whyonearthwouldyoudothis
+ if (NIC_GET(sc, SNCR_CR) & CR_TXP)
+ return (0);
+#endif
+
+ /* grab the replacement mtd */
+ mtdp = &sc->mtda[sc->mtd_free];
+
+ buff = mtdp->mtd_vbuf;
+
+ /* this packet goes to mtdnext fill in the TDA */
+ mtdp->mtd_mbuf = m0;
+ txp = mtdp->mtd_vtxp;
+
+ /* Write to the config word. Every (NTDA/2)+1 packets we set an intr */
+ if (sc->mtd_pint == 0) {
+ sc->mtd_pint = NTDA/2;
+ SWO(sc, txp, TXP_CONFIG, TCR_PINT);
+ } else {
+ sc->mtd_pint--;
+ SWO(sc, txp, TXP_CONFIG, 0);
+ }
+
+ for (m = m0; m; m = m->m_next) {
+ len = m->m_len;
+ totlen += len;
+ (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), buff, len);
+ buff += len;
+ }
+ if (totlen >= TXBSIZE) {
+ panic("%s: sonicput: packet overflow",
+ device_get_nameunit(sc->sc_dev));
+ }
+
+ SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRLO,
+ LOWER(mtdp->mtd_vbuf));
+ SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRHI,
+ UPPER(mtdp->mtd_vbuf));
+
+ if (totlen < ETHERMIN + sizeof(struct ether_header)) {
+ int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
+ (*sc->sc_zerobuf)(sc, mtdp->mtd_vbuf + totlen, pad);
+ totlen = ETHERMIN + sizeof(struct ether_header);
+ }
+
+ SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FSIZE,
+ totlen);
+ SWO(sc, txp, TXP_FRAGCNT, 1);
+ SWO(sc, txp, TXP_PKTSIZE, totlen);
+
+ /* link onto the next mtd that will be used */
+ SWO(sc, txp, TXP_FRAGOFF + (1 * TXP_FRAGSIZE) + TXP_FPTRLO,
+ LOWER(sc->mtda[mtd_next].mtd_vtxp) | EOL);
+
+ /*
+ * The previous txp.tlink currently contains a pointer to
+ * our txp | EOL. Want to clear the EOL, so write our
+ * pointer to the previous txp.
+ */
+ SWO(sc, sc->mtda[sc->mtd_prev].mtd_vtxp, sc->mtd_tlinko,
+ LOWER(mtdp->mtd_vtxp));
+
+ /* make sure chip is running */
+ wbflush();
+ NIC_PUT(sc, SNCR_CR, CR_TXP);
+ wbflush();
+ sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
+
+ return (totlen);
+}
+
+/*
+ * These are called from sonicioctl() when /etc/ifconfig is run to set
+ * the address or switch the i/f on.
+ */
+/*
+ * CAM support
+ */
+hide void
+caminitialise(sc)
+ struct snc_softc *sc;
+{
+ u_int32_t v_cda = sc->v_cda;
+ int i;
+ int camoffset;
+
+ for (i = 0; i < MAXCAM; i++) {
+ camoffset = i * CDA_CAMDESC;
+ SWO(sc, v_cda, (camoffset + CDA_CAMEP), i);
+ SWO(sc, v_cda, (camoffset + CDA_CAMAP2), 0);
+ SWO(sc, v_cda, (camoffset + CDA_CAMAP1), 0);
+ SWO(sc, v_cda, (camoffset + CDA_CAMAP0), 0);
+ }
+ SWO(sc, v_cda, CDA_ENABLE, 0);
+
+#ifdef SNCDEBUG
+ if ((sncdebug & SNC_SHOWCAMENT) != 0) {
+ camdump(sc);
+ }
+#endif
+}
+
+hide void
+camentry(sc, entry, ea)
+ int entry;
+ u_char *ea;
+ struct snc_softc *sc;
+{
+ u_int32_t v_cda = sc->v_cda;
+ int camoffset = entry * CDA_CAMDESC;
+
+ SWO(sc, v_cda, camoffset + CDA_CAMEP, entry);
+ SWO(sc, v_cda, camoffset + CDA_CAMAP2, (ea[5] << 8) | ea[4]);
+ SWO(sc, v_cda, camoffset + CDA_CAMAP1, (ea[3] << 8) | ea[2]);
+ SWO(sc, v_cda, camoffset + CDA_CAMAP0, (ea[1] << 8) | ea[0]);
+ SWO(sc, v_cda, CDA_ENABLE,
+ (SRO(sc, v_cda, CDA_ENABLE) | (1 << entry)));
+}
+
+hide void
+camprogram(sc)
+ struct snc_softc *sc;
+{
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int timeout;
+ int mcount = 0;
+
+ caminitialise(sc);
+
+ ifp = &sc->sc_if;
+
+ /* Always load our own address first. */
+ camentry (sc, mcount, sc->sc_ethercom.ac_enaddr);
+ mcount++;
+
+ /* Assume we won't need allmulti bit. */
+ ifp->if_flags &= ~IFF_ALLMULTI;
+
+ /* Loop through multicast addresses */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ if (mcount == MAXCAM) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ break;
+ }
+
+ /* program the CAM with the specified entry */
+ camentry(sc, mcount,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ mcount++;
+ }
+
+ NIC_PUT(sc, SNCR_CDP, LOWER(sc->v_cda));
+ NIC_PUT(sc, SNCR_CDC, MAXCAM);
+ NIC_PUT(sc, SNCR_CR, CR_LCAM);
+ wbflush();
+
+ timeout = 10000;
+ while ((NIC_GET(sc, SNCR_CR) & CR_LCAM) && timeout--)
+ continue;
+ if (timeout == 0) {
+ /* XXX */
+ panic("%s: CAM initialisation failed\n",
+ device_get_nameunit(sc->sc_dev));
+ }
+ timeout = 10000;
+ while (((NIC_GET(sc, SNCR_ISR) & ISR_LCD) == 0) && timeout--)
+ continue;
+
+ if (NIC_GET(sc, SNCR_ISR) & ISR_LCD)
+ NIC_PUT(sc, SNCR_ISR, ISR_LCD);
+ else
+ device_printf(sc->sc_dev,
+ "CAM initialisation without interrupt\n");
+}
+
+#ifdef SNCDEBUG
+hide void
+camdump(sc)
+ struct snc_softc *sc;
+{
+ int i;
+
+ printf("CAM entries:\n");
+ NIC_PUT(sc, SNCR_CR, CR_RST);
+ wbflush();
+
+ for (i = 0; i < 16; i++) {
+ ushort ap2, ap1, ap0;
+ NIC_PUT(sc, SNCR_CEP, i);
+ wbflush();
+ ap2 = NIC_GET(sc, SNCR_CAP2);
+ ap1 = NIC_GET(sc, SNCR_CAP1);
+ ap0 = NIC_GET(sc, SNCR_CAP0);
+ printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);
+ }
+ printf("CAM enable 0x%x\n", NIC_GET(sc, SNCR_CEP));
+
+ NIC_PUT(sc, SNCR_CR, 0);
+ wbflush();
+}
+#endif
+
+hide void
+initialise_tda(sc)
+ struct snc_softc *sc;
+{
+ struct mtd *mtd;
+ int i;
+
+ for (i = 0; i < NTDA; i++) {
+ mtd = &sc->mtda[i];
+ mtd->mtd_mbuf = 0;
+ }
+
+ sc->mtd_hw = 0;
+ sc->mtd_prev = NTDA - 1;
+ sc->mtd_free = 0;
+ sc->mtd_tlinko = TXP_FRAGOFF + 1*TXP_FRAGSIZE + TXP_FPTRLO;
+ sc->mtd_pint = NTDA/2;
+
+ NIC_PUT(sc, SNCR_UTDA, UPPER(sc->mtda[0].mtd_vtxp));
+ NIC_PUT(sc, SNCR_CTDA, LOWER(sc->mtda[0].mtd_vtxp));
+}
+
+hide void
+initialise_rda(sc)
+ struct snc_softc *sc;
+{
+ int i;
+ u_int32_t vv_rda = 0;
+ u_int32_t v_rda = 0;
+
+ /* link the RDA's together into a circular list */
+ for (i = 0; i < (sc->sc_nrda - 1); i++) {
+ v_rda = sc->v_rda + (i * RXPKT_SIZE(sc));
+ vv_rda = sc->v_rda + ((i+1) * RXPKT_SIZE(sc));
+ SWO(sc, v_rda, RXPKT_RLINK, LOWER(vv_rda));
+ SWO(sc, v_rda, RXPKT_INUSE, 1);
+ }
+ v_rda = sc->v_rda + ((sc->sc_nrda - 1) * RXPKT_SIZE(sc));
+ SWO(sc, v_rda, RXPKT_RLINK, LOWER(sc->v_rda) | EOL);
+ SWO(sc, v_rda, RXPKT_INUSE, 1);
+
+ /* mark end of receive descriptor list */
+ sc->sc_rdamark = sc->sc_nrda - 1;
+
+ sc->sc_rxmark = 0;
+
+ NIC_PUT(sc, SNCR_URDA, UPPER(sc->v_rda));
+ NIC_PUT(sc, SNCR_CRDA, LOWER(sc->v_rda));
+ wbflush();
+}
+
+hide void
+initialise_rra(sc)
+ struct snc_softc *sc;
+{
+ int i;
+ u_int v;
+ int bitmode = sc->bitmode;
+
+ if (bitmode)
+ NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 2);
+ else
+ NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 1);
+
+ NIC_PUT(sc, SNCR_URRA, UPPER(sc->v_rra[0]));
+ NIC_PUT(sc, SNCR_RSA, LOWER(sc->v_rra[0]));
+ /* rea must point just past the end of the rra space */
+ NIC_PUT(sc, SNCR_REA, LOWER(sc->v_rea));
+ NIC_PUT(sc, SNCR_RRP, LOWER(sc->v_rra[0]));
+ NIC_PUT(sc, SNCR_RSC, 0);
+
+ /* fill up SOME of the rra with buffers */
+ for (i = 0; i < NRBA; i++) {
+ v = SONIC_GETDMA(sc->rbuf[i]);
+ SWO(sc, sc->v_rra[i], RXRSRC_PTRHI, UPPER(v));
+ SWO(sc, sc->v_rra[i], RXRSRC_PTRLO, LOWER(v));
+ SWO(sc, sc->v_rra[i], RXRSRC_WCHI, UPPER(NBPG/2));
+ SWO(sc, sc->v_rra[i], RXRSRC_WCLO, LOWER(NBPG/2));
+ }
+ sc->sc_rramark = NRBA;
+ NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[sc->sc_rramark]));
+ wbflush();
+}
+
+void
+sncintr(arg)
+ void *arg;
+{
+ struct snc_softc *sc = (struct snc_softc *)arg;
+ int isr;
+
+ if (sc->sc_enabled == 0)
+ return;
+
+ while ((isr = (NIC_GET(sc, SNCR_ISR) & ISR_ALL)) != 0) {
+ /* scrub the interrupts that we are going to service */
+ NIC_PUT(sc, SNCR_ISR, isr);
+ wbflush();
+
+ if (isr & (ISR_BR | ISR_LCD | ISR_TC))
+ device_printf(sc->sc_dev,
+ "unexpected interrupt status 0x%x\n",
+ isr);
+
+ if (isr & (ISR_TXDN | ISR_TXER | ISR_PINT))
+ sonictxint(sc);
+
+ if (isr & ISR_PKTRX)
+ sonicrxint(sc);
+
+ if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) {
+ if (isr & ISR_HBL)
+ /*
+ * The repeater is not providing a heartbeat.
+ * In itself this isn't harmful, lots of the
+ * cheap repeater hubs don't supply a heartbeat.
+ * So ignore the lack of heartbeat. Its only
+ * if we can't detect a carrier that we have a
+ * problem.
+ */
+ ;
+ if (isr & ISR_RDE)
+ device_printf(sc->sc_dev,
+ "receive descriptors exhausted\n");
+ if (isr & ISR_RBE)
+ device_printf(sc->sc_dev,
+ "receive buffers exhausted\n");
+ if (isr & ISR_RBAE)
+ device_printf(sc->sc_dev,
+ "receive buffer area exhausted\n");
+ if (isr & ISR_RFO)
+ device_printf(sc->sc_dev,
+ "receive FIFO overrun\n");
+ }
+ if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) {
+#ifdef notdef
+ if (isr & ISR_CRC)
+ sc->sc_crctally++;
+ if (isr & ISR_FAE)
+ sc->sc_faetally++;
+ if (isr & ISR_MP)
+ sc->sc_mptally++;
+#endif
+ }
+ sncstart(&sc->sc_if);
+
+#if NRND > 0
+ if (isr)
+ rnd_add_uint32(&sc->rnd_source, isr);
+#endif
+ }
+ return;
+}
+
+/*
+ * Transmit interrupt routine
+ */
+hide void
+sonictxint(sc)
+ struct snc_softc *sc;
+{
+ struct mtd *mtd;
+ u_int32_t txp;
+ unsigned short txp_status;
+ int mtd_hw;
+ struct ifnet *ifp = &sc->sc_if;
+
+ mtd_hw = sc->mtd_hw;
+
+ if (mtd_hw == sc->mtd_free)
+ return;
+
+ while (mtd_hw != sc->mtd_free) {
+ mtd = &sc->mtda[mtd_hw];
+
+ txp = mtd->mtd_vtxp;
+
+ if (SRO(sc, txp, TXP_STATUS) == 0) {
+ break; /* it hasn't really gone yet */
+ }
+
+#ifdef SNCDEBUG
+ if ((sncdebug & SNC_SHOWTXHDR) != 0)
+ {
+ struct ether_header eh;
+
+ (*sc->sc_copyfrombuf)(sc, &eh, mtd->mtd_vbuf, sizeof(eh));
+ device_printf(sc->sc_dev,
+ "xmit status=0x%x len=%d type=0x%x from %6D",
+ SRO(sc, txp, TXP_STATUS),
+ SRO(sc, txp, TXP_PKTSIZE),
+ htons(eh.ether_type),
+ eh.ether_shost, ":");
+ printf(" (to %6D)\n", eh.ether_dhost, ":");
+ }
+#endif /* SNCDEBUG */
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (mtd->mtd_mbuf != 0) {
+ m_freem(mtd->mtd_mbuf);
+ mtd->mtd_mbuf = 0;
+ }
+ if (++mtd_hw == NTDA) mtd_hw = 0;
+
+ txp_status = SRO(sc, txp, TXP_STATUS);
+
+ ifp->if_collisions += (txp_status & TCR_EXC) ? 16 :
+ ((txp_status & TCR_NC) >> 12);
+
+ if ((txp_status & TCR_PTX) == 0) {
+ ifp->if_oerrors++;
+ device_printf(sc->sc_dev, "Tx packet status=0x%x\n",
+ txp_status);
+
+ /* XXX - DG This looks bogus */
+ if (mtd_hw != sc->mtd_free) {
+ printf("resubmitting remaining packets\n");
+ mtd = &sc->mtda[mtd_hw];
+ NIC_PUT(sc, SNCR_CTDA, LOWER(mtd->mtd_vtxp));
+ NIC_PUT(sc, SNCR_CR, CR_TXP);
+ wbflush();
+ break;
+ }
+ }
+ }
+
+ sc->mtd_hw = mtd_hw;
+ return;
+}
+
+/*
+ * Receive interrupt routine
+ */
+hide void
+sonicrxint(sc)
+ struct snc_softc *sc;
+{
+ u_int32_t rda;
+ int orra;
+ int len;
+ int rramark;
+ int rdamark;
+ u_int16_t rxpkt_ptr;
+
+ rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
+
+ while (SRO(sc, rda, RXPKT_INUSE) == 0) {
+ u_int status = SRO(sc, rda, RXPKT_STATUS);
+
+ orra = RBASEQ(SRO(sc, rda, RXPKT_SEQNO)) & RRAMASK;
+ rxpkt_ptr = SRO(sc, rda, RXPKT_PTRLO);
+ /*
+ * Do not trunc ether_header length.
+ * Our sonic_read() and sonic_get() require it.
+ */
+ len = SRO(sc, rda, RXPKT_BYTEC) - FCSSIZE;
+ if (status & RCR_PRX) {
+ /* XXX: Does PGOFSET require? */
+ u_int32_t pkt =
+ sc->rbuf[orra & RBAMASK] + (rxpkt_ptr & PGOFSET);
+ if (sonic_read(sc, pkt, len))
+ sc->sc_if.if_ipackets++;
+ else
+ sc->sc_if.if_ierrors++;
+ } else
+ sc->sc_if.if_ierrors++;
+
+ /*
+ * give receive buffer area back to chip.
+ *
+ * If this was the last packet in the RRA, give the RRA to
+ * the chip again.
+ * If sonic read didnt copy it out then we would have to
+ * wait !!
+ * (dont bother add it back in again straight away)
+ *
+ * Really, we're doing v_rra[rramark] = v_rra[orra] but
+ * we have to use the macros because SONIC might be in
+ * 16 or 32 bit mode.
+ */
+ if (status & RCR_LPKT) {
+ u_int32_t tmp1, tmp2;
+
+ rramark = sc->sc_rramark;
+ tmp1 = sc->v_rra[rramark];
+ tmp2 = sc->v_rra[orra];
+ SWO(sc, tmp1, RXRSRC_PTRLO,
+ SRO(sc, tmp2, RXRSRC_PTRLO));
+ SWO(sc, tmp1, RXRSRC_PTRHI,
+ SRO(sc, tmp2, RXRSRC_PTRHI));
+ SWO(sc, tmp1, RXRSRC_WCLO,
+ SRO(sc, tmp2, RXRSRC_WCLO));
+ SWO(sc, tmp1, RXRSRC_WCHI,
+ SRO(sc, tmp2, RXRSRC_WCHI));
+
+ /* zap old rra for fun */
+ SWO(sc, tmp2, RXRSRC_WCHI, 0);
+ SWO(sc, tmp2, RXRSRC_WCLO, 0);
+
+ sc->sc_rramark = (++rramark) & RRAMASK;
+ NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[rramark]));
+ wbflush();
+ }
+
+ /*
+ * give receive descriptor back to chip simple
+ * list is circular
+ */
+ rdamark = sc->sc_rdamark;
+ SWO(sc, rda, RXPKT_INUSE, 1);
+ SWO(sc, rda, RXPKT_RLINK,
+ SRO(sc, rda, RXPKT_RLINK) | EOL);
+ SWO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))), RXPKT_RLINK,
+ SRO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))),
+ RXPKT_RLINK) & ~EOL);
+ sc->sc_rdamark = sc->sc_rxmark;
+
+ if (++sc->sc_rxmark >= sc->sc_nrda)
+ sc->sc_rxmark = 0;
+ rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
+ }
+}
+
+/*
+ * sonic_read -- pull packet off interface and forward to
+ * appropriate protocol handler
+ */
+hide int
+sonic_read(sc, pkt, len)
+ struct snc_softc *sc;
+ u_int32_t pkt;
+ int len;
+{
+ struct ifnet *ifp = &sc->sc_if;
+ struct ether_header *et;
+ struct mbuf *m;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+ device_printf(sc->sc_dev,
+ "invalid packet length %d bytes\n", len);
+ return (0);
+ }
+
+ /* Pull packet off interface. */
+ m = sonic_get(sc, pkt, len);
+ if (m == 0) {
+ return (0);
+ }
+
+ /* We assume that the header fit entirely in one mbuf. */
+ et = mtod(m, struct ether_header *);
+
+#ifdef SNCDEBUG
+ if ((sncdebug & SNC_SHOWRXHDR) != 0)
+ {
+ device_printf(sc->sc_dev, "rcvd 0x%x len=%d type=0x%x from %6D",
+ pkt, len, htons(et->ether_type),
+ et->ether_shost, ":");
+ printf(" (to %6D)\n", et->ether_dhost, ":");
+ }
+#endif /* SNCDEBUG */
+
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, et, m);
+ return (1);
+}
+
+
+/*
+ * munge the received packet into an mbuf chain
+ */
+hide struct mbuf *
+sonic_get(sc, pkt, datalen)
+ struct snc_softc *sc;
+ u_int32_t pkt;
+ int datalen;
+{
+ struct mbuf *m, *top, **mp;
+ int len;
+ /*
+ * Do not trunc ether_header length.
+ * Our sonic_read() and sonic_get() require it.
+ */
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ m->m_pkthdr.len = datalen;
+ len = MHLEN;
+ top = 0;
+ mp = &top;
+
+ while (datalen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ len = MLEN;
+ }
+ if (datalen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ if (top) m_freem(top);
+ return (0);
+ }
+ len = MCLBYTES;
+ }
+#if 0
+ /* XXX: Require? */
+ if (!top) {
+ register int pad =
+ ALIGN(sizeof(struct ether_header)) -
+ sizeof(struct ether_header);
+ m->m_data += pad;
+ len -= pad;
+ }
+#endif
+ m->m_len = len = min(datalen, len);
+
+ (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), pkt, len);
+ pkt += len;
+ datalen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}
+/*
+ * Enable power on the interface.
+ */
+int
+snc_enable(sc)
+ struct snc_softc *sc;
+{
+
+#ifdef SNCDEBUG
+ device_printf(sc->sc_dev, "snc_enable()\n");
+#endif /* SNCDEBUG */
+
+ if (sc->sc_enabled == 0 && sc->sc_enable != NULL) {
+ if ((*sc->sc_enable)(sc) != 0) {
+ device_printf(sc->sc_dev, "device enable failed\n");
+ return (EIO);
+ }
+ }
+
+ sc->sc_enabled = 1;
+ return (0);
+}
+
+/*
+ * Disable power on the interface.
+ */
+void
+snc_disable(sc)
+ struct snc_softc *sc;
+{
+
+#ifdef SNCDEBUG
+ device_printf(sc->sc_dev, "snc_disable()\n");
+#endif /* SNCDEBUG */
+
+ if (sc->sc_enabled != 0 && sc->sc_disable != NULL) {
+ (*sc->sc_disable)(sc);
+ sc->sc_enabled = 0;
+ }
+}
+
+
diff --git a/sys/dev/snc/dp83932reg.h b/sys/dev/snc/dp83932reg.h
new file mode 100644
index 0000000..b72fe86
--- /dev/null
+++ b/sys/dev/snc/dp83932reg.h
@@ -0,0 +1,271 @@
+/* $FreeBSD$ */
+/* $NecBSD: dp83932reg.h,v 1.2 1999/02/12 05:50:13 kmatsuda Exp $ */
+/* $NetBSD: if_snreg.h,v 1.4 1997/06/15 20:20:12 scottr Exp $ */
+
+/*
+ * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
+ * You may use, copy, and modify this program so long as you retain the
+ * copyright line.
+ */
+
+/*
+ * if_snreg.h -- National Semiconductor DP8393X (SONIC) register defs
+ */
+
+/*
+ * SONIC registers as seen by the processor
+ */
+#define SNCR_CR 0x00 /* Command */
+#define SNCR_DCR 0x01 /* Data Configuration */
+#define SNCR_RCR 0x02 /* Receive Control */
+#define SNCR_TCR 0x03 /* Transmit Control */
+#define SNCR_IMR 0x04 /* Interrupt Mask */
+#define SNCR_ISR 0x05 /* Interrupt Status */
+#define SNCR_UTDA 0x06 /* Upper Transmit Descriptor Address */
+#define SNCR_CTDA 0x07 /* Current Transmit Descriptor Address */
+#define SNCR_TPS 0x08 /* Transmit Packet Size */
+#define SNCR_TFC 0x09 /* Transmit Fragment Count */
+#define SNCR_TSA0 0x0a /* Transmit Start Address 0 */
+#define SNCR_TSA1 0x0b /* Transmit Start Address 1 */
+#define SNCR_TFS 0x0c /* Transmit Fragment Size */
+#define SNCR_URDA 0x0d /* Upper Receive Descriptor Address */
+#define SNCR_CRDA 0x0e /* Current Receive Descriptor Address */
+#define SNCR_CRBA0 0x0f /* Current Receive Buffer Address 0 */
+#define SNCR_CRBA1 0x10 /* Current Receive Buffer Address 1 */
+#define SNCR_RBWC0 0x11 /* Remaining Buffer Word Count 0 */
+#define SNCR_RBWC1 0x12 /* Remaining Buffer Word Count 1 */
+#define SNCR_EOBC 0x13 /* End Of Buffer Word Count */
+#define SNCR_URRA 0x14 /* Upper Receive Resource Address */
+#define SNCR_RSA 0x15 /* Resource Start Address */
+#define SNCR_REA 0x16 /* Resource End Address */
+#define SNCR_RRP 0x17 /* Resource Read Pointer */
+#define SNCR_RWP 0x18 /* Resource Write Pointer */
+#define SNCR_TRBA0 0x19 /* Temporary Receive Buffer Address 0 */
+#define SNCR_TRBA1 0x1a /* Temporary Receive Buffer Address 1 */
+#define SNCR_TBWC0 0x1b /* Temporary Buffer Word Count 0 */
+#define SNCR_TBWC1 0x1c /* Temporary Buffer Word Count 1 */
+#define SNCR_ADDR0 0x1d /* Address Generator 0 */
+#define SNCR_ADDR1 0x1e /* Address Generator 1 */
+#define SNCR_LLFA 0x1f /* Last Link Field Address */
+#define SNCR_TTDA 0x20 /* Temp Transmit Descriptor Address */
+#define SNCR_CEP 0x21 /* CAM Entry Pointer */
+#define SNCR_CAP2 0x22 /* CAM Address Port 2 */
+#define SNCR_CAP1 0x23 /* CAM Address Port 1 */
+#define SNCR_CAP0 0x24 /* CAM Address Port 0 */
+#define SNCR_CE 0x25 /* CAM Enable */
+#define SNCR_CDP 0x26 /* CAM Descriptor Pointer */
+#define SNCR_CDC 0x27 /* CAM Descriptor Count */
+#define SNCR_SR 0x28 /* Silicon Revision */
+#define SNCR_WT0 0x29 /* Watchdog Timer 0 */
+#define SNCR_WT1 0x2a /* Watchdog Timer 1 */
+#define SNCR_RSC 0x2b /* Receive Sequence Counter */
+#define SNCR_CRCT 0x2c /* CRC Error Tally */
+#define SNCR_FAET 0x2d /* FAE Tally */
+#define SNCR_MPT 0x2e /* Missed Packet Tally */
+#define SNCR_MDT 0x2f /* Maximum Deferral Timer */
+#define SNCR_RTC 0x30 /* Receive Test Control */
+#define SNCR_TTC 0x31 /* Transmit Test Control */
+#define SNCR_DTC 0x32 /* DMA Test Control */
+#define SNCR_CC0 0x33 /* CAM Comparison 0 */
+#define SNCR_CC1 0x34 /* CAM Comparison 1 */
+#define SNCR_CC2 0x35 /* CAM Comparison 2 */
+#define SNCR_CM 0x36 /* CAM Match */
+#define SNCR_RES1 0x37 /* reserved */
+#define SNCR_RES2 0x38 /* reserved */
+#define SNCR_RBC 0x39 /* Receiver Byte Count */
+#define SNCR_RES3 0x3a /* reserved */
+#define SNCR_TBO 0x3b /* Transmitter Backoff Counter */
+#define SNCR_TRC 0x3c /* Transmitter Random Counter */
+#define SNCR_TBM 0x3d /* Transmitter Backoff Mask */
+#define SNCR_RES4 0x3e /* Reserved */
+#define SNCR_DCR2 0x3f /* Data Configuration 2 (AVF) */
+
+#define SNC_NREGS 0x40
+
+/*
+ * Register Interpretations
+ */
+
+/*
+ * The command register is used for issuing commands to the SONIC.
+ * With the exception of CR_RST, the bit is reset when the operation
+ * completes.
+ */
+#define CR_LCAM 0x0200 /* load CAM with descriptor at s_cdp */
+#define CR_RRRA 0x0100 /* read next RRA descriptor at s_rrp */
+#define CR_RST 0x0080 /* software reset */
+#define CR_ST 0x0020 /* start timer */
+#define CR_STP 0x0010 /* stop timer */
+#define CR_RXEN 0x0008 /* receiver enable */
+#define CR_RXDIS 0x0004 /* receiver disable */
+#define CR_TXP 0x0002 /* transmit packets */
+#define CR_HTX 0x0001 /* halt transmission */
+
+/*
+ * The data configuration register establishes the SONIC's bus cycle
+ * operation. This register can only be accessed when the SONIC is in
+ * reset mode (s_cr.CR_RST is set.)
+ */
+#define DCR_EXBUS 0x8000 /* extended bus mode (AVF) */
+#define DCR_LBR 0x2000 /* latched bus retry */
+#define DCR_PO1 0x1000 /* programmable output 1 */
+#define DCR_PO0 0x0800 /* programmable output 0 */
+#define DCR_STERM 0x0400 /* synchronous termination */
+#define DCR_USR1 0x0200 /* reflects USR1 input pin */
+#define DCR_USR0 0x0100 /* reflects USR0 input pin */
+#define DCR_WC1 0x0080 /* wait state control 1 */
+#define DCR_WC0 0x0040 /* wait state control 0 */
+#define DCR_DW 0x0020 /* data width select */
+#define DCR_BMS 0x0010 /* DMA block mode select */
+#define DCR_RFT1 0x0008 /* receive FIFO threshold control 1 */
+#define DCR_RFT0 0x0004 /* receive FIFO threshold control 0 */
+#define DCR_TFT1 0x0002 /* transmit FIFO threshold control 1 */
+#define DCR_TFT0 0x0001 /* transmit FIFO threshold control 0 */
+
+/* data configuration register aliases */
+#define DCR_SYNC DCR_STERM /* synchronous (memory cycle 2 clocks) */
+#define DCR_ASYNC 0 /* asynchronous (memory cycle 3 clocks) */
+
+#define DCR_WAIT0 0 /* 0 wait states added */
+#define DCR_WAIT1 DCR_WC0 /* 1 wait state added */
+#define DCR_WAIT2 DCR_WC1 /* 2 wait states added */
+#define DCR_WAIT3 (DCR_WC1|DCR_WC0) /* 3 wait states added */
+
+#define DCR_DW16 0 /* use 16-bit DMA accesses */
+#define DCR_DW32 DCR_DW /* use 32-bit DMA accesses */
+
+#define DCR_DMAEF 0 /* DMA until TX/RX FIFO has emptied/filled */
+#define DCR_DMABLOCK DCR_BMS /* DMA until RX/TX threshold crossed */
+
+#define DCR_RFT4 0 /* receive threshold 4 bytes */
+#define DCR_RFT8 DCR_RFT0 /* receive threshold 8 bytes */
+#define DCR_RFT16 DCR_RFT1 /* receive threshold 16 bytes */
+#define DCR_RFT24 (DCR_RFT1|DCR_RFT0) /* receive threshold 24 bytes */
+
+#define DCR_TFT8 0 /* transmit threshold 8 bytes */
+#define DCR_TFT16 DCR_TFT0 /* transmit threshold 16 bytes */
+#define DCR_TFT24 DCR_TFT1 /* transmit threshold 24 bytes */
+#define DCR_TFT28 (DCR_TFT1|DCR_TFT0) /* transmit threshold 28 bytes */
+
+/*
+ * The receive control register is used to filter incoming packets and
+ * provides status information on packets received.
+ * The contents of the register are copied into the RXpkt.status field
+ * when a packet is received. RCR_MC - RCR_PRX are then reset.
+ */
+#define RCR_ERR 0x8000 /* accept packets with CRC errors */
+#define RCR_RNT 0x4000 /* accept runt (length < 64) packets */
+#define RCR_BRD 0x2000 /* accept broadcast packets */
+#define RCR_PRO 0x1000 /* accept all physical address packets */
+#define RCR_AMC 0x0800 /* accept all multicast packets */
+#define RCR_LB1 0x0400 /* loopback control 1 */
+#define RCR_LB0 0x0200 /* loopback control 0 */
+#define RCR_MC 0x0100 /* multicast packet received */
+#define RCR_BC 0x0080 /* broadcast packet received */
+#define RCR_LPKT 0x0040 /* last packet in RBA (RBWC < EOBC) */
+#define RCR_CRS 0x0020 /* carrier sense activity */
+#define RCR_COL 0x0010 /* collision activity */
+#define RCR_CRC 0x0008 /* CRC error */
+#define RCR_FAE 0x0004 /* frame alignment error */
+#define RCR_LBK 0x0002 /* loopback packet received */
+#define RCR_PRX 0x0001 /* packet received without errors */
+
+/* receiver control register aliases */
+/* the loopback control bits provide the following options */
+#define RCR_LBNONE 0 /* no loopback - normal operation */
+#define RCR_LBMAC RCR_LB0 /* MAC loopback */
+#define RCR_LBENDEC RCR_LB1 /* ENDEC loopback */
+#define RCR_LBTRANS (RCR_LB1|RCR_LB0) /* transceiver loopback */
+
+/*
+ * The transmit control register controls the SONIC's transmit operations.
+ * TCR_PINT - TCR_EXDIS are loaded from the TXpkt.config field at the
+ * start of transmission. TCR_EXD-TCR_PTX are cleared at the beginning
+ * of transmission and updated when the transmission is completed.
+ */
+#define TCR_PINT 0x8000 /* interrupt when transmission starts */
+#define TCR_POWC 0x4000 /* program out of window collision timer */
+#define TCR_CRCI 0x2000 /* transmit packet without 4 byte FCS */
+#define TCR_EXDIS 0x1000 /* disable excessive deferral timer */
+#define TCR_EXD 0x0400 /* excessive deferrals occurred (>3.2ms) */
+#define TCR_DEF 0x0200 /* deferred transmissions occurred */
+#define TCR_NCRS 0x0100 /* carrier not present during transmission */
+#define TCR_CRSL 0x0080 /* carrier lost during transmission */
+#define TCR_EXC 0x0040 /* excessive collisions (>16) detected */
+#define TCR_OWC 0x0020 /* out of window (bad) collision occurred */
+#define TCR_PMB 0x0008 /* packet monitored bad - the tansmitted
+ * packet had a bad source address or CRC */
+#define TCR_FU 0x0004 /* FIFO underrun (memory access failed) */
+#define TCR_BCM 0x0002 /* byte count mismatch (TXpkt.pkt_size
+ * != sum(TXpkt.frag_size) */
+#define TCR_PTX 0x0001 /* packet transmitted without errors */
+#define TCR_NC 0xf000 /* after transmission, # of colls */
+
+/* transmit control register aliases */
+#define TCR_OWCSFD 0 /* start after start of frame delimiter */
+#define TCR_OWCPRE TCR_POWC /* start after first bit of preamble */
+
+
+/*
+ * The interrupt mask register masks the interrupts that
+ * are generated from the interrupt status register.
+ * All reserved bits should be written with 0.
+ */
+#define IMR_BREN 0x4000 /* bus retry occurred enable */
+#define IMR_HBLEN 0x2000 /* heartbeat lost enable */
+#define IMR_LCDEN 0x1000 /* load CAM done interrupt enable */
+#define IMR_PINTEN 0x0800 /* programmable interrupt enable */
+#define IMR_PRXEN 0x0400 /* packet received enable */
+#define IMR_PTXEN 0x0200 /* packet transmitted enable */
+#define IMR_TXEREN 0x0100 /* transmit error enable */
+#define IMR_TCEN 0x0080 /* timer complete enable */
+#define IMR_RDEEN 0x0040 /* receive descriptors exhausted enable */
+#define IMR_RBEEN 0x0020 /* receive buffers exhausted enable */
+#define IMR_RBAEEN 0x0010 /* receive buffer area exceeded enable */
+#define IMR_CRCEN 0x0008 /* CRC tally counter rollover enable */
+#define IMR_FAEEN 0x0004 /* FAE tally counter rollover enable */
+#define IMR_MPEN 0x0002 /* MP tally counter rollover enable */
+#define IMR_RFOEN 0x0001 /* receive FIFO overrun enable */
+
+
+/*
+ * The interrupt status register indicates the source of an interrupt when
+ * the INT pin goes active. The interrupt is acknowledged by writing
+ * the appropriate bit(s) in this register.
+ */
+#define ISR_ALL 0x7fff /* all interrupts */
+#define ISR_BR 0x4000 /* bus retry occurred */
+#define ISR_HBL 0x2000 /* CD heartbeat lost */
+#define ISR_LCD 0x1000 /* load CAM command has completed */
+#define ISR_PINT 0x0800 /* programmed interrupt from TXpkt.config */
+#define ISR_PKTRX 0x0400 /* packet received */
+#define ISR_TXDN 0x0200 /* no remaining packets to be transmitted */
+#define ISR_TXER 0x0100 /* packet transmission caused error */
+#define ISR_TC 0x0080 /* timer complete */
+#define ISR_RDE 0x0040 /* receive descriptors exhausted */
+#define ISR_RBE 0x0020 /* receive buffers exhausted */
+#define ISR_RBAE 0x0010 /* receive buffer area exceeded */
+#define ISR_CRC 0x0008 /* CRC tally counter rollover */
+#define ISR_FAE 0x0004 /* FAE tally counter rollover */
+#define ISR_MP 0x0002 /* MP tally counter rollover */
+#define ISR_RFO 0x0001 /* receive FIFO overrun */
+
+/*
+ * The second data configuration register allows additional user defined
+ * pins to be controlled. These bits are only available if s_dcr.DCR_EXBUS
+ * is set.
+ */
+#define DCR2_EXPO3 0x8000 /* EXUSR3 output */
+#define DCR2_EXPO2 0x4000 /* EXUSR2 output */
+#define DCR2_EXPO1 0x2000 /* EXUSR1 output */
+#define DCR2_EXPO0 0x1000 /* EXUSR0 output */
+#define DCR2_HD 0x0800 /* heart beat disable (83934/83936) */
+#define DCR2_JD 0x0200 /* TPI jabber timer disable (83934/83936) */
+#define DCR2_AUTO 0x0100 /* AUI/TPI auto selection (83934/83936) */
+#define DCR2_XWRAP 0x0040 /* TPI transceiver loopback (83934/83936) */
+#define DCR2_FD 0x0020 /* full duplex (83936) */
+#define DCR2_PHL 0x0010 /* extend HOLD signal by 1/2 clock */
+#define DCR2_LRDY 0x0008 /* set latched ready mode */
+#define DCR2_PCM 0x0004 /* packet compress on match */
+#define DCR2_PCNM 0x0002 /* packet compress on mismatch */
+#define DCR2_RJM 0x0001 /* reject on match */
diff --git a/sys/dev/snc/dp83932subr.c b/sys/dev/snc/dp83932subr.c
new file mode 100644
index 0000000..65b9de9
--- /dev/null
+++ b/sys/dev/snc/dp83932subr.c
@@ -0,0 +1,902 @@
+/* $FreeBSD$ */
+/* $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Kouichi Matsuda. 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 Kouichi Matsuda for
+ * NetBSD/pc98.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R
+ * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda.
+ *
+ * These cards use National Semiconductor DP83934AVQB as Ethernet Controller
+ * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM.
+ */
+
+/*
+ * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_inarp.h>
+#endif
+
+#include <net/bpf.h>
+
+#include <sys/bus.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+
+#include <dev/snc/dp83932reg.h>
+#include <dev/snc/dp83932var.h>
+#include <dev/snc/if_sncreg.h>
+#include <dev/snc/dp83932subr.h>
+
+integrate u_int16_t snc_nec16_select_bank
+ __P((struct snc_softc *, u_int32_t, u_int32_t));
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
+int
+sncsetup(sc, lladdr)
+ struct snc_softc *sc;
+ u_int8_t *lladdr;
+{
+ u_int32_t p, pp;
+ int i;
+ int offset;
+
+ /*
+ * Put the pup in reset mode (sncinit() will fix it later),
+ * stop the timer, disable all interrupts and clear any interrupts.
+ */
+ NIC_PUT(sc, SNCR_CR, CR_STP);
+ wbflush();
+ NIC_PUT(sc, SNCR_CR, CR_RST);
+ wbflush();
+ NIC_PUT(sc, SNCR_IMR, 0);
+ wbflush();
+ NIC_PUT(sc, SNCR_ISR, ISR_ALL);
+ wbflush();
+
+ /*
+ * because the SONIC is basically 16bit device it 'concatenates'
+ * a higher buffer address to a 16 bit offset--this will cause wrap
+ * around problems near the end of 64k !!
+ */
+ p = pp = 0;
+
+ for (i = 0; i < NRRA; i++) {
+ sc->v_rra[i] = SONIC_GETDMA(p);
+ p += RXRSRC_SIZE(sc);
+ }
+ sc->v_rea = SONIC_GETDMA(p);
+
+ p = SOALIGN(sc, p);
+
+ sc->v_cda = SONIC_GETDMA(p);
+ p += CDA_SIZE(sc);
+
+ p = SOALIGN(sc, p);
+
+ for (i = 0; i < NTDA; i++) {
+ struct mtd *mtdp = &sc->mtda[i];
+ mtdp->mtd_vtxp = SONIC_GETDMA(p);
+ p += TXP_SIZE(sc);
+ }
+
+ p = SOALIGN(sc, p);
+
+ if ((p - pp) > NBPG) {
+ device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +"
+ "TDA (%ld) > NBPG (%d). Punt!\n",
+ (ulong)sc->v_cda - (ulong)sc->v_rra[0],
+ (ulong)sc->mtda[0].mtd_vtxp - (ulong)sc->v_cda,
+ (ulong)p - (ulong)sc->mtda[0].mtd_vtxp,
+ NBPG);
+ return(1);
+ }
+
+ p = pp + NBPG;
+ pp = p;
+
+ sc->sc_nrda = NBPG / RXPKT_SIZE(sc);
+ sc->v_rda = SONIC_GETDMA(p);
+
+ p = pp + NBPG;
+
+ for (i = 0; i < NRBA; i++) {
+ sc->rbuf[i] = p;
+ p += NBPG;
+ }
+
+ pp = p;
+ offset = TXBSIZE;
+ for (i = 0; i < NTDA; i++) {
+ struct mtd *mtdp = &sc->mtda[i];
+
+ mtdp->mtd_vbuf = SONIC_GETDMA(p);
+ offset += TXBSIZE;
+ if (offset < NBPG) {
+ p += TXBSIZE;
+ } else {
+ p = pp + NBPG;
+ pp = p;
+ offset = TXBSIZE;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * miscellaneous NEC/SONIC detect functions.
+ */
+
+/*
+ * check if a specified irq is acceptable.
+ */
+u_int8_t
+snc_nec16_validate_irq(irq)
+ int irq;
+{
+ const u_int8_t encoded_irq[16] = {
+ -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1
+ };
+
+ return encoded_irq[irq];
+}
+
+/*
+ * specify irq to board.
+ */
+int
+snc_nec16_register_irq(sc, irq)
+ struct snc_softc *sc;
+ int irq;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t encoded_irq;
+
+ encoded_irq = snc_nec16_validate_irq(irq);
+ if (encoded_irq == (u_int8_t) -1) {
+ printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq);
+ return 0;
+ }
+
+ /* select SNECR_IRQSEL register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL);
+ /* write encoded irq value */
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq);
+
+ return 1;
+}
+
+/*
+ * check if a specified memory base address is acceptable.
+ */
+int
+snc_nec16_validate_mem(maddr)
+ int maddr;
+{
+
+ /* Check on Normal mode with max range, only */
+ if ((maddr & ~0x1E000) != 0xC0000) {
+ printf("snc_nec16_validate_mem: "
+ "unsupported window base (0x%x)\n", maddr);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * specify memory base address to board and map to first bank.
+ */
+int
+snc_nec16_register_mem(sc, maddr)
+ struct snc_softc *sc;
+ int maddr;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ if (snc_nec16_validate_mem(maddr) == 0)
+ return 0;
+
+ /* select SNECR_MEMSEL register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL);
+ /* write encoded memory base select value */
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr));
+
+ /*
+ * set current bank to 0 (bottom) and map
+ */
+ /* select SNECR_MEMBS register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN);
+ /* set current bank to 0 */
+ sc->curbank = 0;
+
+ return 1;
+}
+
+int
+snc_nec16_check_memory(iot, ioh, memt, memh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_space_tag_t memt;
+ bus_space_handle_t memh;
+{
+ u_int16_t val;
+ int i, j;
+
+ val = 0;
+ for (i = 0; i < SNEC_NBANK; i++) {
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
+
+ /* write test pattern */
+ for (j = 0; j < SNEC_NMEMS / 2; j++) {
+ bus_space_write_2(memt, memh, j * 2, val + j);
+ }
+ val += 0x1000;
+ }
+
+ val = 0;
+ for (i = 0; i < SNEC_NBANK; i++) {
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
+
+ /* read test pattern */
+ for (j = 0; j < SNEC_NMEMS / 2; j++) {
+ if (bus_space_read_2(memt, memh, j * 2) != val + j)
+ break;
+ }
+
+ if (j < SNEC_NMEMS / 2) {
+ printf("snc_nec16_check_memory: "
+ "memory check failed at 0x%04x%04x"
+ "val 0x%04x != expected 0x%04x\n", i, j,
+ bus_space_read_2(memt, memh, j * 2),
+ val + j);
+ return 0;
+ }
+ val += 0x1000;
+ }
+
+ /* zero clear mem */
+ for (i = 0; i < SNEC_NBANK; i++) {
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
+
+ bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2);
+ }
+
+ /* again read test if these are 0 */
+ for (i = 0; i < SNEC_NBANK; i++) {
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
+
+ /* check if cleared */
+ for (j = 0; j < SNEC_NMEMS; j += 2) {
+ if (bus_space_read_2(memt, memh, j) != 0)
+ break;
+ }
+
+ if (j != SNEC_NMEMS) {
+ printf("snc_nec16_check_memory: "
+ "memory zero clear failed at 0x%04x%04x\n", i, j);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int
+snc_nec16_detectsubr(iot, ioh, memt, memh, irq, maddr, type)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_space_tag_t memt;
+ bus_space_handle_t memh;
+ int irq;
+ int maddr;
+ u_int8_t type;
+{
+ u_int16_t cr;
+ u_int8_t ident;
+ int rv = 0;
+
+ if (snc_nec16_validate_irq(irq) == (u_int8_t) -1)
+ return 0;
+ /* XXX: maddr already checked */
+ if (snc_nec16_validate_mem(maddr) == 0)
+ return 0;
+
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT);
+ ident = bus_space_read_1(iot, ioh, SNEC_CTRLB);
+ if (ident == 0xff || ident == 0x00) {
+ /* not found */
+ return 0;
+ }
+
+ switch (type) {
+ case SNEC_TYPE_LEGACY:
+ rv = (ident == SNECR_IDENT_LEGACY_CBUS);
+ break;
+ case SNEC_TYPE_PNP:
+ rv = ((ident == SNECR_IDENT_PNP_CBUS) ||
+ (ident == SNECR_IDENT_PNP_PCMCIABUS));
+ break;
+ default:
+ break;
+ }
+
+ if (rv == 0) {
+ printf("snc_nec16_detectsubr: parent bus mismatch\n");
+ return 0;
+ }
+
+ /* select SONIC register SNCR_CR */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR);
+ bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST);
+ delay(400);
+
+ cr = bus_space_read_2(iot, ioh, SNEC_CTRL);
+ if (cr != (CR_RXDIS | CR_STP | CR_RST)) {
+#ifdef DIAGNOSTIC
+ printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n",
+ cr);
+#endif
+ return 0;
+ }
+
+ if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0)
+ return 0;
+
+ return 1;
+}
+
+/* XXX */
+#define SNC_VENDOR_NEC 0x00004c
+#define SNC_NEC_SERIES_LEGACY_CBUS 0xa5
+#define SNC_NEC_SERIES_PNP_PCMCIA 0xd5
+#define SNC_NEC_SERIES_PNP_PCMCIA2 0x6d /* XXX */
+#define SNC_NEC_SERIES_PNP_CBUS 0x0d
+#define SNC_NEC_SERIES_PNP_CBUS2 0x3d
+
+u_int8_t *
+snc_nec16_detect_type(myea)
+ u_int8_t *myea;
+{
+ u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2];
+ u_int8_t series = myea[3];
+ u_int8_t type = myea[4] & 0x80;
+ u_int8_t *typestr;
+
+ switch (vendor) {
+ case SNC_VENDOR_NEC:
+ switch (series) {
+ case SNC_NEC_SERIES_LEGACY_CBUS:
+ if (type)
+ typestr = "NEC PC-9801-84";
+ else
+ typestr = "NEC PC-9801-83";
+ break;
+ case SNC_NEC_SERIES_PNP_CBUS:
+ case SNC_NEC_SERIES_PNP_CBUS2:
+ if (type)
+ typestr = "NEC PC-9801-104";
+ else
+ typestr = "NEC PC-9801-103";
+ break;
+ case SNC_NEC_SERIES_PNP_PCMCIA:
+ case SNC_NEC_SERIES_PNP_PCMCIA2:
+ /* XXX: right ? */
+ if (type)
+ typestr = "NEC PC-9801N-J02R";
+ else
+ typestr = "NEC PC-9801N-J02";
+ break;
+ default:
+ typestr = "NEC unknown (PC-9801N-25?)";
+ break;
+ }
+ break;
+ default:
+ typestr = "unknown (3rd vendor?)";
+ break;
+ }
+
+ return typestr;
+}
+
+int
+snc_nec16_get_enaddr(iot, ioh, myea)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ u_int8_t *myea;
+{
+ u_int8_t eeprom[SNEC_EEPROM_SIZE];
+ u_int8_t rom_sum, sum = 0x00;
+ int i;
+
+ snc_nec16_read_eeprom(iot, ioh, eeprom);
+
+ for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) {
+ sum = sum ^ eeprom[i];
+ }
+
+ rom_sum = eeprom[SNEC_EEPROM_CKSUM];
+
+ if (sum != rom_sum) {
+ printf("snc_nec16_get_enaddr: "
+ "checksum mismatch; calculated %02x != read %02x",
+ sum, rom_sum);
+ return 0;
+ }
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ myea[i] = eeprom[SNEC_EEPROM_SA0 + i];
+
+ return 1;
+}
+
+/*
+ * read from NEC/SONIC NIC register.
+ */
+u_int16_t
+snc_nec16_nic_get(sc, reg)
+ struct snc_softc *sc;
+ u_int8_t reg;
+{
+ u_int16_t val;
+
+ /* select SONIC register */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
+ val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL);
+
+ return val;
+}
+
+/*
+ * write to NEC/SONIC NIC register.
+ */
+void
+snc_nec16_nic_put(sc, reg, val)
+ struct snc_softc *sc;
+ u_int8_t reg;
+ u_int16_t val;
+{
+
+ /* select SONIC register */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val);
+}
+
+
+/*
+ * select memory bank and map
+ * where exists specified (internal buffer memory) offset.
+ */
+integrate u_int16_t
+snc_nec16_select_bank(sc, base, offset)
+ struct snc_softc *sc;
+ u_int32_t base;
+ u_int32_t offset;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t bank;
+ u_int16_t noffset;
+
+ /* bitmode is fixed to 16 bit. */
+ bank = (base + offset * 2) >> 13;
+ noffset = (base + offset * 2) & (SNEC_NMEMS - 1);
+
+#ifdef SNCDEBUG
+ if (noffset % 2) {
+ device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n",
+ noffset);
+ }
+#endif /* SNCDEBUG */
+
+ if (sc->curbank != bank) {
+ /* select SNECR_MEMBS register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
+ /* select new bank */
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN);
+ /* update current bank */
+ sc->curbank = bank;
+ }
+
+ return noffset;
+}
+
+/*
+ * write to SONIC descriptors.
+ */
+void
+snc_nec16_writetodesc(sc, base, offset, val)
+ struct snc_softc *sc;
+ u_int32_t base;
+ u_int32_t offset;
+ u_int16_t val;
+{
+ bus_space_tag_t memt = sc->sc_memt;
+ bus_space_handle_t memh = sc->sc_memh;
+ u_int16_t noffset;
+
+ noffset = snc_nec16_select_bank(sc, base, offset);
+
+ bus_space_write_2(memt, memh, noffset, val);
+}
+
+/*
+ * read from SONIC descriptors.
+ */
+u_int16_t
+snc_nec16_readfromdesc(sc, base, offset)
+ struct snc_softc *sc;
+ u_int32_t base;
+ u_int32_t offset;
+{
+ bus_space_tag_t memt = sc->sc_memt;
+ bus_space_handle_t memh = sc->sc_memh;
+ u_int16_t noffset;
+
+ noffset = snc_nec16_select_bank(sc, base, offset);
+
+ return bus_space_read_2(memt, memh, noffset);
+}
+
+/*
+ * read from SONIC data buffer.
+ */
+void
+snc_nec16_copyfrombuf(sc, dst, offset, size)
+ struct snc_softc *sc;
+ void *dst;
+ u_int32_t offset;
+ size_t size;
+{
+ bus_space_tag_t memt = sc->sc_memt;
+ bus_space_handle_t memh = sc->sc_memh;
+ u_int16_t noffset;
+ u_int8_t* bptr = dst;
+
+ noffset = snc_nec16_select_bank(sc, offset, 0);
+
+ /* XXX: should check if offset + size < 0x2000. */
+
+ bus_space_barrier(memt, memh, noffset, size,
+ BUS_SPACE_BARRIER_READ);
+
+ if (size > 3) {
+ if (noffset & 3) {
+ size_t asize = (~noffset & 3);
+
+ bus_space_read_region_1(memt, memh, noffset,
+ bptr, asize);
+ bptr += asize;
+ noffset += asize;
+ size -= asize;
+ }
+ bus_space_read_region_4(memt, memh, noffset,
+ (u_int32_t *) bptr, size >> 2);
+ bptr += size & ~3;
+ noffset += size & ~3;
+ size &= 3;
+ }
+ if (size)
+ bus_space_read_region_1(memt, memh, noffset, bptr, size);
+}
+
+/*
+ * write to SONIC data buffer.
+ */
+void
+snc_nec16_copytobuf(sc, src, offset, size)
+ struct snc_softc *sc;
+ void *src;
+ u_int32_t offset;
+ size_t size;
+{
+ bus_space_tag_t memt = sc->sc_memt;
+ bus_space_handle_t memh = sc->sc_memh;
+ u_int16_t noffset, onoffset;
+ size_t osize = size;
+ u_int8_t* bptr = src;
+
+ noffset = snc_nec16_select_bank(sc, offset, 0);
+ onoffset = noffset;
+
+ /* XXX: should check if offset + size < 0x2000. */
+
+ if (size > 3) {
+ if (noffset & 3) {
+ size_t asize = (~noffset & 3);
+
+ bus_space_write_region_1(memt, memh, noffset,
+ bptr, asize);
+ bptr += asize;
+ noffset += asize;
+ size -= asize;
+ }
+ bus_space_write_region_4(memt, memh, noffset,
+ (u_int32_t *)bptr, size >> 2);
+ bptr += size & ~3;
+ noffset += size & ~3;
+ size -= size & ~3;
+ }
+ if (size)
+ bus_space_write_region_1(memt, memh, noffset, bptr, size);
+
+ bus_space_barrier(memt, memh, onoffset, osize,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+/*
+ * write (fill) 0 to SONIC data buffer.
+ */
+void
+snc_nec16_zerobuf(sc, offset, size)
+ struct snc_softc *sc;
+ u_int32_t offset;
+ size_t size;
+{
+ bus_space_tag_t memt = sc->sc_memt;
+ bus_space_handle_t memh = sc->sc_memh;
+ u_int16_t noffset, onoffset;
+ size_t osize = size;
+
+ noffset = snc_nec16_select_bank(sc, offset, 0);
+ onoffset = noffset;
+
+ /* XXX: should check if offset + size < 0x2000. */
+
+ if (size > 3) {
+ if (noffset & 3) {
+ size_t asize = (~noffset & 3);
+
+ bus_space_set_region_1(memt, memh, noffset, 0, asize);
+ noffset += asize;
+ size -= asize;
+ }
+ bus_space_set_region_4(memt, memh, noffset, 0, size >> 2);
+ noffset += size & ~3;
+ size -= size & ~3;
+ }
+ if (size)
+ bus_space_set_region_1(memt, memh, noffset, 0, size);
+
+ bus_space_barrier(memt, memh, onoffset, osize,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+
+/*
+ * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83,
+ * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98.
+ * Ported by Kouichi Matsuda.
+ *
+ * This algorism is generic to read data sequentially from 4-Wire
+ * Microwire Serial EEPROM.
+ */
+
+#define SNEC_EEP_DELAY 1000
+
+void
+snc_nec16_read_eeprom(iot, ioh, data)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ u_int8_t *data;
+{
+ u_int8_t n, val, bit;
+
+ /* Read bytes from EEPROM; two bytes per an iteration. */
+ for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) {
+ /* select SNECR_EEP */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
+ delay(SNEC_EEP_DELAY);
+
+ /* Start EEPROM access. */
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_DI);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_DI);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK);
+ delay(SNEC_EEP_DELAY);
+
+ /* Pass the iteration count to the chip. */
+ for (bit = 0x20; bit != 0x00; bit >>= 1) {
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS |
+ ((n & bit) ? SNECR_EEP_DI : 0x00));
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK |
+ ((n & bit) ? SNECR_EEP_DI : 0x00));
+ delay(SNEC_EEP_DELAY);
+ }
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
+ (void) bus_space_read_1(iot, ioh, SNEC_CTRLB); /* ACK */
+ delay(SNEC_EEP_DELAY);
+
+ /* Read a byte. */
+ val = 0;
+ for (bit = 0x80; bit != 0x00; bit >>= 1) {
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
+
+ if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
+ val |= bit;
+ }
+ *data++ = val;
+
+ /* Read one more byte. */
+ val = 0;
+ for (bit = 0x80; bit != 0x00; bit >>= 1) {
+ bus_space_write_1(iot, ioh, SNEC_CTRLB,
+ SNECR_EEP_CS | SNECR_EEP_SK);
+ delay(SNEC_EEP_DELAY);
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
+
+ if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
+ val |= bit;
+ }
+ *data++ = val;
+
+ bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
+ delay(SNEC_EEP_DELAY);
+ }
+
+#ifdef SNCDEBUG
+ /* Report what we got. */
+ data -= SNEC_EEPROM_SIZE;
+ log(LOG_INFO, "%s: EEPROM:"
+ " %02x%02x%02x%02x %02x%02x%02x%02x -"
+ " %02x%02x%02x%02x %02x%02x%02x%02x -"
+ " %02x%02x%02x%02x %02x%02x%02x%02x -"
+ " %02x%02x%02x%02x %02x%02x%02x%02x\n",
+ "snc_nec16_read_eeprom",
+ data[ 0], data[ 1], data[ 2], data[ 3],
+ data[ 4], data[ 5], data[ 6], data[ 7],
+ data[ 8], data[ 9], data[10], data[11],
+ data[12], data[13], data[14], data[15],
+ data[16], data[17], data[18], data[19],
+ data[20], data[21], data[22], data[23],
+ data[24], data[25], data[26], data[27],
+ data[28], data[29], data[30], data[31]);
+#endif
+}
+
+#ifdef SNCDEBUG
+void
+snc_nec16_dump_reg(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ u_int8_t n;
+ u_int16_t val;
+
+ printf("SONIC registers (word):");
+ for (n = 0; n < SNC_NREGS; n++) {
+ /* select required SONIC register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, n);
+ delay(10);
+ val = bus_space_read_2(iot, ioh, SNEC_CTRL);
+ if ((n % 0x10) == 0)
+ printf("\n%04x ", val);
+ else
+ printf("%04x ", val);
+ }
+ printf("\n");
+
+ printf("NEC/SONIC registers (byte):\n");
+ for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) {
+ /* select required SONIC register */
+ bus_space_write_1(iot, ioh, SNEC_ADDR, n);
+ delay(10);
+ val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB);
+ printf("%04x ", val);
+ }
+ printf("\n");
+}
+
+#endif /* SNCDEBUG */
diff --git a/sys/dev/snc/dp83932subr.h b/sys/dev/snc/dp83932subr.h
new file mode 100644
index 0000000..7bcf501
--- /dev/null
+++ b/sys/dev/snc/dp83932subr.h
@@ -0,0 +1,78 @@
+/* $FreeBSD$ */
+/* $NecBSD: dp83932subr.h,v 1.5 1999/02/02 00:47:25 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Kouichi Matsuda. 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 Kouichi Matsuda for
+ * NetBSD/pc98.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R
+ * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda.
+ *
+ * These cards use National Semiconductor DP83934AVQB as Ethernet Controller
+ * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM.
+ */
+
+int sncsetup __P((struct snc_softc *, u_int8_t *));
+
+u_int8_t snc_nec16_validate_irq __P((int));
+int snc_nec16_register_irq __P((struct snc_softc *, int));
+int snc_nec16_validate_mem __P((int));
+int snc_nec16_register_mem __P((struct snc_softc *, int));
+
+u_int16_t snc_nec16_nic_get __P((struct snc_softc *, u_int8_t));
+void snc_nec16_nic_put __P((struct snc_softc *, u_int8_t, u_int16_t));
+
+
+void snc_nec16_writetodesc
+ __P((struct snc_softc *, u_int32_t, u_int32_t, u_int16_t));
+u_int16_t snc_nec16_readfromdesc
+ __P((struct snc_softc *, u_int32_t, u_int32_t));
+
+void snc_nec16_copyfrombuf __P((struct snc_softc *, void *, u_int32_t, size_t));
+void snc_nec16_copytobuf __P((struct snc_softc *, void *, u_int32_t, size_t));
+void snc_nec16_zerobuf __P((struct snc_softc *, u_int32_t, size_t));
+
+int snc_nec16_detectsubr
+ __P((bus_space_tag_t, bus_space_handle_t, bus_space_tag_t,
+ bus_space_handle_t, int, int, u_int8_t));
+int snc_nec16_check_memory
+ __P((bus_space_tag_t, bus_space_handle_t, bus_space_tag_t,
+ bus_space_handle_t));
+
+int snc_nec16_get_enaddr
+ __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *));
+u_int8_t *snc_nec16_detect_type __P((u_int8_t *));
+void snc_nec16_read_eeprom
+ __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *));
+
+#ifdef SNCDEBUG
+void snc_nec16_dump_reg __P((bus_space_tag_t, bus_space_handle_t));
+#endif /* SNDEBUG */
diff --git a/sys/dev/snc/dp83932var.h b/sys/dev/snc/dp83932var.h
new file mode 100644
index 0000000..adcf9c8
--- /dev/null
+++ b/sys/dev/snc/dp83932var.h
@@ -0,0 +1,307 @@
+/* $FreeBSD$ */
+/* $NecBSD: dp83932var.h,v 1.3 1999/01/24 01:39:51 kmatsuda Exp $ */
+/* $NetBSD: if_snvar.h,v 1.12 1998/05/01 03:42:47 scottr Exp $ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1997, 1998, 1999
+ * Kouichi Matsuda. All rights reserved.
+ */
+/*
+ * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
+ * You may use, copy, and modify this program so long as you retain the
+ * copyright line.
+ */
+
+/*
+ * if_snvar.h -- National Semiconductor DP8393X (SONIC) NetBSD/mac68k vars
+ */
+/*
+ * Modified for NetBSD/pc98 1.2.1 from NetBSD/mac68k 1.2D by Kouichi Matsuda.
+ * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and
+ * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as
+ * Ethernet Controller and National Semiconductor NS46C46 as
+ * (64 * 16 bits) Microwire Serial EEPROM.
+ */
+
+/* borrow from arch/mac68k/dev/if_mcvar.h for debug. */
+#ifdef DDB
+#define integrate
+#define hide
+#else
+#define integrate static __inline
+#define hide static
+#endif
+
+/* NetBSD Emulation */
+#ifdef __FreeBSD__
+#ifndef NBPG
+#define NBPG PAGE_SIZE
+#endif
+#ifndef PGOFSET
+#define PGOFSET PAGE_MASK
+#endif
+typedef unsigned long ulong;
+#define delay(x) DELAY(x)
+#endif
+
+/*
+ * Vendor types
+ */
+
+/*
+ * SONIC buffers need to be aligned 16 or 32 bit aligned.
+ * These macros calculate and verify alignment.
+ */
+#define ROUNDUP(p, N) (((int) p + N - 1) & ~(N - 1))
+
+#define SOALIGN(m, array) (m ? (ROUNDUP(array, 4)) : (ROUNDUP(array, 2)))
+
+#define LOWER(x) ((unsigned)(x) & 0xffff)
+#define UPPER(x) ((unsigned)(x) >> 16)
+
+/*
+ * Memory access macros. Since we handle SONIC in 16 bit mode (PB5X0)
+ * and 32 bit mode (everything else) using a single GENERIC kernel
+ * binary, all structures have to be accessed using macros which can
+ * adjust the offsets appropriately.
+ */
+/* m is not sc->bitmode, we treat m as sc. */
+#define SWO(m, a, o, x) (*(m)->sc_writetodesc)((m), (a), (o), (x))
+#define SRO(m, a, o) (*(m)->sc_readfromdesc)((m), (a), (o))
+
+/*
+ * Register access macros. We use bus_space_* to talk to the Sonic
+ * registers. A mapping table is used in case a particular configuration
+ * hooked the regs up at non-word offsets.
+ */
+#define NIC_GET(sc, reg) (*(sc)->sc_nic_get)(sc, reg)
+#define NIC_PUT(sc, reg, val) (*(sc)->sc_nic_put)(sc, reg, val)
+
+#define SONIC_GETDMA(p) (p)
+
+/* pc98 does not have any write buffers to flush... */
+#define wbflush()
+
+/*
+ * buffer sizes in 32 bit mode
+ * 1 TXpkt is 4 hdr words + (3 * FRAGMAX) + 1 link word == 23 words == 92 bytes
+ *
+ * 1 RxPkt is 7 words == 28 bytes
+ * 1 Rda is 4 words == 16 bytes
+ *
+ * The CDA is 17 words == 68 bytes
+ *
+ * total space in page 0 = NTDA * 92 + NRRA * 16 + NRDA * 28 + 68
+ */
+
+#define NRBA 16 /* # receive buffers < NRRA */
+#define RBAMASK (NRBA-1)
+#define NTDA 16 /* # transmit descriptors */
+#define NRRA 64 /* # receive resource descriptors */
+#define RRAMASK (NRRA-1) /* the reason why NRRA must be power of two */
+
+#define FCSSIZE 4 /* size of FCS appended to packets */
+
+/*
+ * maximum receive packet size plus 2 byte pad to make each
+ * one aligned. 4 byte slop (required for eobc)
+ */
+#define RBASIZE(sc) (sizeof(struct ether_header) + ETHERMTU + FCSSIZE + \
+ ((sc)->bitmode ? 6 : 2))
+
+/*
+ * transmit buffer area
+ */
+#define TXBSIZE 1536 /* 6*2^8 -- the same size as the 8390 TXBUF */
+
+#define SN_NPAGES 2 + NRBA + (NTDA/2)
+
+typedef struct mtd {
+ u_int32_t mtd_vtxp;
+ u_int32_t mtd_vbuf;
+ struct mbuf *mtd_mbuf;
+} mtd_t;
+
+/*
+ * The snc_softc for PC-98 if_snc.
+ */
+typedef struct snc_softc {
+ struct arpcom sc_ethercom;
+#define sc_if sc_ethercom.ac_if /* network visible interface */
+
+ device_t sc_dev;
+
+ struct resource * ioport;
+ int ioport_rid;
+ struct resource * iomem;
+ int iomem_rid;
+ struct resource * irq;
+ int irq_rid;
+ void * irq_handle;
+
+ bus_space_tag_t sc_iot; /* bus identifier for io */
+ bus_space_tag_t sc_memt; /* bus identifier for mem */
+ bus_space_handle_t sc_ioh; /* io handle */
+ bus_space_handle_t sc_memh; /* bus memory handle */
+
+ int bitmode; /* 32 bit mode == 1, 16 == 0 */
+
+ u_int16_t sncr_dcr; /* DCR for this instance */
+ u_int16_t sncr_dcr2; /* DCR2 for this instance */
+
+ int sc_rramark; /* index into v_rra of wp */
+ u_int32_t v_rra[NRRA]; /* DMA addresses of v_rra */
+ u_int32_t v_rea; /* ptr to the end of the rra space */
+
+ int sc_rxmark; /* current hw pos in rda ring */
+ int sc_rdamark; /* current sw pos in rda ring */
+ int sc_nrda; /* total number of RDAs */
+ u_int32_t v_rda;
+
+ u_int32_t rbuf[NRBA];
+
+ struct mtd mtda[NTDA];
+ int mtd_hw; /* idx of first mtd given to hw */
+ int mtd_prev; /* idx of last mtd given to hardware */
+ int mtd_free; /* next free mtd to use */
+ int mtd_tlinko; /*
+ * offset of tlink of last txp given
+ * to SONIC. Need to clear EOL on
+ * this word to add a desc.
+ */
+ int mtd_pint; /* Counter to set TXP_PINT */
+
+ u_int32_t v_cda;
+
+ u_int8_t curbank; /* current window bank */
+
+ struct ifmedia sc_media; /* supported media information */
+
+ /*
+ * NIC register access functions:
+ */
+ u_int16_t (*sc_nic_get)
+ __P((struct snc_softc *, u_int8_t));
+ void (*sc_nic_put)
+ __P((struct snc_softc *, u_int8_t, u_int16_t));
+
+ /*
+ * Memory functions:
+ *
+ * copy to/from descriptor
+ * copy to/from buffer
+ * zero bytes in buffer
+ */
+ void (*sc_writetodesc)
+ __P((struct snc_softc *, u_int32_t, u_int32_t, u_int16_t));
+ u_int16_t (*sc_readfromdesc)
+ __P((struct snc_softc *, u_int32_t, u_int32_t));
+ void (*sc_copytobuf)
+ __P((struct snc_softc *, void *, u_int32_t, size_t));
+ void (*sc_copyfrombuf)
+ __P((struct snc_softc *, void *, u_int32_t, size_t));
+ void (*sc_zerobuf)
+ __P((struct snc_softc *, u_int32_t, size_t));
+
+ /*
+ * Machine-dependent functions:
+ *
+ * hardware reset hook - may be NULL
+ * hardware init hook - may be NULL
+ * media change hook - may be NULL
+ */
+ void (*sc_hwreset) __P((struct snc_softc *));
+ void (*sc_hwinit) __P((struct snc_softc *));
+ int (*sc_mediachange) __P((struct snc_softc *));
+ void (*sc_mediastatus) __P((struct snc_softc *,
+ struct ifmediareq *));
+
+ int sc_enabled; /* boolean; power enabled on interface */
+
+ int (*sc_enable) __P((struct snc_softc *));
+ void (*sc_disable) __P((struct snc_softc *));
+
+ void *sc_sh; /* shutdownhook cookie */
+ int gone;
+
+#if NRND > 0
+ rndsource_element_t rnd_source;
+#endif
+} snc_softc_t;
+
+/*
+ * Accessing SONIC data structures and registers as 32 bit values
+ * makes code endianess independent. The SONIC is however always in
+ * bigendian mode so it is necessary to ensure that data structures shared
+ * between the CPU and the SONIC are always in bigendian order.
+ */
+
+/*
+ * Receive Resource Descriptor
+ * This structure describes the buffers into which packets
+ * will be received. Note that more than one packet may be
+ * packed into a single buffer if constraints permit.
+ */
+#define RXRSRC_PTRLO 0 /* buffer address LO */
+#define RXRSRC_PTRHI 1 /* buffer address HI */
+#define RXRSRC_WCLO 2 /* buffer size (16bit words) LO */
+#define RXRSRC_WCHI 3 /* buffer size (16bit words) HI */
+
+#define RXRSRC_SIZE(sc) (sc->bitmode ? (4 * 4) : (4 * 2))
+
+/*
+ * Receive Descriptor
+ * This structure holds information about packets received.
+ */
+#define RXPKT_STATUS 0
+#define RXPKT_BYTEC 1
+#define RXPKT_PTRLO 2
+#define RXPKT_PTRHI 3
+#define RXPKT_SEQNO 4
+#define RXPKT_RLINK 5
+#define RXPKT_INUSE 6
+#define RXPKT_SIZE(sc) (sc->bitmode ? (7 * 4) : (7 * 2))
+
+#define RBASEQ(x) (((x)>>8)&0xff)
+#define PSNSEQ(x) ((x) & 0xff)
+
+/*
+ * Transmit Descriptor
+ * This structure holds information about packets to be transmitted.
+ */
+#define FRAGMAX 8 /* maximum number of fragments in a packet */
+
+#define TXP_STATUS 0 /* + transmitted packet status */
+#define TXP_CONFIG 1 /* transmission configuration */
+#define TXP_PKTSIZE 2 /* entire packet size in bytes */
+#define TXP_FRAGCNT 3 /* # fragments in packet */
+
+#define TXP_FRAGOFF 4 /* offset to first fragment */
+#define TXP_FRAGSIZE 3 /* size of each fragment desc */
+#define TXP_FPTRLO 0 /* ptr to packet fragment LO */
+#define TXP_FPTRHI 1 /* ptr to packet fragment HI */
+#define TXP_FSIZE 2 /* fragment size */
+
+#define TXP_WORDS (TXP_FRAGOFF + (FRAGMAX*TXP_FRAGSIZE) + 1) /* 1 for tlink */
+#define TXP_SIZE(sc) ((sc->bitmode) ? (TXP_WORDS*4) : (TXP_WORDS*2))
+
+#define EOL 0x0001 /* end of list marker for link fields */
+
+/*
+ * CDA, the CAM descriptor area. The SONIC has a 16 entry CAM to
+ * match incoming addresses against. It is programmed via DMA
+ * from a memory region.
+ */
+#define MAXCAM 16 /* number of user entries in CAM */
+#define CDA_CAMDESC 4 /* # words i na descriptor */
+#define CDA_CAMEP 0 /* CAM Address Port 0 xx-xx-xx-xx-YY-YY */
+#define CDA_CAMAP0 1 /* CAM Address Port 1 xx-xx-YY-YY-xx-xx */
+#define CDA_CAMAP1 2 /* CAM Address Port 2 YY-YY-xx-xx-xx-xx */
+#define CDA_CAMAP2 3
+#define CDA_ENABLE 64 /* mask enabling CAM entries */
+#define CDA_SIZE(sc) ((4*16 + 1) * ((sc->bitmode) ? 4 : 2))
+
+void sncconfig __P((struct snc_softc *, int *, int, int, u_int8_t *));
+void sncintr __P((void *));
+void sncshutdown __P((void *));
diff --git a/sys/dev/snc/if_snc.c b/sys/dev/snc/if_snc.c
new file mode 100644
index 0000000..5a30e3d
--- /dev/null
+++ b/sys/dev/snc/if_snc.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * 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 unmodified, 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$
+ */
+
+/*
+ * National Semiconductor DP8393X SONIC Driver
+ *
+ * This is the bus independent attachment on FreeBSD 4.x
+ * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+#include <net/if_dl.h>
+#include <net/if_mib.h>
+
+#include <net/bpf.h>
+#include "opt_bdg.h"
+#ifdef BRIDGE
+#include <net/bridge.h>
+#endif
+
+#include <dev/snc/dp83932reg.h>
+#include <dev/snc/dp83932var.h>
+#include <dev/snc/dp83932subr.h>
+#include <dev/snc/if_sncreg.h>
+#include <dev/snc/if_sncvar.h>
+
+/* devclass for "snc" */
+devclass_t snc_devclass;
+
+/****************************************************************
+ Resource management functions
+ ****************************************************************/
+
+/*
+ * Allocate a port resource with the given resource id.
+ */
+int
+snc_alloc_port(dev, rid)
+ device_t dev;
+ int rid;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0ul, ~0ul, SNEC_NREGS, RF_ACTIVE);
+ if (res) {
+ sc->ioport = res;
+ sc->ioport_rid = rid;
+ sc->sc_iot = rman_get_bustag(res);
+ sc->sc_ioh = rman_get_bushandle(res);
+ return (0);
+ } else {
+ u_long start, count;
+
+ bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count);
+ printf("snc_alloc_port: can't assign port 0x%lx-0x%lx\n",
+ start, start + count - 1);
+ return (ENOENT);
+ }
+}
+
+/*
+ * Allocate a memory resource with the given resource id.
+ */
+int
+snc_alloc_memory(dev, rid)
+ device_t dev;
+ int rid;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0ul, ~0ul, SNEC_NMEMS, RF_ACTIVE);
+ if (res) {
+ sc->iomem = res;
+ sc->iomem_rid = rid;
+ sc->sc_memt = rman_get_bustag(res);
+ sc->sc_memh = rman_get_bushandle(res);
+ return (0);
+ } else {
+ u_long start, count;
+
+ bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count);
+ printf("snc_alloc_memory: can't assign memory 0x%lx-0x%lx\n",
+ start, start + count - 1);
+ return (ENOENT);
+ }
+}
+
+/*
+ * Allocate an irq resource with the given resource id.
+ */
+int
+snc_alloc_irq(dev, rid, flags)
+ device_t dev;
+ int rid;
+ int flags;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0ul, ~0ul, 1, (RF_ACTIVE | flags));
+ if (res) {
+ sc->irq = res;
+ sc->irq_rid = rid;
+ return (0);
+ } else {
+ printf("snc_alloc_irq: can't assign irq %ld\n",
+ bus_get_resource_start(dev, SYS_RES_IRQ, rid));
+ return (ENOENT);
+ }
+}
+
+/*
+ * Release all resources
+ */
+void
+snc_release_resources(dev)
+ device_t dev;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+
+ if (sc->ioport) {
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->ioport_rid, sc->ioport);
+ sc->ioport = 0;
+ }
+ if (sc->iomem) {
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->iomem_rid, sc->iomem);
+ sc->iomem = 0;
+ }
+ if (sc->irq) {
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->irq_rid, sc->irq);
+ sc->irq = 0;
+ }
+}
+
+/****************************************************************
+ Probe routine
+ ****************************************************************/
+
+int
+snc_probe(dev, type)
+ device_t dev;
+ int type;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+
+ return snc_nec16_detectsubr(sc->sc_iot, sc->sc_ioh,
+ sc->sc_memt, sc->sc_memh,
+ rman_get_start(sc->irq),
+ rman_get_start(sc->iomem),
+ type);
+}
+
+/****************************************************************
+ Attach routine
+ ****************************************************************/
+
+int
+snc_attach(dev)
+ device_t dev;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ u_int8_t myea[ETHER_ADDR_LEN];
+
+ if (snc_nec16_register_irq(sc, rman_get_start(sc->irq)) == 0 ||
+ snc_nec16_register_mem(sc, rman_get_start(sc->iomem)) == 0) {
+ snc_release_resources(dev);
+ return(ENOENT);
+ }
+
+ snc_nec16_get_enaddr(sc->sc_iot, sc->sc_ioh, myea);
+ device_printf(dev, "%s Ethernet\n", snc_nec16_detect_type(myea));
+
+ sc->sc_dev = dev;
+
+ sc->sncr_dcr = DCR_SYNC | DCR_WAIT0 |
+ DCR_DMABLOCK | DCR_RFT16 | DCR_TFT28;
+ sc->sncr_dcr2 = 0; /* XXX */
+ sc->bitmode = 0; /* 16 bit card */
+
+ sc->sc_nic_put = snc_nec16_nic_put;
+ sc->sc_nic_get = snc_nec16_nic_get;
+ sc->sc_writetodesc = snc_nec16_writetodesc;
+ sc->sc_readfromdesc = snc_nec16_readfromdesc;
+ sc->sc_copytobuf = snc_nec16_copytobuf;
+ sc->sc_copyfrombuf = snc_nec16_copyfrombuf;
+ sc->sc_zerobuf = snc_nec16_zerobuf;
+
+ /* sncsetup returns 1 if something fails */
+ if (sncsetup(sc, myea)) {
+ snc_release_resources(dev);
+ return(ENOENT);
+ }
+
+ sncconfig(sc, NULL, 0, 0, myea);
+
+ return 0;
+}
+
+/****************************************************************
+ Shutdown routine
+ ****************************************************************/
+
+void
+snc_shutdown(dev)
+ device_t dev;
+{
+ sncshutdown(device_get_softc(dev));
+}
diff --git a/sys/dev/snc/if_snc_cbus.c b/sys/dev/snc/if_snc_cbus.c
new file mode 100644
index 0000000..6575269
--- /dev/null
+++ b/sys/dev/snc/if_snc_cbus.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * 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 unmodified, 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$
+ */
+
+/*
+ * National Semiconductor DP8393X SONIC Driver
+ *
+ * This is the C-bus specific attachment on FreeBSD
+ * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/kernel.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+
+#include <isa/isavar.h>
+#include <isa/pnpvar.h>
+#include <sys/malloc.h> /* as dependency for isa/isa_common.h */
+#include <isa/isa_common.h> /* for snc_isapnp_reconfig() */
+
+#include <dev/snc/dp83932var.h>
+#include <dev/snc/dp83932subr.h>
+#include <dev/snc/if_sncreg.h>
+#include <dev/snc/if_sncvar.h>
+
+static void snc_isapnp_reconfig __P((device_t));
+static int snc_isa_probe __P((device_t));
+static int snc_isa_attach __P((device_t));
+
+static struct isa_pnp_id snc_ids[] = {
+ { 0x6180a3b8, NULL }, /* NEC8061 NEC PC-9801-104 */
+ { 0, NULL }
+};
+
+static void
+snc_isapnp_reconfig(dev)
+ device_t dev;
+{
+ struct isa_device *idev = DEVTOISA(dev);
+ struct isa_config config;
+ u_long start, count;
+ int rid;
+
+ bzero(&config, sizeof(config));
+
+ for (rid = 0; rid < ISA_NMEM; rid++) {
+ if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count))
+ break;
+ config.ic_mem[rid].ir_start = start;
+ config.ic_mem[rid].ir_end = start;
+ config.ic_mem[rid].ir_size = count;
+ }
+ config.ic_nmem = rid;
+ for (rid = 0; rid < ISA_NPORT; rid++) {
+ if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count))
+ break;
+ config.ic_port[rid].ir_start = start;
+ config.ic_port[rid].ir_end = start;
+ config.ic_port[rid].ir_size = count;
+ }
+ config.ic_nport = rid;
+ for (rid = 0; rid < ISA_NIRQ; rid++) {
+ if (bus_get_resource(dev, SYS_RES_IRQ, rid, &start, &count))
+ break;
+ config.ic_irqmask[rid] = 1 << start;
+ }
+ config.ic_nirq = rid;
+ for (rid = 0; rid < ISA_NDRQ; rid++) {
+ if (bus_get_resource(dev, SYS_RES_DRQ, rid, &start, &count))
+ break;
+ config.ic_drqmask[rid] = 1 << start;
+ }
+ config.ic_ndrq = rid;
+
+ idev->id_config_cb(idev->id_config_arg, &config, 1);
+}
+
+static int
+snc_isa_probe(dev)
+ device_t dev;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ int type;
+ int error = 0;
+
+ bzero(sc, sizeof(struct snc_softc));
+
+ /* Check isapnp ids */
+ error = ISA_PNP_PROBE(device_get_parent(dev), dev, snc_ids);
+
+ /* If the card had a PnP ID that didn't match any we know about */
+ if (error == ENXIO) {
+ return(error);
+ }
+
+ switch (error) {
+ case 0: /* Matched PnP */
+ type = SNEC_TYPE_PNP;
+ break;
+
+ case ENOENT: /* Legacy ISA */
+ type = SNEC_TYPE_LEGACY;
+ break;
+
+ default: /* If we had some other problem. */
+ return(error);
+ }
+
+ if (type == SNEC_TYPE_PNP && isa_get_portsize(dev) == 0) {
+ int port;
+ int rid = 0;
+ struct resource *res = NULL;
+
+ for (port = 0x0888; port <= 0x3888; port += 0x1000) {
+ bus_set_resource(dev, SYS_RES_IOPORT, rid,
+ port, SNEC_NREGS);
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, SNEC_NREGS,
+ 0 /* !RF_ACTIVE */);
+ if (res) break;
+ }
+
+ printf("snc_isa_probe: broken PnP resource, ");
+ if (res) {
+ printf("use port 0x%x\n", port);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
+ snc_isapnp_reconfig(dev);
+ } else {
+ printf("and can't find port\n");
+ }
+ }
+
+ error = snc_alloc_port(dev, 0);
+ error = max(error, snc_alloc_memory(dev, 0));
+ error = max(error, snc_alloc_irq(dev, 0, 0));
+
+ if (!error && !snc_probe(dev, type))
+ error = ENOENT;
+
+ snc_release_resources(dev);
+ return (error);
+}
+
+static int
+snc_isa_attach(dev)
+ device_t dev;
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ int error;
+
+ bzero(sc, sizeof(struct snc_softc));
+
+ snc_alloc_port(dev, 0);
+ snc_alloc_memory(dev, 0);
+ snc_alloc_irq(dev, 0, 0);
+
+ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
+ sncintr, sc, &sc->irq_handle);
+ if (error) {
+ printf("snc_isa_attach: bus_setup_intr() failed\n");
+ snc_release_resources(dev);
+ return (error);
+ }
+
+ /* This interface is always enabled. */
+ sc->sc_enabled = 1;
+
+ return snc_attach(dev);
+}
+
+static device_method_t snc_isa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, snc_isa_probe),
+ DEVMETHOD(device_attach, snc_isa_attach),
+ DEVMETHOD(device_shutdown, snc_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t snc_isa_driver = {
+ "snc",
+ snc_isa_methods,
+ sizeof(struct snc_softc)
+};
+
+DRIVER_MODULE(if_snc, isa, snc_isa_driver, snc_devclass, 0, 0);
diff --git a/sys/dev/snc/if_snc_pccard.c b/sys/dev/snc/if_snc_pccard.c
new file mode 100644
index 0000000..4a396d4
--- /dev/null
+++ b/sys/dev/snc/if_snc_pccard.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * 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 unmodified, 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$
+ */
+
+/*
+ * National Semiconductor DP8393X SONIC Driver
+ *
+ * This is the PC-Card attachment on FreeBSD
+ * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp> and
+ * Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/kernel.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+
+#include <dev/pccard/pccardvar.h>
+
+#include <dev/snc/dp83932var.h>
+#include <dev/snc/dp83932reg.h>
+#include <dev/snc/if_sncvar.h>
+#include <dev/snc/if_sncreg.h>
+
+/*
+ * PC-Card (PCMCIA) specific code.
+ */
+static int snc_pccard_probe(device_t);
+static int snc_pccard_attach(device_t);
+static int snc_pccard_detach(device_t);
+
+
+static device_method_t snc_pccard_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, snc_pccard_probe),
+ DEVMETHOD(device_attach, snc_pccard_attach),
+ DEVMETHOD(device_detach, snc_pccard_detach),
+
+ { 0, 0 }
+};
+
+static driver_t snc_pccard_driver = {
+ "snc",
+ snc_pccard_methods,
+ sizeof(struct snc_softc)
+};
+
+DRIVER_MODULE(if_snc, pccard, snc_pccard_driver, snc_devclass, 0, 0);
+
+/*
+ * snc_pccard_detach - unload the driver and clear the table.
+ * XXX TODO:
+ * This is usually called when the card is ejected, but
+ * can be caused by a modunload of a controller driver.
+ * The idea is to reset the driver's view of the device
+ * and ensure that any driver entry points such as
+ * read and write do not hang.
+ */
+static int
+snc_pccard_detach(device_t dev)
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = &sc->sc_if;
+
+ if (sc->gone) {
+ device_printf(dev, "already unloaded\n");
+ return (0);
+ }
+ sncshutdown(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ if_detach(ifp);
+ sc->gone = 1;
+ bus_teardown_intr(dev, sc->irq, sc->irq_handle);
+ snc_release_resources(dev);
+ return (0);
+}
+
+/*
+ * Probe framework for pccards. Replicates the standard framework,
+ * minus the pccard driver registration and ignores the ether address
+ * supplied (from the CIS), relying on the probe to find it instead.
+ */
+static int
+snc_pccard_probe(device_t dev)
+{
+ int error;
+
+ error = snc_alloc_port(dev, 0);
+ error = max(error, snc_alloc_memory(dev, 0));
+ error = max(error, snc_alloc_irq(dev, 0, 0));
+
+ if (!error && !snc_probe(dev, SNEC_TYPE_PNP))
+ error = ENOENT;
+
+ snc_release_resources(dev);
+ return (error);
+}
+
+static int
+snc_pccard_attach(device_t dev)
+{
+ struct snc_softc *sc = device_get_softc(dev);
+ int error;
+
+ bzero(sc, sizeof(struct snc_softc));
+
+ snc_alloc_port(dev, 0);
+ snc_alloc_memory(dev, 0);
+ snc_alloc_irq(dev, 0, 0);
+
+ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
+ sncintr, sc, &sc->irq_handle);
+ if (error) {
+ printf("snc_isa_attach: bus_setup_intr() failed\n");
+ snc_release_resources(dev);
+ return (error);
+ }
+
+ /* This interface is always enabled. */
+ sc->sc_enabled = 1;
+
+ /* pccard_get_ether(dev, ether_addr); */
+
+ return snc_attach(dev);
+}
diff --git a/sys/dev/snc/if_sncreg.h b/sys/dev/snc/if_sncreg.h
new file mode 100644
index 0000000..30b0bb7
--- /dev/null
+++ b/sys/dev/snc/if_sncreg.h
@@ -0,0 +1,140 @@
+/* $FreeBSD$ */
+/* $NecBSD: if_snreg.h,v 1.3 1999/01/24 01:39:52 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Kouichi Matsuda. 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 Kouichi Matsuda for
+ * NetBSD/pc98.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modified for NetBSD/pc98 1.2.1 from NetBSD/mac68k 1.2D by Kouichi Matsuda.
+ * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and
+ * PC-9801N-J02R, which uses National Semiconductor DP83934AVQB as
+ * Ethernet Controller and National Semiconductor NS46C46 as (64 * 16 bits)
+ * Microwire Serial EEPROM.
+ */
+
+/*
+ * XXX: Should not be HERE. (Should be shared with...)
+ */
+
+/*
+ * NEC/SONIC port mappings, offset from iobase.
+ */
+#define SNEC_CTRL 0 /* SONIC control port (word) */
+#define SNEC_CTRLB 1 /* NEC/SONIC control port (byte) */
+#define SNEC_RSVD0 2 /* not used */
+#define SNEC_ADDR 3 /* SONIC, NEC/SONIC register address set port */
+#define SNEC_RSVD1 4 /* not used */
+#define SNEC_RSVD2 5 /* not used */
+
+#define SNEC_NREGS 6
+
+/* bank memory size */
+#define SNEC_NMEMS (NBPG * 2)
+/* how many bank */
+#define SNEC_NBANK 0x10
+/* internal buffer size */
+#define SNEC_NBUF (SNEC_NMEMS * SNEC_NBANK)
+
+
+/*
+ * NEC/SONIC specific internal registers.
+ */
+
+/*
+ * Memory Bank Select Register (MEMBS)
+ */
+#define SNECR_MEMBS 0x80
+#define SNECR_MEMBS_BSEN 0x01 /* enable memory bank select */
+#define SNECR_MEMBS_EBNMSK 0x1c /* encoded bank select number */
+/* Translate bank number to encoded bank select number. */
+#define SNECR_MEMBS_B2EB(bank) (bank << 2)
+#define SNECR_MEMBS_PCMCIABUS 0x80 /* bus type identification */
+
+/*
+ * Memory Base Address Select Register (MEMSEL)
+ */
+#define SNECR_MEMSEL 0x82
+/* Translate base phys address to encoded select number. */
+#define SNECR_MEMSEL_PHYS2EN(maddr) ((maddr >> 13) & 0x0f)
+
+/*
+ * Encoded Irq Select Register (IRQSEL)
+ */
+#define SNECR_IRQSEL 0x84
+
+/*
+ * EEPROM Access Register (EEP)
+ */
+#define SNECR_EEP 0x86
+#define SNECR_EEP_DI 0x10 /* EEPROM Serial Data Input (high) */
+#define SNECR_EEP_CS 0x20 /* EEPROM Chip Select (high) */
+#define SNECR_EEP_SK 0x40 /* EEPROM Serial Data Clock (high) */
+#define SNECR_EEP_DO 0x80 /* EEPROM Serial Data Output (high) */
+
+/* EEPROM data locations */
+#define SNEC_EEPROM_KEY0 6 /* Station Address Check Sum Key #1 */
+#define SNEC_EEPROM_KEY1 7 /* Station Address Check Sum Key #2 */
+#define SNEC_EEPROM_SA0 8 /* Station Address #1 */
+#define SNEC_EEPROM_SA1 9 /* Station Address #2 */
+#define SNEC_EEPROM_SA2 10 /* Station Address #3 */
+#define SNEC_EEPROM_SA3 11 /* Station Address #4 */
+#define SNEC_EEPROM_SA4 12 /* Station Address #5 */
+#define SNEC_EEPROM_SA5 13 /* Station Address #6 */
+#define SNEC_EEPROM_CKSUM 14 /* Station Address Check Sum */
+
+#define SNEC_EEPROM_SIZE 32 /* valid EEPROM data (max 128 bytes) */
+
+/*
+ * Bus and Mode Identification Register (IDENT)
+ */
+#define SNECR_IDENT 0x88
+ /* Bit 0: Bus Identification. */
+#define SNECR_IDENT_CBUS 0x01 /* on PC-98 C-Bus */
+#define SNECR_IDENT_PCMCIABUS 0x00 /* on PCMCIA Bus */
+ /* Bit 2: always 1 */
+#define SNECR_IDENT_MAGIC 0x04
+ /* Bit 4: Bus Configuration Mode Identification. */
+#define SNECR_IDENT_PNP 0x10 /* Plug and Play (C-Bus and PCMCIA) */
+#define SNECR_IDENT_LEGACY 0x00 /* Legacy C-Bus */
+
+#define SNECR_IDENT_LEGACY_CBUS \
+ (SNECR_IDENT_LEGACY | SNECR_IDENT_MAGIC | SNECR_IDENT_CBUS)
+#define SNECR_IDENT_PNP_CBUS \
+ (SNECR_IDENT_PNP | SNECR_IDENT_MAGIC | SNECR_IDENT_CBUS)
+#define SNECR_IDENT_PNP_PCMCIABUS \
+ (SNECR_IDENT_PNP | SNECR_IDENT_MAGIC | SNECR_IDENT_PCMCIABUS)
+
+/*
+ * XXX: parent bus type aliases
+ */
+#define SNEC_TYPE_LEGACY 0
+#define SNEC_TYPE_PNP 1
+
diff --git a/sys/dev/snc/if_sncvar.h b/sys/dev/snc/if_sncvar.h
new file mode 100644
index 0000000..98b2d94
--- /dev/null
+++ b/sys/dev/snc/if_sncvar.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * 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 unmodified, 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$
+ */
+
+/*
+ * National Semiconductor DP8393X SONIC Driver
+ *
+ * This is the machine dependent attachment on FreeBSD 4.x
+ * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
+ */
+
+extern devclass_t snc_devclass;
+
+void snc_release_resources __P((device_t));
+int snc_alloc_port __P((device_t, int));
+int snc_alloc_memory __P((device_t, int));
+int snc_alloc_irq __P((device_t, int, int));
+
+int snc_probe __P((device_t, int));
+int snc_attach __P((device_t));
+
+void snc_shutdown __P((device_t));
OpenPOWER on IntegriCloud