summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfjoe <fjoe@FreeBSD.org>2002-01-08 20:03:13 +0000
committerfjoe <fjoe@FreeBSD.org>2002-01-08 20:03:13 +0000
commit2053aff54edfb4c3ac126a8b88700dbc70a7969f (patch)
treebb285377f57f0c2656c28eaca30fbc3434b7cb8a
parent849d50be93de0733f49a8209a1729f2787710113 (diff)
downloadFreeBSD-src-2053aff54edfb4c3ac126a8b88700dbc70a7969f.zip
FreeBSD-src-2053aff54edfb4c3ac126a8b88700dbc70a7969f.tar.gz
- generic Arcnet framework
- device driver for SMC COM90cx6 Arcnet network adapters Obtained from: NetBSD
-rw-r--r--sys/conf/NOTES9
-rw-r--r--sys/conf/files2
-rw-r--r--sys/conf/files.i3861
-rw-r--r--sys/dev/cm/if_cm_isa.c135
-rw-r--r--sys/dev/cm/smc90cx6.c1071
-rw-r--r--sys/dev/cm/smc90cx6reg.h91
-rw-r--r--sys/dev/cm/smc90cx6var.h103
-rw-r--r--sys/i386/conf/NOTES9
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/arcnet/Makefile12
-rw-r--r--sys/modules/cm/Makefile10
-rw-r--r--sys/net/if_arcsubr.c780
12 files changed, 2225 insertions, 0 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 5d56a4c..ad17181 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -509,6 +509,7 @@ device musycc # LMC/SBE LMC1504 quad T1/E1
# Ethernets; it is MANDATORY when a Ethernet device driver is
# configured or token-ring is enabled.
# The `fddi' device provides generic code to support FDDI.
+# The `arcnet' device provides generic code to support Arcnet.
# The `sppp' device serves a similar role for certain types
# of synchronous PPP links (like `cx', `ar').
# The `sl' device implements the Serial Line IP (SLIP) service.
@@ -543,6 +544,7 @@ device ether #Generic Ethernet
device vlan #VLAN support
device token #Generic TokenRing
device fddi #Generic FDDI
+device arcnet #Generic Arcnet
device sppp #Generic Synchronous PPP
device loop 1 #Network loopback device
device bpf #Berkeley packet filter
@@ -1711,6 +1713,8 @@ device miibus
# the SysKonnect SK-9D21 and SK-9D41, and the embedded gigE NICs
# on Dell PowerEdge 2550 servers.
# cnw: Xircom CNW/Netware Airsurfer PC Card adapter
+# cm: Arcnet SMC COM90c26 / SMC COM90c56
+# (and SMC COM90c66 in '56 compatibility mode) adapters.
# cs: IBM Etherjet and other Crystal Semi CS89x0-based adapters
# cx: Cronyx/Sigma multiport sync/async (with Cisco or PPP framing)
# dc: Support for PCI fast ethernet adapters based on the DEC/Intel 21143
@@ -1829,6 +1833,11 @@ hint.ar.0.at="isa"
hint.ar.0.port="0x300"
hint.ar.0.irq="10"
hint.ar.0.maddr="0xd0000"
+device cm
+hint.cm.0.at="isa"
+hint.cm.0.port="0x2e0"
+hint.cm.0.irq="9"
+hint.cm.0.maddr="0xdc000"
device cs
hint.cs.0.at="isa"
hint.cs.0.port="0x300"
diff --git a/sys/conf/files b/sys/conf/files
index 77353f8..d435ae0 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -289,6 +289,7 @@ dev/cardbus/cardbus.c optional cardbus
dev/cardbus/cardbus_cis.c optional cardbus
dev/ccd/ccd.c optional ccd
dev/ciss/ciss.c optional ciss
+dev/cm/smc90cx6.c optional cm
dev/cnw/if_cnw.c optional cnw card
#dev/cnw/if_cnw.c optional cnw pccard
dev/cs/if_cs.c optional cs
@@ -907,6 +908,7 @@ bpf.h standard \
net/bridge.c optional bridge
net/bsd_comp.c optional ppp_bsdcomp
net/if.c standard
+net/if_arcsubr.c optional arcnet
net/if_atmsubr.c optional atm
net/if_disc.c optional disc
net/if_ef.c optional ef
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 8cf3d2b..1043953 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -96,6 +96,7 @@ crypto/des/des_setkey.c optional netsmbcrypto
dev/advansys/adv_isa.c optional adv isa
dev/aic/aic_isa.c optional aic isa
dev/ar/if_ar_isa.c optional ar isa
+dev/cm/if_cm_isa.c optional cm isa
dev/ed/if_ed_isa.c optional ed isa
dev/eisa/eisaconf.c optional eisa
dev/em/if_em.c optional em
diff --git a/sys/dev/cm/if_cm_isa.c b/sys/dev/cm/if_cm_isa.c
new file mode 100644
index 0000000..8af2dff
--- /dev/null
+++ b/sys/dev/cm/if_cm_isa.c
@@ -0,0 +1,135 @@
+/* $NetBSD: if_bah_zbus.c,v 1.6 2000/01/23 21:06:12 aymeric Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ignatios Souvatzis.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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/if.h>
+#include <net/if_arc.h>
+
+#include <dev/cm/smc90cx6var.h>
+
+static int cm_isa_probe __P((device_t));
+static int cm_isa_attach __P((device_t));
+
+static int
+cm_isa_probe(dev)
+ device_t dev;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ int error;
+
+ bzero(sc, sizeof(struct cm_softc));
+
+ error = cm_probe(dev);
+ if (error == 0)
+ goto end;
+
+end:
+ if (error == 0)
+ error = cm_alloc_irq(dev, 0);
+
+ cm_release_resources(dev);
+ return (error);
+}
+
+static int
+cm_isa_attach(dev)
+ device_t dev;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ int error;
+
+ cm_alloc_port(dev, sc->port_rid, sc->port_used);
+ cm_alloc_memory(dev, sc->mem_rid, sc->mem_used);
+ cm_alloc_irq(dev, sc->irq_rid);
+
+ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
+ cmintr, sc, &sc->irq_handle);
+ if (error) {
+ cm_release_resources(dev);
+ return (error);
+ }
+
+ return cm_attach(sc, device_get_unit(dev));
+}
+
+static int
+cm_isa_detach(device_t dev)
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = &sc->sc_arccom.ac_if;
+ int s;
+
+ cm_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ s = splimp();
+ arc_ifdetach(&sc->sc_arccom.ac_if);
+ splx(s);
+
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
+ cm_release_resources(dev);
+
+ return (0);
+}
+
+static device_method_t cm_isa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cm_isa_probe),
+ DEVMETHOD(device_attach, cm_isa_attach),
+ DEVMETHOD(device_detach, cm_isa_detach),
+
+ { 0, 0 }
+};
+
+static driver_t cm_isa_driver = {
+ "cm",
+ cm_isa_methods,
+ sizeof(struct cm_softc)
+};
+
+DRIVER_MODULE(if_cm, isa, cm_isa_driver, cm_devclass, 0, 0);
diff --git a/sys/dev/cm/smc90cx6.c b/sys/dev/cm/smc90cx6.c
new file mode 100644
index 0000000..a5dfb9c
--- /dev/null
+++ b/sys/dev/cm/smc90cx6.c
@@ -0,0 +1,1071 @@
+/* $NetBSD: smc90cx6.c,v 1.38 2001/07/07 15:57:53 thorpej Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ignatios Souvatzis.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56
+ * compatibility mode) boards
+ */
+
+/* #define CMSOFTCOPY */
+#define CMRETRANSMIT /**/
+#undef CM_DEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#if __FreeBSD_version < 500000
+#include <machine/clock.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_arc.h>
+#include <net/bpf.h>
+
+#if 0
+#if NBPFILTER > 0
+#include <net/bpfdesc.h>
+#endif
+#endif
+
+#include <dev/cm/smc90cx6reg.h>
+#include <dev/cm/smc90cx6var.h>
+
+MODULE_DEPEND(if_cm, arcnet, 1, 1, 1);
+
+/* these should be elsewhere */
+
+#define ARC_MIN_LEN 1
+#define ARC_MIN_FORBID_LEN 254
+#define ARC_MAX_FORBID_LEN 256
+#define ARC_MAX_LEN 508
+#define ARC_ADDR_LEN 1
+
+/* for watchdog timer. This should be more than enough. */
+#define ARCTIMEOUT (5*IFNET_SLOWHZ)
+
+/* short notation */
+
+#define GETREG(off) \
+ bus_space_read_1(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), \
+ (off))
+#define PUTREG(off, value) \
+ bus_space_write_1(rman_get_bustag((sc)->port_res), \
+ rman_get_bushandle((sc)->port_res), \
+ (off), (value))
+#define GETMEM(off) \
+ bus_space_read_1(rman_get_bustag((sc)->mem_res), \
+ rman_get_bushandle((sc)->mem_res), \
+ (off))
+#define PUTMEM(off, value) \
+ bus_space_write_1(rman_get_bustag((sc)->mem_res), \
+ rman_get_bushandle((sc)->mem_res), \
+ (off), (value))
+
+devclass_t cm_devclass;
+
+/*
+ * This currently uses 2 bufs for tx, 2 for rx
+ *
+ * New rx protocol:
+ *
+ * rx has a fillcount variable. If fillcount > (NRXBUF-1),
+ * rx can be switched off from rx hard int.
+ * Else rx is restarted on the other receiver.
+ * rx soft int counts down. if it is == (NRXBUF-1), it restarts
+ * the receiver.
+ * To ensure packet ordering (we need that for 1201 later), we have a counter
+ * which is incremented modulo 256 on each receive and a per buffer
+ * variable, which is set to the counter on filling. The soft int can
+ * compare both values to determine the older packet.
+ *
+ * Transmit direction:
+ *
+ * cm_start checks tx_fillcount
+ * case 2: return
+ *
+ * else fill tx_act ^ 1 && inc tx_fillcount
+ *
+ * check tx_fillcount again.
+ * case 2: set IFF_OACTIVE to stop arc_output from filling us.
+ * case 1: start tx
+ *
+ * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
+ * case 1: start tx on tx_act ^ 1, softcall cm_start
+ * case 0: softcall cm_start
+ *
+ * #define fill(i) get mbuf && copy mbuf to chip(i)
+ */
+
+void cm_init __P((void *));
+void cm_reset __P((struct cm_softc *));
+void cm_start __P((struct ifnet *));
+int cm_ioctl __P((struct ifnet *, unsigned long, caddr_t));
+void cm_watchdog __P((struct ifnet *));
+void cm_srint __P((void *vsc));
+static void cm_tint __P((struct cm_softc *, int));
+void cm_reconwatch(void *);
+
+int
+cm_probe(dev)
+ device_t dev;
+{
+ int error;
+ struct cm_softc *sc = device_get_softc(dev);
+
+ error = cm_alloc_port(dev, 0, CM_IO_PORTS);
+ if (error)
+ return error;
+
+ if (GETREG(CMSTAT) == 0xff)
+ return ENXIO;
+
+ error = cm_alloc_memory(dev, 0, 0x800);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+/*
+ * Allocate a port resource with the given resource id.
+ */
+int
+cm_alloc_port(dev, rid, size)
+ device_t dev;
+ int rid;
+ int size;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0ul, ~0ul, size, RF_ACTIVE);
+ if (res) {
+ sc->port_rid = rid;
+ sc->port_res = res;
+ sc->port_used = size;
+ return (0);
+ } else {
+ return (ENOENT);
+ }
+}
+
+/*
+ * Allocate a memory resource with the given resource id.
+ */
+int
+cm_alloc_memory(dev, rid, size)
+ device_t dev;
+ int rid;
+ int size;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0ul, ~0ul, size, RF_ACTIVE);
+ if (res) {
+ sc->mem_rid = rid;
+ sc->mem_res = res;
+ sc->mem_used = size;
+ return (0);
+ } else {
+ return (ENOENT);
+ }
+}
+
+/*
+ * Allocate an irq resource with the given resource id.
+ */
+int
+cm_alloc_irq(dev, rid)
+ device_t dev;
+ int rid;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0ul, ~0ul, 1, RF_ACTIVE);
+ if (res) {
+ sc->irq_rid = rid;
+ sc->irq_res = res;
+ return (0);
+ } else {
+ return (ENOENT);
+ }
+}
+
+/*
+ * Release all resources
+ */
+void
+cm_release_resources(dev)
+ device_t dev;
+{
+ struct cm_softc *sc = device_get_softc(dev);
+
+ if (sc->port_res) {
+ bus_deactivate_resource(dev, SYS_RES_IOPORT,
+ sc->port_rid, sc->port_res);
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->port_rid, sc->port_res);
+ sc->port_res = 0;
+ }
+ if (sc->mem_res) {
+ bus_deactivate_resource(dev, SYS_RES_MEMORY,
+ sc->mem_rid, sc->mem_res);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->mem_rid, sc->mem_res);
+ sc->mem_res = 0;
+ }
+ if (sc->irq_res) {
+ bus_deactivate_resource(dev, SYS_RES_IRQ,
+ sc->irq_rid, sc->irq_res);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->irq_rid, sc->irq_res);
+ sc->irq_res = 0;
+ }
+}
+
+int
+cm_attach(sc, unit)
+ struct cm_softc *sc;
+ int unit;
+{
+ struct ifnet *ifp = &sc->sc_arccom.ac_if;
+ int s;
+ u_int8_t linkaddress;
+
+ s = splhigh();
+
+ /*
+ * read the arcnet address from the board
+ */
+
+ GETREG(CMRESET);
+ do {
+ DELAY(200);
+ } while (!(GETREG(CMSTAT) & CM_POR));
+
+ linkaddress = GETMEM(CMMACOFF);
+
+ /* clear the int mask... */
+
+ sc->sc_intmask = 0;
+ PUTREG(CMSTAT, 0);
+
+ PUTREG(CMCMD, CM_CONF(CONF_LONG));
+ PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG));
+ sc->sc_recontime = sc->sc_reconcount = 0;
+
+ /* and reenable kernel int level */
+ splx(s);
+
+ /*
+ * set interface to stopped condition (reset)
+ */
+ cm_stop(sc);
+
+ if (!ifp->if_name) {
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "cm";
+ ifp->if_output = arc_output;
+ ifp->if_start = cm_start;
+ ifp->if_ioctl = cm_ioctl;
+ ifp->if_watchdog = cm_watchdog;
+ ifp->if_init = cm_init;
+ /* XXX IFQ_SET_READY(&ifp->if_snd); */
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ ifp->if_timer = 0;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+
+ arc_ifattach(ifp, linkaddress);
+
+#ifdef CMSOFTCOPY
+ sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, cm_srint, sc);
+ sc->sc_txcookie = softintr_establish(IPL_SOFTNET,
+ (void (*) __P((void *)))cm_start, ifp);
+#endif
+
+#if __FreeBSD_version < 500000
+ callout_init(&sc->sc_recon_ch);
+#else
+ callout_init(&sc->sc_recon_ch, 0);
+#endif
+ }
+
+ printf("%s%d: link addr 0x%02x(%d)\n",
+ ifp->if_name, ifp->if_unit, linkaddress, linkaddress);
+ return 0;
+}
+
+/*
+ * Initialize device
+ *
+ */
+void
+cm_init(xsc)
+ void *xsc;
+{
+ struct cm_softc *sc = (struct cm_softc *)xsc;
+ struct ifnet *ifp;
+ int s;
+
+ ifp = &sc->sc_arccom.ac_if;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ s = splimp();
+ ifp->if_flags |= IFF_RUNNING;
+ cm_reset(sc);
+ cm_start(ifp);
+ splx(s);
+ }
+}
+
+/*
+ * Reset the interface...
+ *
+ * this assumes that it is called inside a critical section...
+ *
+ */
+void
+cm_reset(sc)
+ struct cm_softc *sc;
+{
+ struct ifnet *ifp;
+ int linkaddress;
+
+ ifp = &sc->sc_arccom.ac_if;
+
+#ifdef CM_DEBUG
+ printf("%s%d: reset\n", ifp->if_name, ifp->if_unit);
+#endif
+ /* stop and restart hardware */
+
+ GETREG(CMRESET);
+ do {
+ DELAY(200);
+ } while (!(GETREG(CMSTAT) & CM_POR));
+
+ linkaddress = GETMEM(CMMACOFF);
+
+#if defined(CM_DEBUG) && (CM_DEBUG > 2)
+ printf("%s%d: reset: card reset, link addr = 0x%02x (%d)\n",
+ ifp->if_name, ifp->if_unit, linkaddress, linkaddress);
+#endif
+
+ /* tell the routing level about the (possibly changed) link address */
+ arc_storelladdr(ifp, linkaddress);
+ arc_frag_init(ifp);
+
+ /* POR is NMI, but we need it below: */
+ sc->sc_intmask = CM_RECON|CM_POR;
+ PUTREG(CMSTAT, sc->sc_intmask);
+ PUTREG(CMCMD, CM_CONF(CONF_LONG));
+
+#ifdef CM_DEBUG
+ printf("%s%d: reset: chip configured, status=0x%02x\n",
+ ifp->if_name, ifp->if_unit, GETREG(CMSTAT));
+#endif
+ PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG));
+
+#ifdef CM_DEBUG
+ printf("%s%d: reset: bits cleared, status=0x%02x\n",
+ ifp->if_name, ifp->if_unit, GETREG(CMSTAT));
+#endif
+
+ sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
+
+ /* start receiver */
+
+ sc->sc_intmask |= CM_RI;
+ sc->sc_rx_fillcount = 0;
+ sc->sc_rx_act = 2;
+
+ PUTREG(CMCMD, CM_RXBC(2));
+ PUTREG(CMSTAT, sc->sc_intmask);
+
+#ifdef CM_DEBUG
+ printf("%s%d: reset: started receiver, status=0x%02x\n",
+ ifp->if_name, ifp->if_unit, GETREG(CMSTAT));
+#endif
+
+ /* and init transmitter status */
+ sc->sc_tx_act = 0;
+ sc->sc_tx_fillcount = 0;
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ cm_start(ifp);
+}
+
+/*
+ * Take interface offline
+ */
+void
+cm_stop(sc)
+ struct cm_softc *sc;
+{
+ /* Stop the interrupts */
+ PUTREG(CMSTAT, 0);
+
+ /* Stop the interface */
+ GETREG(CMRESET);
+
+ /* Stop watchdog timer */
+ sc->sc_arccom.ac_if.if_timer = 0;
+}
+
+/*
+ * Start output on interface. Get another datagram to send
+ * off the interface queue, and copy it to the
+ * interface becore starting the output
+ *
+ * this assumes that it is called inside a critical section...
+ * XXX hm... does it still?
+ *
+ */
+void
+cm_start(ifp)
+ struct ifnet *ifp;
+{
+ struct cm_softc *sc = ifp->if_softc;
+ struct mbuf *m,*mp;
+
+ int cm_ram_ptr;
+ int len, tlen, offset, s, buffer;
+#ifdef CMTIMINGS
+ u_long copystart, lencopy, perbyte;
+#endif
+
+#if defined(CM_DEBUG) && (CM_DEBUG > 3)
+ printf("%s%d: start(%p)\n", ifp->if_name, ifp->if_unit, ifp);
+#endif
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return;
+
+ s = splimp();
+
+ if (sc->sc_tx_fillcount >= 2) {
+ splx(s);
+ return;
+ }
+
+ m = arc_frag_next(ifp);
+ buffer = sc->sc_tx_act ^ 1;
+
+ splx(s);
+
+ if (m == 0)
+ return;
+
+ /*
+ * If bpf is listening on this interface, let it
+ * see the packet before we commit it to the wire
+ *
+ * (can't give the copy in A2060 card RAM to bpf, because
+ * that RAM is just accessed as on every other byte)
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m);
+
+#ifdef CM_DEBUG
+ if (m->m_len < ARC_HDRLEN)
+ m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */
+ printf("%s%d: start: filling %d from %d to %d type %d\n",
+ ifp->if_name, ifp->if_unit, buffer, mtod(m, u_char *)[0],
+ mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
+#else
+ if (m->m_len < 2)
+ m = m_pullup(m, 2);
+#endif
+ cm_ram_ptr = buffer*512;
+
+ if (m == 0)
+ return;
+
+ /* write the addresses to RAM and throw them away */
+
+ /*
+ * Hardware does this: Yet Another Microsecond Saved.
+ * (btw, timing code says usually 2 microseconds)
+ * PUTMEM(cm_ram_ptr + 0, mtod(m, u_char *)[0]);
+ */
+
+ PUTMEM(cm_ram_ptr + 1, mtod(m, u_char *)[1]);
+ m_adj(m, 2);
+
+ /* get total length left at this point */
+ tlen = m->m_pkthdr.len;
+ if (tlen < ARC_MIN_FORBID_LEN) {
+ offset = 256 - tlen;
+ PUTMEM(cm_ram_ptr + 2, offset);
+ } else {
+ PUTMEM(cm_ram_ptr + 2, 0);
+ if (tlen <= ARC_MAX_FORBID_LEN)
+ offset = 255; /* !!! */
+ else {
+ if (tlen > ARC_MAX_LEN)
+ tlen = ARC_MAX_LEN;
+ offset = 512 - tlen;
+ }
+ PUTMEM(cm_ram_ptr + 3, offset);
+
+ }
+ cm_ram_ptr += offset;
+
+ /* lets loop through the mbuf chain */
+
+ for (mp = m; mp; mp = mp->m_next) {
+ if ((len = mp->m_len)) { /* YAMS */
+ bus_space_write_region_1(
+ rman_get_bustag(sc->mem_res),
+ rman_get_bushandle(sc->mem_res),
+ cm_ram_ptr, mtod(mp, caddr_t), len);
+
+ cm_ram_ptr += len;
+ }
+ }
+
+ sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
+ sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
+
+ /* actually transmit the packet */
+ s = splimp();
+
+ if (++sc->sc_tx_fillcount > 1) {
+ /*
+ * We are filled up to the rim. No more bufs for the moment,
+ * please.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ } else {
+#ifdef CM_DEBUG
+ printf("%s%d: start: starting transmitter on buffer %d\n",
+ ifp->if_name, ifp->if_unit, buffer);
+#endif
+ /* Transmitter was off, start it */
+ sc->sc_tx_act = buffer;
+
+ /*
+ * We still can accept another buf, so don't:
+ * ifp->if_flags |= IFF_OACTIVE;
+ */
+ sc->sc_intmask |= CM_TA;
+ PUTREG(CMCMD, CM_TX(buffer));
+ PUTREG(CMSTAT, sc->sc_intmask);
+
+ sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT;
+ }
+ splx(s);
+ m_freem(m);
+
+ /*
+ * After 10 times reading the docs, I realized
+ * that in the case the receiver NAKs the buffer request,
+ * the hardware retries till shutdown.
+ * This is integrated now in the code above.
+ */
+
+ return;
+}
+
+/*
+ * Arcnet interface receiver soft interrupt:
+ * get the stuff out of any filled buffer we find.
+ */
+void
+cm_srint(vsc)
+ void *vsc;
+{
+ struct cm_softc *sc = (struct cm_softc *)vsc;
+ int buffer, len, offset, s, type;
+ int cm_ram_ptr;
+ struct mbuf *m;
+ struct arc_header *ah;
+ struct ifnet *ifp;
+
+ ifp = &sc->sc_arccom.ac_if;
+
+ s = splimp();
+ buffer = sc->sc_rx_act ^ 1;
+ splx(s);
+
+ /* Allocate header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ if (m == 0) {
+ /*
+ * in case s.th. goes wrong with mem, drop it
+ * to make sure the receiver can be started again
+ * count it as input error (we dont have any other
+ * detectable)
+ */
+ ifp->if_ierrors++;
+ goto cleanup;
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+
+ /*
+ * Align so that IP packet will be longword aligned. Here we
+ * assume that m_data of new packet is longword aligned.
+ * When implementing PHDS, we might have to change it to 2,
+ * (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent.
+ */
+
+ cm_ram_ptr = buffer*512;
+ offset = GETMEM(cm_ram_ptr + 2);
+ if (offset)
+ len = 256 - offset;
+ else {
+ offset = GETMEM(cm_ram_ptr + 3);
+ len = 512 - offset;
+ }
+
+ /*
+ * first +2 bytes for align fixup below
+ * second +2 bytes are for src/dst addresses
+ */
+ if ((len + 2 + 2) > MHLEN) {
+ /* attach an mbuf cluster */
+ MCLGET(m, M_DONTWAIT);
+
+ /* Insist on getting a cluster */
+ if ((m->m_flags & M_EXT) == 0) {
+ ifp->if_ierrors++;
+ goto cleanup;
+ }
+ }
+
+ if (m == 0) {
+ ifp->if_ierrors++;
+ goto cleanup;
+ }
+
+ type = GETMEM(cm_ram_ptr + offset);
+ m->m_data += 1 + arc_isphds(type);
+ /* mbuf filled with ARCnet addresses */
+ m->m_pkthdr.len = m->m_len = len + 2;
+
+ ah = mtod(m, struct arc_header *);
+ ah->arc_shost = GETMEM(cm_ram_ptr + 0);
+ ah->arc_dhost = GETMEM(cm_ram_ptr + 1);
+
+ bus_space_read_region_1(
+ rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res),
+ cm_ram_ptr + offset, mtod(m, u_char *) + 2, len);
+
+ arc_input(ifp, m);
+
+ m = NULL;
+ ifp->if_ipackets++;
+
+cleanup:
+
+ if (m != NULL)
+ m_freem(m);
+
+ /* mark buffer as invalid by source id 0 */
+ PUTMEM(buffer << 9, 0);
+ s = splimp();
+
+ if (--sc->sc_rx_fillcount == 2 - 1) {
+
+ /* was off, restart it on buffer just emptied */
+ sc->sc_rx_act = buffer;
+ sc->sc_intmask |= CM_RI;
+
+ /* this also clears the RI flag interupt: */
+ PUTREG(CMCMD, CM_RXBC(buffer));
+ PUTREG(CMSTAT, sc->sc_intmask);
+
+#ifdef CM_DEBUG
+ printf("%s%d: srint: restarted rx on buf %d\n",
+ ifp->if_name, ifp->if_unit, buffer);
+#endif
+ }
+ splx(s);
+}
+
+__inline static void
+cm_tint(sc, isr)
+ struct cm_softc *sc;
+ int isr;
+{
+ struct ifnet *ifp;
+
+ int buffer;
+#ifdef CMTIMINGS
+ int clknow;
+#endif
+
+ ifp = &(sc->sc_arccom.ac_if);
+ buffer = sc->sc_tx_act;
+
+ /*
+ * retransmit code:
+ * Normal situtations first for fast path:
+ * If acknowledgement received ok or broadcast, we're ok.
+ * else if
+ */
+
+ if (isr & CM_TMA || sc->sc_broadcast[buffer])
+ sc->sc_arccom.ac_if.if_opackets++;
+#ifdef CMRETRANSMIT
+ else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0
+ && --sc->sc_retransmits[buffer] > 0) {
+ /* retransmit same buffer */
+ PUTREG(CMCMD, CM_TX(buffer));
+ return;
+ }
+#endif
+ else
+ ifp->if_oerrors++;
+
+
+ /* We know we can accept another buffer at this point. */
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (--sc->sc_tx_fillcount > 0) {
+
+ /*
+ * start tx on other buffer.
+ * This also clears the int flag
+ */
+ buffer ^= 1;
+ sc->sc_tx_act = buffer;
+
+ /*
+ * already given:
+ * sc->sc_intmask |= CM_TA;
+ * PUTREG(CMSTAT, sc->sc_intmask);
+ */
+ PUTREG(CMCMD, CM_TX(buffer));
+ /* init watchdog timer */
+ ifp->if_timer = ARCTIMEOUT;
+
+#if defined(CM_DEBUG) && (CM_DEBUG > 1)
+ printf("%s%d: tint: starting tx on buffer %d, status 0x%02x\n",
+ ifp->if_name, ifp->if_unit, buffer, GETREG(CMSTAT));
+#endif
+ } else {
+ /* have to disable TX interrupt */
+ sc->sc_intmask &= ~CM_TA;
+ PUTREG(CMSTAT, sc->sc_intmask);
+ /* ... and watchdog timer */
+ ifp->if_timer = 0;
+
+#ifdef CM_DEBUG
+ printf("%s%d: tint: no more buffers to send, status 0x%02x\n",
+ ifp->if_name, ifp->if_unit, GETREG(CMSTAT));
+#endif
+ }
+
+ /* XXXX TODO */
+#ifdef CMSOFTCOPY
+ /* schedule soft int to fill a new buffer for us */
+ softintr_schedule(sc->sc_txcookie);
+#else
+ /* call it directly */
+ cm_start(ifp);
+#endif
+}
+
+/*
+ * Our interrupt routine
+ */
+void
+cmintr(arg)
+ void *arg;
+{
+ struct cm_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_arccom.ac_if;
+
+ u_char isr, maskedisr;
+ int buffer;
+ u_long newsec;
+
+ isr = GETREG(CMSTAT);
+ maskedisr = isr & sc->sc_intmask;
+ if (!maskedisr)
+ return;
+ do {
+
+#if defined(CM_DEBUG) && (CM_DEBUG>1)
+ printf("%s%d: intr: status 0x%02x, intmask 0x%02x\n",
+ ifp->if_name, ifp->if_unit, isr, sc->sc_intmask);
+#endif
+
+ if (maskedisr & CM_POR) {
+ /*
+ * XXX We should never see this. Don't bother to store
+ * the address.
+ * sc->sc_arccom.ac_anaddr = GETMEM(CMMACOFF);
+ */
+ PUTREG(CMCMD, CM_CLR(CLR_POR));
+ log(LOG_WARNING,
+ "%s%d: intr: got spurious power on reset int\n",
+ ifp->if_name, ifp->if_unit);
+ }
+
+ if (maskedisr & CM_RECON) {
+ /*
+ * we dont need to:
+ * PUTREG(CMCMD, CM_CONF(CONF_LONG));
+ */
+ PUTREG(CMCMD, CM_CLR(CLR_RECONFIG));
+ sc->sc_arccom.ac_if.if_collisions++;
+
+ /*
+ * If less than 2 seconds per reconfig:
+ * If ARC_EXCESSIVE_RECONFIGS
+ * since last burst, complain and set treshold for
+ * warnings to ARC_EXCESSIVE_RECONS_REWARN.
+ *
+ * This allows for, e.g., new stations on the cable, or
+ * cable switching as long as it is over after
+ * (normally) 16 seconds.
+ *
+ * XXX TODO: check timeout bits in status word and
+ * double time if necessary.
+ */
+
+ callout_stop(&sc->sc_recon_ch);
+ newsec = time_second;
+ if ((newsec - sc->sc_recontime <= 2) &&
+ (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
+ log(LOG_WARNING,
+ "%s%d: excessive token losses, "
+ "cable problem?\n",
+ ifp->if_name, ifp->if_unit);
+ }
+ sc->sc_recontime = newsec;
+ callout_reset(&sc->sc_recon_ch, 15 * hz,
+ cm_reconwatch, (void *)sc);
+ }
+
+ if (maskedisr & CM_RI) {
+#if defined(CM_DEBUG) && (CM_DEBUG > 1)
+ printf("%s%d: intr: hard rint, act %d\n",
+ ifp->if_name, ifp->if_unit, sc->sc_rx_act);
+#endif
+
+ buffer = sc->sc_rx_act;
+ /* look if buffer is marked invalid: */
+ if (GETMEM(buffer*512) == 0) {
+ /*
+ * invalid marked buffer (or illegally
+ * configured sender)
+ */
+ log(LOG_WARNING,
+ "%s%d: spurious RX interupt or sender 0 "
+ " (ignored)\n", ifp->if_name, ifp->if_unit);
+ /*
+ * restart receiver on same buffer.
+ * XXX maybe better reset interface?
+ */
+ PUTREG(CMCMD, CM_RXBC(buffer));
+ } else {
+ if (++sc->sc_rx_fillcount > 1) {
+ sc->sc_intmask &= ~CM_RI;
+ PUTREG(CMSTAT, sc->sc_intmask);
+ } else {
+ buffer ^= 1;
+ sc->sc_rx_act = buffer;
+
+ /*
+ * Start receiver on other receive
+ * buffer. This also clears the RI
+ * interupt flag.
+ */
+ PUTREG(CMCMD, CM_RXBC(buffer));
+ /* in RX intr, so mask is ok for RX */
+
+#ifdef CM_DEBUG
+ printf("%s%d: strt rx for buf %d, "
+ "stat 0x%02x\n",
+ ifp->if_name, ifp->if_unit,
+ sc->sc_rx_act, GETREG(CMSTAT));
+#endif
+ }
+
+#ifdef CMSOFTCOPY
+ /*
+ * this one starts a soft int to copy out
+ * of the hw
+ */
+ softintr_schedule(sc->sc_rxcookie);
+#else
+ /* this one does the copy here */
+ cm_srint(sc);
+#endif
+ }
+ }
+ if (maskedisr & CM_TA) {
+ cm_tint(sc, isr);
+ }
+ isr = GETREG(CMSTAT);
+ maskedisr = isr & sc->sc_intmask;
+ } while (maskedisr);
+#if defined(CM_DEBUG) && (CM_DEBUG>1)
+ printf("%s%d: intr (exit): status 0x%02x, intmask 0x%02x\n",
+ ifp->if_name, ifp->if_unit, isr, sc->sc_intmask);
+#endif
+}
+
+void
+cm_reconwatch(arg)
+ void *arg;
+{
+ struct cm_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_arccom.ac_if;
+
+ if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
+ sc->sc_reconcount = 0;
+ log(LOG_WARNING, "%s%d: token valid again.\n",
+ ifp->if_name, ifp->if_unit);
+ }
+ sc->sc_reconcount = 0;
+}
+
+
+/*
+ * Process an ioctl request.
+ * This code needs some work - it looks pretty ugly.
+ */
+int
+cm_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct cm_softc *sc;
+ struct ifaddr *ifa;
+ struct ifreq *ifr;
+ int s, error;
+
+ error = 0;
+ sc = ifp->if_softc;
+ ifa = (struct ifaddr *)data;
+ ifr = (struct ifreq *)data;
+ s = splimp();
+
+#if defined(CM_DEBUG) && (CM_DEBUG > 2)
+ printf("%s%d: ioctl() called, cmd = 0x%lx\n",
+ ifp->if_name, ifp->if_unit, command);
+#endif
+
+ switch (command) {
+ case SIOCSIFADDR:
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ case SIOCSIFMTU:
+ error = arc_ioctl(ifp, command, 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.
+ */
+ cm_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } 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.
+ */
+ cm_init(sc);
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+ return (error);
+}
+
+/*
+ * watchdog routine for transmitter.
+ *
+ * We need this, because else a receiver whose hardware is alive, but whose
+ * software has not enabled the Receiver, would make our hardware wait forever
+ * Discovered this after 20 times reading the docs.
+ *
+ * Only thing we do is disable transmitter. We'll get an transmit timeout,
+ * and the int handler will have to decide not to retransmit (in case
+ * retransmission is implemented).
+ *
+ * This one assumes being called inside splimp()
+ */
+
+void
+cm_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct cm_softc *sc = ifp->if_softc;
+
+ PUTREG(CMCMD, CM_TXDIS);
+ return;
+}
diff --git a/sys/dev/cm/smc90cx6reg.h b/sys/dev/cm/smc90cx6reg.h
new file mode 100644
index 0000000..35e7afd
--- /dev/null
+++ b/sys/dev/cm/smc90cx6reg.h
@@ -0,0 +1,91 @@
+/* $NetBSD: smc90cx6reg.h,v 1.7 1999/02/16 23:34:13 is Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ignatios Souvatzis.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * chip offsets and bits for the SMC Arcnet chipset.
+ */
+
+#ifndef _SMC90CXVAR_H_
+#define _SMC90CXVAR_H_
+
+#define CM_IO_PORTS 16
+
+/* register offsets */
+
+#define CMSTAT 0
+#define CMCMD 1
+#define CMRESET 8
+
+/* memory offsets */
+#define CMCHECKBYTE 0
+#define CMMACOFF 1
+
+#define CM_TXDIS 0x01
+#define CM_RXDIS 0x02
+#define CM_TX(x) (0x03 | ((x)<<3))
+#define CM_RX(x) (0x04 | ((x)<<3))
+#define CM_RXBC(x) (0x84 | ((x)<<3))
+
+#define CM_CONF(x) (0x05 | (x))
+#define CLR_POR 0x08
+#define CLR_RECONFIG 0x10
+
+#define CM_CLR(x) (0x06 | (x))
+#define CONF_LONG 0x08
+#define CONF_SHORT 0x00
+
+/*
+ * These are not in the COM90C65 docs. Derived from the arcnet.asm
+ * packet driver by Philippe Prindeville and Russel Nelson.
+ */
+
+#define CM_LDTST(x) (0x07 | (x))
+#define TEST_ON 0x08
+#define TEST_OFF 0x00
+
+#define CM_TA 1 /* int mask also */
+#define CM_TMA 2
+#define CM_RECON 4 /* int mask also */
+#define CM_TEST 8 /* not in the COM90C65 docs (see above) */
+#define CM_POR 0x10 /* non maskable interrupt */
+#define CM_ET1 0x20 /* timeout value bits, normally 1 */
+#define CM_ET2 0x40 /* timeout value bits, normally 1 */
+#define CM_RI 0x80 /* int mask also */
+
+#endif
diff --git a/sys/dev/cm/smc90cx6var.h b/sys/dev/cm/smc90cx6var.h
new file mode 100644
index 0000000..6d00b8f
--- /dev/null
+++ b/sys/dev/cm/smc90cx6var.h
@@ -0,0 +1,103 @@
+/* $NetBSD: smc90cx6var.h,v 1.5 2000/03/23 07:01:32 thorpej Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ignatios Souvatzis.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * BAH (SMC 8bit ARCnet chipset) k/dpi
+ *
+ * The SMC 8bit ARCnet chip family uses a register and a memory window, which
+ * we get passed via bus_space_tags and bus_space_handles.
+ *
+ * As the reset functionality differs between the Amiga boards (using the
+ * 90c26 chip) and middle-aged ISA boards (using the 90c56 chip), we have
+ * a sc_reset callback function in the softc, which does a stop function
+ * (reset and leave dead) or a reset function depending on wether the 2nd
+ * parameter is 0 or 1.
+ */
+
+#ifndef _SMC90CX6VAR_H_
+#define _SMC90CX6VAR_H_
+
+#include <sys/callout.h>
+
+struct cm_softc {
+ struct arccom sc_arccom; /* Common arcnet structures */
+
+ int port_rid; /* resource id for port range */
+ struct resource *port_res; /* resource for port range */
+ int port_used; /* ports used */
+
+ int mem_rid; /* resource id for memory range */
+ struct resource *mem_res; /* resource for memory range */
+ int mem_used; /* memory used */
+
+ int irq_rid; /* resource id for irq */
+ struct resource *irq_res; /* resource for irq */
+ void * irq_handle; /* handle for irq handler */
+
+ void *sc_rxcookie; /* softcallback cookies */
+ void *sc_txcookie;
+ struct callout sc_recon_ch;
+ u_long sc_recontime; /* seconds only, I'm lazy */
+ u_long sc_reconcount; /* for the above */
+ u_long sc_reconcount_excessive; /* for the above */
+#define ARC_EXCESSIVE_RECONS 20
+#define ARC_EXCESSIVE_RECONS_REWARN 400
+ u_char sc_intmask;
+ u_char sc_rx_act; /* 2..3 */
+ u_char sc_tx_act; /* 0..1 */
+ u_char sc_rx_fillcount;
+ u_char sc_tx_fillcount;
+ u_char sc_broadcast[2]; /* is it a broadcast packet? */
+ u_char sc_retransmits[2]; /* unused at the moment */
+};
+
+int cm_attach __P((struct cm_softc *, int unit));
+void cmintr __P((void *));
+
+int cm_probe __P((device_t dev));
+void cm_stop __P((struct cm_softc *sc));
+
+int cm_alloc_port __P((device_t dev, int rid, int size));
+int cm_alloc_memory __P((device_t dev, int rid, int size));
+int cm_alloc_irq __P((device_t dev, int rid));
+void cm_release_resources __P((device_t dev));
+
+extern devclass_t cm_devclass;
+
+#endif
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 5d56a4c..ad17181 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -509,6 +509,7 @@ device musycc # LMC/SBE LMC1504 quad T1/E1
# Ethernets; it is MANDATORY when a Ethernet device driver is
# configured or token-ring is enabled.
# The `fddi' device provides generic code to support FDDI.
+# The `arcnet' device provides generic code to support Arcnet.
# The `sppp' device serves a similar role for certain types
# of synchronous PPP links (like `cx', `ar').
# The `sl' device implements the Serial Line IP (SLIP) service.
@@ -543,6 +544,7 @@ device ether #Generic Ethernet
device vlan #VLAN support
device token #Generic TokenRing
device fddi #Generic FDDI
+device arcnet #Generic Arcnet
device sppp #Generic Synchronous PPP
device loop 1 #Network loopback device
device bpf #Berkeley packet filter
@@ -1711,6 +1713,8 @@ device miibus
# the SysKonnect SK-9D21 and SK-9D41, and the embedded gigE NICs
# on Dell PowerEdge 2550 servers.
# cnw: Xircom CNW/Netware Airsurfer PC Card adapter
+# cm: Arcnet SMC COM90c26 / SMC COM90c56
+# (and SMC COM90c66 in '56 compatibility mode) adapters.
# cs: IBM Etherjet and other Crystal Semi CS89x0-based adapters
# cx: Cronyx/Sigma multiport sync/async (with Cisco or PPP framing)
# dc: Support for PCI fast ethernet adapters based on the DEC/Intel 21143
@@ -1829,6 +1833,11 @@ hint.ar.0.at="isa"
hint.ar.0.port="0x300"
hint.ar.0.irq="10"
hint.ar.0.maddr="0xd0000"
+device cm
+hint.cm.0.at="isa"
+hint.cm.0.port="0x2e0"
+hint.cm.0.irq="9"
+hint.cm.0.maddr="0xdc000"
device cs
hint.cs.0.at="isa"
hint.cs.0.port="0x300"
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 1d558b3..55427dd 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -117,11 +117,13 @@ SUBDIR+=aac \
acpi \
aic \
ar \
+ arcnet \
apm \
asr \
atspeaker \
bktr \
ciss \
+ cm \
coff \
el \
em \
diff --git a/sys/modules/arcnet/Makefile b/sys/modules/arcnet/Makefile
new file mode 100644
index 0000000..a88ae65
--- /dev/null
+++ b/sys/modules/arcnet/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../net
+
+KMOD= arcnet
+SRCS= if_arcsubr.c
+SRCS+= opt_inet.h opt_inet6.h
+
+opt_inet.h opt_inet6.h:
+ echo "#define INET 1" > ${.TARGET}
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/cm/Makefile b/sys/modules/cm/Makefile
new file mode 100644
index 0000000..3f2067b
--- /dev/null
+++ b/sys/modules/cm/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/cm
+
+KMOD= if_cm
+SRCS= smc90cx6.c if_cm_isa.c
+
+SRCS+= bus_if.h device_if.h isa_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c
new file mode 100644
index 0000000..d47dee9
--- /dev/null
+++ b/sys/net/if_arcsubr.c
@@ -0,0 +1,780 @@
+/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1994, 1995 Ignatios Souvatzis
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
+ * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
+ *
+ */
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_arc.h>
+#include <net/if_arp.h>
+#include <net/bpf.h>
+
+#if defined(INET) || defined(INET6)
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef INET6
+#include <netinet6/nd6.h>
+#endif
+
+MODULE_VERSION(arcnet, 1);
+
+#define ARCNET_ALLOW_BROKEN_ARP
+
+static struct mbuf *arc_defrag __P((struct ifnet *, struct mbuf *));
+
+u_int8_t arcbroadcastaddr = 0;
+
+#define senderr(e) { error = (e); goto bad;}
+#define SIN(s) ((struct sockaddr_in *)s)
+
+/*
+ * ARCnet output routine.
+ * Encapsulate a packet of type family for the local net.
+ * Assumes that ifp is actually pointer to arccom structure.
+ */
+int
+arc_output(ifp, m, dst, rt0)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt0;
+{
+ struct mbuf *mcopy;
+ struct rtentry *rt;
+ struct arccom *ac;
+ struct arc_header *ah;
+ struct arphdr *arph;
+ int error;
+ u_int8_t atype, adst;
+#if __FreeBSD_version < 500000
+ int s;
+#endif
+
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ return(ENETDOWN); /* m, m1 aren't initialized yet */
+
+ error = 0;
+ ac = (struct arccom *)ifp;
+ mcopy = NULL;
+
+ if ((rt = rt0)) {
+ if ((rt->rt_flags & RTF_UP) == 0) {
+ if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
+ rt->rt_refcnt--;
+ else
+ senderr(EHOSTUNREACH);
+ }
+ if (rt->rt_flags & RTF_GATEWAY) {
+ if (rt->rt_gwroute == 0)
+ goto lookup;
+ if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
+ rtfree(rt); rt = rt0;
+ lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
+ if ((rt = rt->rt_gwroute) == 0)
+ senderr(EHOSTUNREACH);
+ }
+ }
+ if (rt->rt_flags & RTF_REJECT)
+ if (rt->rt_rmx.rmx_expire == 0 ||
+ time_second < rt->rt_rmx.rmx_expire)
+ senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
+ }
+
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+
+ /*
+ * For now, use the simple IP addr -> ARCnet addr mapping
+ */
+ if (m->m_flags & (M_BCAST|M_MCAST))
+ adst = arcbroadcastaddr; /* ARCnet broadcast address */
+ else if (ifp->if_flags & IFF_NOARP)
+ adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
+ else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
+ return 0; /* not resolved yet */
+
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & (M_BCAST|M_MCAST)) &&
+ (ifp->if_flags & IFF_SIMPLEX))
+ mcopy = m_copy(m, 0, (int)M_COPYALL);
+ atype = (ifp->if_flags & IFF_LINK0) ?
+ ARCTYPE_IP_OLD : ARCTYPE_IP;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+#ifdef OLDIP6OUTPUT
+ if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
+ return(0); /* if not yet resolves */
+#else
+ if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
+ return(0); /* it must be impossible, but... */
+#endif /* OLDIP6OUTPUT */
+ atype = ARCTYPE_INET6;
+ break;
+#endif
+
+ case AF_UNSPEC:
+ ah = (struct arc_header *)dst->sa_data;
+ adst = ah->arc_dhost;
+ atype = ah->arc_type;
+
+ if (atype == ARCTYPE_ARP) {
+ atype = (ifp->if_flags & IFF_LINK0) ?
+ ARCTYPE_ARP_OLD: ARCTYPE_ARP;
+
+#ifdef ARCNET_ALLOW_BROKEN_ARP
+ /*
+ * XXX It's not clear per RFC826 if this is needed, but
+ * "assigned numbers" say this is wrong.
+ * However, e.g., AmiTCP 3.0Beta used it... we make this
+ * switchable for emergency cases. Not perfect, but...
+ */
+ arph = mtod(m, struct arphdr *);
+ if (ifp->if_flags & IFF_LINK2)
+ arph->ar_pro = atype - 1;
+#endif
+ }
+ break;
+
+ default:
+ printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
+ dst->sa_family);
+ senderr(EAFNOSUPPORT);
+ }
+
+ if (mcopy)
+ (void) if_simloop(ifp, mcopy, dst->sa_family, 0);
+
+ M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
+ if (m == 0)
+ senderr(ENOBUFS);
+ ah = mtod(m, struct arc_header *);
+ ah->arc_type = atype;
+ ah->arc_dhost = adst;
+ ah->arc_shost = *IF_LLADDR(ifp);
+
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m);
+
+#if __FreeBSD_version < 500000
+ s = splimp();
+
+ /*
+ * Queue message on interface, and start output if interface
+ * not yet active.
+ */
+ if (IF_QFULL(&ifp->if_snd)) {
+ IF_DROP(&ifp->if_snd);
+ splx(s);
+ senderr(ENOBUFS);
+ }
+ ifp->if_obytes += m->m_pkthdr.len;
+ IF_ENQUEUE(&ifp->if_snd, m);
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ splx(s);
+#else
+ if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
+ m = 0;
+ senderr(ENOBUFS);
+ }
+#endif
+
+ return (error);
+
+bad:
+ if (m)
+ m_freem(m);
+ return (error);
+}
+
+void
+arc_frag_init(ifp)
+ struct ifnet *ifp;
+{
+ struct arccom *ac;
+
+ ac = (struct arccom *)ifp;
+ ac->curr_frag = 0;
+}
+
+struct mbuf *
+arc_frag_next(ifp)
+ struct ifnet *ifp;
+{
+ struct arccom *ac;
+ struct mbuf *m;
+ struct arc_header *ah;
+
+ ac = (struct arccom *)ifp;
+ if ((m = ac->curr_frag) == 0) {
+ int tfrags;
+
+ /* dequeue new packet */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ return 0;
+
+ ah = mtod(m, struct arc_header *);
+ if (!arc_isphds(ah->arc_type))
+ return m;
+
+ ++ac->ac_seqid; /* make the seqid unique */
+ tfrags = (m->m_pkthdr.len + 503) / 504;
+ ac->fsflag = 2 * tfrags - 3;
+ ac->sflag = 0;
+ ac->rsflag = ac->fsflag;
+ ac->arc_dhost = ah->arc_dhost;
+ ac->arc_shost = ah->arc_shost;
+ ac->arc_type = ah->arc_type;
+
+ m_adj(m, ARC_HDRLEN);
+ ac->curr_frag = m;
+ }
+
+ /* split out next fragment and return it */
+ if (ac->sflag < ac->fsflag) {
+ /* we CAN'T have short packets here */
+ ac->curr_frag = m_split(m, 504, M_DONTWAIT);
+ if (ac->curr_frag == 0) {
+ m_free(m);
+ return 0;
+ }
+
+ M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
+ if (m == 0) {
+ m_free(ac->curr_frag);
+ ac->curr_frag = 0;
+
+ m_free(m);
+ return 0;
+ }
+
+ ah = mtod(m, struct arc_header *);
+ ah->arc_flag = ac->rsflag;
+ ah->arc_seqid = ac->ac_seqid;
+
+ ac->sflag += 2;
+ ac->rsflag = ac->sflag;
+ } else if ((m->m_pkthdr.len >=
+ ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
+ (m->m_pkthdr.len <=
+ ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
+ ac->curr_frag = 0;
+
+ M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
+ if (m == 0)
+ return 0;
+
+ ah = mtod(m, struct arc_header *);
+ ah->arc_flag = 0xFF;
+ ah->arc_seqid = 0xFFFF;
+ ah->arc_type2 = ac->arc_type;
+ ah->arc_flag2 = ac->sflag;
+ ah->arc_seqid2 = ac->ac_seqid;
+ } else {
+ ac->curr_frag = 0;
+
+ M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
+ if (m == 0)
+ return 0;
+
+ ah = mtod(m, struct arc_header *);
+ ah->arc_flag = ac->sflag;
+ ah->arc_seqid = ac->ac_seqid;
+ }
+
+ ah->arc_dhost = ac->arc_dhost;
+ ah->arc_shost = ac->arc_shost;
+ ah->arc_type = ac->arc_type;
+
+ return m;
+}
+
+/*
+ * Defragmenter. Returns mbuf if last packet found, else
+ * NULL. frees imcoming mbuf as necessary.
+ */
+
+__inline struct mbuf *
+arc_defrag(ifp, m)
+ struct ifnet *ifp;
+ struct mbuf *m;
+{
+ struct arc_header *ah, *ah1;
+ struct arccom *ac;
+ struct ac_frag *af;
+ struct mbuf *m1;
+ char *s;
+ int newflen;
+ u_char src,dst,typ;
+
+ ac = (struct arccom *)ifp;
+
+ if (m->m_len < ARC_HDRNEWLEN) {
+ m = m_pullup(m, ARC_HDRNEWLEN);
+ if (m == NULL) {
+ ++ifp->if_ierrors;
+ return NULL;
+ }
+ }
+
+ ah = mtod(m, struct arc_header *);
+ typ = ah->arc_type;
+
+ if (!arc_isphds(typ))
+ return m;
+
+ src = ah->arc_shost;
+ dst = ah->arc_dhost;
+
+ if (ah->arc_flag == 0xff) {
+ m_adj(m, 4);
+
+ if (m->m_len < ARC_HDRNEWLEN) {
+ m = m_pullup(m, ARC_HDRNEWLEN);
+ if (m == NULL) {
+ ++ifp->if_ierrors;
+ return NULL;
+ }
+ }
+
+ ah = mtod(m, struct arc_header *);
+ }
+
+ af = &ac->ac_fragtab[src];
+ m1 = af->af_packet;
+ s = "debug code error";
+
+ if (ah->arc_flag & 1) {
+ /*
+ * first fragment. We always initialize, which is
+ * about the right thing to do, as we only want to
+ * accept one fragmented packet per src at a time.
+ */
+ if (m1 != NULL)
+ m_freem(m1);
+
+ af->af_packet = m;
+ m1 = m;
+ af->af_maxflag = ah->arc_flag;
+ af->af_lastseen = 0;
+ af->af_seqid = ah->arc_seqid;
+
+ return NULL;
+ /* notreached */
+ } else {
+ /* check for unfragmented packet */
+ if (ah->arc_flag == 0)
+ return m;
+
+ /* do we have a first packet from that src? */
+ if (m1 == NULL) {
+ s = "no first frag";
+ goto outofseq;
+ }
+
+ ah1 = mtod(m1, struct arc_header *);
+
+ if (ah->arc_seqid != ah1->arc_seqid) {
+ s = "seqid differs";
+ goto outofseq;
+ }
+
+ if (typ != ah1->arc_type) {
+ s = "type differs";
+ goto outofseq;
+ }
+
+ if (dst != ah1->arc_dhost) {
+ s = "dest host differs";
+ goto outofseq;
+ }
+
+ /* typ, seqid and dst are ok here. */
+
+ if (ah->arc_flag == af->af_lastseen) {
+ m_freem(m);
+ return NULL;
+ }
+
+ if (ah->arc_flag == af->af_lastseen + 2) {
+ /* ok, this is next fragment */
+ af->af_lastseen = ah->arc_flag;
+ m_adj(m,ARC_HDRNEWLEN);
+
+ /*
+ * m_cat might free the first mbuf (with pkthdr)
+ * in 2nd chain; therefore:
+ */
+
+ newflen = m->m_pkthdr.len;
+
+ m_cat(m1,m);
+
+ m1->m_pkthdr.len += newflen;
+
+ /* is it the last one? */
+ if (af->af_lastseen > af->af_maxflag) {
+ af->af_packet = NULL;
+ return(m1);
+ } else
+ return NULL;
+ }
+ s = "other reason";
+ /* if all else fails, it is out of sequence, too */
+ }
+outofseq:
+ if (m1) {
+ m_freem(m1);
+ af->af_packet = NULL;
+ }
+
+ if (m)
+ m_freem(m);
+
+ log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
+ ifp->if_name, ifp->if_unit, s);
+
+ return NULL;
+}
+
+/*
+ * return 1 if Packet Header Definition Standard, else 0.
+ * For now: old IP, old ARP aren't obviously. Lacking correct information,
+ * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
+ * (Apple and Novell corporations were involved, among others, in PHDS work).
+ * Easiest is to assume that everybody else uses that, too.
+ */
+int
+arc_isphds(type)
+ u_int8_t type;
+{
+ return (type != ARCTYPE_IP_OLD &&
+ type != ARCTYPE_ARP_OLD &&
+ type != ARCTYPE_DIAGNOSE);
+}
+
+/*
+ * Process a received Arcnet packet;
+ * the packet is in the mbuf chain m with
+ * the ARCnet header.
+ */
+void
+arc_input(ifp, m)
+ struct ifnet *ifp;
+ struct mbuf *m;
+{
+ struct arc_header *ah;
+ struct ifqueue *inq;
+ u_int8_t atype;
+#ifdef INET
+ struct arphdr *arph;
+#endif
+#if __FreeBSD_version < 500000
+ int s;
+#endif
+
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return;
+ }
+
+ /* possibly defragment: */
+ m = arc_defrag(ifp, m);
+ if (m == NULL)
+ return;
+
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m);
+
+ ah = mtod(m, struct arc_header *);
+
+ ifp->if_ibytes += m->m_pkthdr.len;
+
+ if (arcbroadcastaddr == ah->arc_dhost) {
+ m->m_flags |= M_BCAST|M_MCAST;
+ ifp->if_imcasts++;
+ }
+
+ atype = ah->arc_type;
+ switch (atype) {
+#ifdef INET
+ case ARCTYPE_IP:
+ m_adj(m, ARC_HDRNEWLEN);
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+
+ case ARCTYPE_IP_OLD:
+ m_adj(m, ARC_HDRLEN);
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+
+ case ARCTYPE_ARP:
+ if (ifp->if_flags & IFF_NOARP) {
+ /* Discard packet if ARP is disabled on interface */
+ m_freem(m);
+ return;
+ }
+ m_adj(m, ARC_HDRNEWLEN);
+ schednetisr(NETISR_ARP);
+ inq = &arpintrq;
+#ifdef ARCNET_ALLOW_BROKEN_ARP
+ mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
+#endif
+ break;
+
+ case ARCTYPE_ARP_OLD:
+ if (ifp->if_flags & IFF_NOARP) {
+ /* Discard packet if ARP is disabled on interface */
+ m_freem(m);
+ return;
+ }
+ m_adj(m, ARC_HDRLEN);
+ schednetisr(NETISR_ARP);
+ inq = &arpintrq;
+ arph = mtod(m, struct arphdr *);
+#ifdef ARCNET_ALLOW_BROKEN_ARP
+ mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
+#endif
+ break;
+#endif
+#ifdef INET6
+ case ARCTYPE_INET6:
+ m_adj(m, ARC_HDRNEWLEN);
+ schednetisr(NETISR_IPV6);
+ inq = &ip6intrq;
+ break;
+#endif
+ default:
+ m_freem(m);
+ return;
+ }
+
+#if __FreeBSD_version < 500000
+ s = splimp();
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ m_freem(m);
+ } else
+ IF_ENQUEUE(inq, m);
+ splx(s);
+#else
+ IF_HANDOFF(inq, m, NULL);
+#endif
+}
+
+/*
+ * Convert Arcnet address to printable (loggable) representation.
+ */
+static char digits[] = "0123456789abcdef";
+char *
+arc_sprintf(ap)
+ u_int8_t *ap;
+{
+ static char arcbuf[3];
+ char *cp = arcbuf;
+
+ *cp++ = digits[*ap >> 4];
+ *cp++ = digits[*ap++ & 0xf];
+ *cp = 0;
+ return (arcbuf);
+}
+
+/*
+ * Register (new) link level address.
+ */
+void
+arc_storelladdr(ifp, lla)
+ struct ifnet *ifp;
+ u_int8_t lla;
+{
+ *IF_LLADDR(ifp) = lla;
+}
+
+/*
+ * Perform common duties while attaching to interface list
+ */
+void
+arc_ifattach(ifp, lla)
+ struct ifnet *ifp;
+ u_int8_t lla;
+{
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+ struct arccom *ac;
+
+ if_attach(ifp);
+ ifp->if_type = IFT_ARCNET;
+ ifp->if_addrlen = 1;
+ ifp->if_hdrlen = ARC_HDRLEN;
+ ifp->if_mtu = 1500;
+ if (ifp->if_baudrate == 0)
+ ifp->if_baudrate = 2500000;
+#if __FreeBSD_version < 500000
+ ifa = ifnet_addrs[ifp->if_index - 1];
+#else
+ ifa = ifaddr_byindex(ifp->if_index);
+#endif
+ KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ARCNET;
+ sdl->sdl_alen = ifp->if_addrlen;
+
+ if (ifp->if_flags & IFF_BROADCAST)
+ ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
+
+ ac = (struct arccom *)ifp;
+ ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
+ if (lla == 0) {
+ /* XXX this message isn't entirely clear, to me -- cgd */
+ log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n",
+ ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
+ }
+ arc_storelladdr(ifp, lla);
+
+ ifp->if_broadcastaddr = &arcbroadcastaddr;
+
+ bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
+}
+
+void
+arc_ifdetach(ifp)
+ struct ifnet *ifp;
+{
+ bpfdetach(ifp);
+ if_detach(ifp);
+}
+
+int
+arc_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0;
+
+ switch (command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ifp->if_init(ifp->if_softc); /* before arpwhohas */
+ arp_ifinit(ifp, ifa);
+ break;
+#endif
+ default:
+ ifp->if_init(ifp->if_softc);
+ break;
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifr == NULL)
+ error = EAFNOSUPPORT;
+ else {
+ switch (ifr->ifr_addr.sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ error = 0;
+ break;
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ }
+ break;
+
+ case SIOCSIFMTU:
+ /*
+ * Set the interface MTU.
+ * mtu can't be larger than ARCMTU for RFC1051
+ * and can't be larger than ARC_PHDS_MTU
+ */
+ if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
+ ifr->ifr_mtu > ARC_PHDS_MAXMTU)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+#if 0
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+
+ sa = (struct sockaddr *) & ifr->ifr_data;
+ bcopy(IFP2AC(ifp)->ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+#endif
+ }
+
+ return (error);
+}
OpenPOWER on IntegriCloud