BSD 4_4 release
[unix-history] / usr / src / sys / i386 / isa / if_apx.c
index 69e3a59..3875b42 100644 (file)
@@ -1,10 +1,36 @@
 /*
 /*
- * Copyright (c) 1982, 1990 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * 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.
  *
  *
- *     @(#)if_apx.c    7.1 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)if_apx.c    8.1 (Berkeley) 6/11/93
  */
 
 /*
  */
 
 /*
 #include "apx.h"
 #if NAPX > 0
 
 #include "apx.h"
 #if NAPX > 0
 
-#include "param.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "ioctl.h"
-#include "errno.h"
-#include "syslog.h"
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
 
 
-#include "net/if.h"
-#include "net/netisr.h"
-#include "netccitt/x25.h"
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/if_types.h>
+#ifdef CCITT
+#include <netccitt/x25.h>
+int x25_rtrequest(), x25_ifoutput();
+#endif
 
 
-#include "apxreg.h"
+#include <i386/isa/if_apxreg.h>
 
 int    apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
 
 int    apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
-int    apxinit(), x25_ifoutput(), apxioctl(), apxreset();
-void   apx_ifattach(), apxinput(), apxintr(), apxtint(), apaxrint();
+int    apxinit(), apxoutput(), apxioctl(), apxreset(), apxdebug = 0;
+void   apx_ifattach(), apxtest(), apxinput(), apxintr(), apxtint(), apxrint();
 
 struct apx_softc {
        struct  ifnet apx_if;
 
 struct apx_softc {
        struct  ifnet apx_if;
-       caddr_t apx_device;             /* e.g. isa_device */
-       u_short apx_csr4;               /* byte gender, set in mach dep code */
+       caddr_t apx_device;             /* e.g. isa_device, vme_device, etc. */
        struct  apc_reg *apx_reg;       /* control regs for both subunits */
        struct  apc_mem *apx_hmem;      /* Host addr for shared memory */
        struct  apc_mem *apx_dmem;      /* Device (chip) addr for shared mem */
        struct  sgcp *apx_sgcp;         /* IO control port for this subunit */
        struct  apc_reg *apx_reg;       /* control regs for both subunits */
        struct  apc_mem *apx_hmem;      /* Host addr for shared memory */
        struct  apc_mem *apx_dmem;      /* Device (chip) addr for shared mem */
        struct  sgcp *apx_sgcp;         /* IO control port for this subunit */
-       struct  apc_modes apx_modes;    /* Parameters, as amended by ioctls */
+       int     apx_flags;              /* Flags specific to this driver */
+#define APXF_CHIPHERE  0x01            /* mk5025 present */
        int     apx_rxnum;              /* Last receiver dx we looked at */
        int     apx_txnum;              /* Last tranmistter dx we stomped on */
        int     apx_txcnt;              /* Number of packets queued for tx*/
        int     apx_rxnum;              /* Last receiver dx we looked at */
        int     apx_txnum;              /* Last tranmistter dx we stomped on */
        int     apx_txcnt;              /* Number of packets queued for tx*/
-} apx_softc[2 * NAPX], *apx_lastsoftc = apx_softc;
+       u_int   apx_msize;
+       struct  sgae apx_csr23;         /* 24 bit init addr, as seen by chip */
+       u_short apx_csr4;               /* byte gender, set in mach dep code */
+       struct  apc_modes apx_modes;    /* Parameters, as amended by ioctls */
+} apx_softc[2 * NAPX];
 
 struct apxstat {
 
 struct apxstat {
-       int     nulltx;
-       int     pint;
-};
+       int     rxnull;                 /* no rx bufs ready this interrupt */
+       int     rxnrdy;                 /* expected rx buf not ready */
+       int     rx2big;                 /* expected rx buf not ready */
+       int     txnull;
+       int     pint;                   /* new primitive available interrupt */
+       int     rint;                   /* receive interrupts */
+       int     tint;                   /* transmit interrupts */
+       int     anyint;                 /* note all interrupts */
+       int     queued;                 /* got through apxinput */
+       int     nxpctd;                 /* received while if was down */
+       int     rstfld;                 /* reset didn't work */
+} apxstat;
 
 /* default operating paramters for devices */
 struct apc_modes apx_default_modes = {
 
 /* default operating paramters for devices */
 struct apc_modes apx_default_modes = {
@@ -67,26 +110,25 @@ struct     apc_modes apx_default_modes = {
    -80,                /* apm_sgob.tp; */
  },
  2,            /* apm_txwin; */
    -80,                /* apm_sgob.tp; */
  },
  2,            /* apm_txwin; */
5,            /* apm_apxmode; */
- 0,            /* apm_apxaltmode; */
1,            /* apm_apxmode: RS_232 connector and modem clock; */
+ 0,            /* apm_apxaltmode: enable dtr, disable X.21 connector; */
  IFT_X25,      /* apm_iftype; */
 };
 
 /* Begin bus & endian dependence */
 
  IFT_X25,      /* apm_iftype; */
 };
 
 /* Begin bus & endian dependence */
 
-#include "i386/isa/if_apxreg.h"
-#include "i386/isa/isa_device.h"
+#include <i386/isa/isa_device.h>
 
 struct isa_driver apxdriver = {
        apxprobe, apxattach, "apx",
 };
 
 #define SG_RCSR(apx, csrnum) \
 
 struct isa_driver apxdriver = {
        apxprobe, apxattach, "apx",
 };
 
 #define SG_RCSR(apx, csrnum) \
-        (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1),
-         inw(&(apx->apx_sgcp->sgcp_rdp))
+        (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
+         inw(&(apx->apx_sgcp->sgcp_rdp)))
 
 #define SG_WCSR(apx, csrnum, data) \
 
 #define SG_WCSR(apx, csrnum, data) \
-        (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1),
+        (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
          outw(&(apx->apx_sgcp->sgcp_rdp), data))
 
 #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
          outw(&(apx->apx_sgcp->sgcp_rdp), data))
 
 #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
@@ -97,45 +139,46 @@ struct     isa_driver apxdriver = {
 apxprobe(id)
        register struct isa_device *id;
 {
 apxprobe(id)
        register struct isa_device *id;
 {
-       int     moffset, subunit, unit = id->id_unit << 1;
-       struct  apc_reg *reg = id->id_iobase;
+       int     moffset = 0, nchips = 2, unit = id->id_unit << 1, subunit;
+       struct  apc_reg *reg = (struct apc_reg *)id->id_iobase;
        register struct apx_softc *apx = apx_softc + unit;
 
        register struct apx_softc *apx = apx_softc + unit;
 
-       /* Set and read DTR defeat in channel 0 to test presence of apc */
-       outb(&reg->axr_altmode, 4);
-       if (inb(&reg->axr_altmode) == 0)
-               return 0;                       /* No board present */
-
-       for (subunit = 0; subunit < 2; subunit++, apx++) {
-               /* Set and read DTR mode to test present of SGS thompson chip */
-               apx->apx_if.if_unit = unit++;
-               apx->apx_sgcp = reg->axr_sgcb + subunit;
-               SG_WCSR(apx, 5, 0x08);
-               if ((SG_RCSR(apx, 5) & 0xff08) != 0x08)) {
-                       apxerror(apx, "no mk5025 for channel", subunit);
-                       continue;
-               }
-               moffset = subunit ? id->id_msize >> 1 : 0;
+       /*
+        * Probing for the second MK5025 on all ISA/EISA adax boards
+        * manufactured prior to July 1992 (and some time following)
+        * will hang the bus and the system.  Thus, it is essential
+        * not to probe for the second mk5025 if it is known not to be there.
+        * As the current config scheme for 386BSD does not have a flags
+        * field, we adopt the convention of using the low order bit of
+        * the memsize to warn us that we have a single chip board.
+        */
+       if (id->id_msize & 1)
+               nchips = 1;
+       for (subunit = 0; subunit < nchips; subunit++) {
+               apx->apx_msize  = id->id_msize >> 1;
                apx->apx_hmem   = (struct apc_mem *) (id->id_maddr + moffset);
                apx->apx_hmem   = (struct apc_mem *) (id->id_maddr + moffset);
-               apx->apx_dmem   = (struct apc_mem *) (moffset);
-               apx->apx_modes  = apx_default_modes;
-               apx->apx_device = (caddr_t) id;
+               apx->apx_dmem   = (struct apc_mem *) moffset;
+               apx->apx_device = (caddr_t) id;
                apx->apx_reg    = reg;
                apx->apx_reg    = reg;
-               apx->apx_csr4   = 0x0110;       /* no byte swapping for PC-AT */
+               apx->apx_sgcp   = reg->axr_sgcp + subunit;
+               apx->apx_csr4   = 0x0210;       /* no byte swapping for PC-AT */
+               apx->apx_modes  = apx_default_modes;
+               apx->apx_if.if_unit = unit++;
+               moffset = apx->apx_msize;
+               apxtest(apx++);
        }
        return 1;
 }
 
 apxattach(id)
        }
        return 1;
 }
 
 apxattach(id)
-       register struct isa_device *id;
+       struct  isa_device *id;
 {
 {
-       int     unit = id->id_unit + id->id_unit;
+       register struct apx_softc *apx = apx_softc + (id->id_unit << 1);
 
 
-       apx_ifattach(unit);
-       apx_ifattach(unit + 1);
-       return (0);
+       apx_ifattach(&((apx++)->apx_if));
+       apx_ifattach(&(apx->apx_if));
+       return 0;
 }
 }
-
 /* End bus & endian dependence */
 
 /*
 /* End bus & endian dependence */
 
 /*
@@ -143,24 +186,23 @@ apxattach(id)
  * record.  System will initialize the interface when it is ready
  * to accept packets.
  */
  * record.  System will initialize the interface when it is ready
  * to accept packets.
  */
-apx_ifattach(unit)
+void
+apx_ifattach(ifp)
+       register struct ifnet *ifp;
 {
 {
-       register struct ifnet *ifp = &(apx_softc[unit].apx_if);
        /*
         * Initialize ifnet structure
         */
        /*
         * Initialize ifnet structure
         */
-       if (apx_softc[unit].apx_device == 0)
-               return;
-       ifp->if_name = "apc";
-       ifp->if_mtu = SGMTU;
-       ifp->if_init = apxinit;
-       ifp->if_output = x25_ifoutput;
-       ifp->if_start = apxstart;
-       ifp->if_ioctl = apxioctl;
-       ifp->if_reset = apxreset;
-       ifp->if_type = apx_default_modes.axp_iftype;
-       ifp->if_hdrlen = 5;
-       ifp->if_addrlen = 8;
+       ifp->if_name    = "apc";
+       ifp->if_mtu     = SGMTU;
+       ifp->if_init    = apxinit;
+       ifp->if_output  = apxoutput;
+       ifp->if_start   = apxstart;
+       ifp->if_ioctl   = apxioctl;
+       ifp->if_reset   = apxreset;
+       ifp->if_type    = apx_default_modes.apm_iftype;
+       ifp->if_hdrlen  = 5;
+       ifp->if_addrlen = 8;
        if_attach(ifp);
 }
 /*
        if_attach(ifp);
 }
 /*
@@ -181,6 +223,36 @@ apxinit(unit)
        return 0;
 }
 
        return 0;
 }
 
+apxctr(apx)
+       register struct apx_softc *apx;
+{
+       APX_WCSR(apx, axr_ccr, 0xB0); /* select ctr 2, write lsb+msb, mode 0 */
+       APX_WCSR(apx, axr_cnt2, 0x1);
+       APX_WCSR(apx, axr_cnt2, 0x0);
+       DELAY(50);
+       APX_WCSR(apx, axr_ccr, 0xE8); /* latch status, ctr 2; */
+       return (APX_RCSR(apx, axr_cnt2));
+}
+
+void
+apxtest(apx)
+       register struct apx_softc *apx;
+{
+       int i =  0;
+
+       if ((apx->apx_if.if_unit & 1) == 0 && (i = apxctr(apx)) == 0)
+               apxerror(apx, "no response from timer chip", 0);
+       if (SG_RCSR(apx, 1) & 0x8000)
+               SG_WCSR(apx, 1, 0x8040);
+       SG_WCSR(apx, 4, apx->apx_csr4);
+       SG_WCSR(apx, 5, 0x08);          /* Set DTR mode in SGS thompson chip */
+       if (((i = SG_RCSR(apx, 5)) & 0xff08) != 0x08)
+               apxerror(apx, "no mk5025, csr5 high bits are", i);
+       else
+               apx->apx_flags |= APXF_CHIPHERE;
+       (void) apx_uprim(apx, SG_STOP, "stop after probing");
+}
+
 apxreset(unit)
        int     unit;
 {
 apxreset(unit)
        int     unit;
 {
@@ -195,38 +267,41 @@ apxreset(unit)
        MODE(apm_apxaltmode);
        APX_WCSR(apx, axr_mode, apm_apxmode);
        APX_WCSR(apx, axr_altmode, apm_apxaltmode);
        MODE(apm_apxaltmode);
        APX_WCSR(apx, axr_mode, apm_apxmode);
        APX_WCSR(apx, axr_altmode, apm_apxaltmode);
-       apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = apx->apx_rxnt = 0;
-
-       if (apx_uprim(apx, SG_STOP, "stop") ||
-           !(apx->apx_if.if_flags & IFF_UP))
+       (void) apxctr(apx);
+       (void) apx_uprim(apx, SG_STOP, "stop to reset");
+       if ((apx->apx_if.if_flags & IFF_UP) == 0)
                return 0;
                return 0;
-       apx_meminit(apx->apc_mem, apx); /* also sets CSR2 */
-       SG_WCSR(apx, 3, (int)apx->apx_dmem);
+       apx_meminit(apx->apx_hmem, apx);
        SG_WCSR(apx, 4, apx->apx_csr4);
        SG_WCSR(apx, 4, apx->apx_csr4);
-       if (apx_uprim(apx, SG_INIT, "init request")) ||
+       SG_WCSR(apx, 2, apx->apx_csr23.f_hi);
+       SG_WCSR(apx, 3, apx->apx_csr23.lo);
+       if (apx_uprim(apx, SG_INIT, "init request") ||
            apx_uprim(apx, SG_STAT, "status request") ||
            apx_uprim(apx, SG_TRANS, "transparent mode"))
                return 0;
        SG_WCSR(apx, 0, SG_INEA);
            apx_uprim(apx, SG_STAT, "status request") ||
            apx_uprim(apx, SG_TRANS, "transparent mode"))
                return 0;
        SG_WCSR(apx, 0, SG_INEA);
-       return 1:
+       return 1;
 }
 
 apx_uprim(apx, request, ident)
 }
 
 apx_uprim(apx, request, ident)
-       int request;
-       char *ident;
        register struct apx_softc *apx;
        register struct apx_softc *apx;
+       char *ident;
 {
        register int timo = 0;
 {
        register int timo = 0;
-       int reply = SG_RCSR(apx, 1);
+       int reply;
 
 
-       if (reply & x8040)
-               SG_WCRS(1, x8040); /* Magic! */
+       if ((apx->apx_flags & APXF_CHIPHERE) == 0)
+               return 1;       /* maybe even should panic . . . */
+       if ((reply = SG_RCSR(apx, 1)) & 0x8040)
+               SG_WCSR(apx, 1, 0x8040); /* Magic! */
+       if (request == SG_STOP && (SG_RCSR(apx, 0) & SG_STOPPED))
+               return 0;
        SG_WCSR(apx, 1, request | SG_UAV);
        do {
        SG_WCSR(apx, 1, request | SG_UAV);
        do {
-               reply = SG_RCRS(1);
-               if (timo >= TIMO | reply & 0x8000) {
-                       apxerror(apx, ident, reply);
-                       return 1;
+               reply = SG_RCSR(apx, 1);
+               if (timo++ >= TIMO || (reply & 0x8000)) {
+                               apxerror(apx, ident, reply);
+                               return 1;
                }
        } while (reply & SG_UAV);
        return 0;
                }
        } while (reply & SG_UAV);
        return 0;
@@ -238,28 +313,27 @@ apx_meminit(apc, apx)
 {
        register struct apc_mem *apcbase = apx->apx_dmem;
        register int i;
 {
        register struct apc_mem *apcbase = apx->apx_dmem;
        register int i;
-#define LOWADDR(e) (((u_long)&(apcbase->(e))) & 0xffff)
-#define HIADDR(e) ((((u_long)&(apcbase->(e))) >> 16) & 0xff)
-#define SET_SGDX(dx, f, a, b, m) \
-       { (dx).sgdx_addr = LOWADDR(a); (dx).sgdx_bcnt = (b);\
-         (dx).sgdx_mcnt = (m); (dx).sgdx_flags = (f) | HIADDR(a); }
-
-       bzero((caddr_t)apc, LOWADDR(apc_rxmd[0]));
-       apc->apc_mode = 0x8040; /* 2 flag spacing, trans mode, 16bit FCS */
+#define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff)
+#define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff)
+#define SET_SGAE(d, f, a) {(d).lo = LOWADDR(a); (d).f_hi = (f) | HIADDR(a);}
+#define SET_SGDX(d, f, a, b) \
+       {SET_SGAE((d).sgdx_ae, f, a); (d).sgdx_mcnt = (d).sgdx_bcnt = (b);}
+
+       apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0;
+       bzero((caddr_t)apc, ((caddr_t)(&apc->apc_rxmd[0])) - (caddr_t)apc);
+       apc->apc_mode = 0x0108; /* 2 flag spacing, leave addr & ctl, do CRC16 */
        apc->apc_sgop = apx->apx_modes.apm_sgop;
        apc->apc_sgop = apx->apx_modes.apm_sgop;
-       apc->apc_rlen = SG_RLEN | HIADDR(apc_rxmd[0]);
-       apc->apc_rdra = LOWADDR(apc_rxmd[0]);
-       apc->apc_rlen = SG_TLEN | apx->apx_modes.apm_txwin |HIADDR(apc_txmd[0]);
-       apc->apc_tdra = LOWADDR(apc_txmd[0]);
-       SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf, -SGMTU, 0);
-       SET_SGDX(apc->apc_txtid, 0, apc_txidbuf, -SGMTU, 0);
-       apc->apc_stathi = HIADDR(apc_sgsb);
-       apc->apc_statlo = LOWADDR(apc_sgsb);
+       SET_SGAE(apx->apx_csr23, SG_UIE | SG_PROM, apc_mode);
+       SET_SGAE(apc->apc_rxdd, SG_RLEN, apc_rxmd[0]);
+       i = SG_TLEN | ((apx->apx_modes.apm_txwin)<< 8);
+       SET_SGAE(apc->apc_txdd, i, apc_txmd[0]);
+       SET_SGAE(apc->apc_stdd, 0, apc_sgsb);
+       SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf[0], -SGMTU);
+       SET_SGDX(apc->apc_txtid, 0, apc_txidbuf[0], 0);
        for (i = 0; i < SGRBUF; i++)
        for (i = 0; i < SGRBUF; i++)
-                SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU, 0)
+                SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU)
        for (i = 0; i < SGTBUF; i++)
        for (i = 0; i < SGTBUF; i++)
-                SET_SGDX(apc->apc_txmd[i], SG_TUI, apc_tbuf[i][0], 0, 0)
-       SG_WCSR(apx, 2, SG_UIE | SG_PROM | HIADDR(apc_mode));
+                SET_SGDX(apc->apc_txmd[i], 0, apc_tbuf[i][0], 0)
 }
 
 /*
 }
 
 /*
@@ -272,40 +346,44 @@ apxstart(ifp)
 {
        register struct apx_softc *apx = &apx_softc[ifp->if_unit];
        register struct sgdx *dx;
 {
        register struct apx_softc *apx = &apx_softc[ifp->if_unit];
        register struct sgdx *dx;
-       struct apc_mem *apc = apx->apx_mem;
+       struct apc_mem *apc = apx->apx_hmem;
        struct mbuf *m;
        int len;
 
        if ((ifp->if_flags & IFF_RUNNING) == 0)
                return (0);
        do {
        struct mbuf *m;
        int len;
 
        if ((ifp->if_flags & IFF_RUNNING) == 0)
                return (0);
        do {
-               dx = apc->apc_txmd + apc->apc_txnum;
+               dx = apc->apc_txmd + apx->apx_txnum;
                if (dx->sgdx_flags & SG_OWN)
                        return (0);
                IF_DEQUEUE(&ifp->if_snd, m);
                if (m == 0)
                        return (0);
                len = min(m->m_pkthdr.len, SGMTU);
                if (dx->sgdx_flags & SG_OWN)
                        return (0);
                IF_DEQUEUE(&ifp->if_snd, m);
                if (m == 0)
                        return (0);
                len = min(m->m_pkthdr.len, SGMTU);
-               m_copydata(m, 0, len, apc->apc_txbuf[apx->apx_txnum]);
+               m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]);
+               m_freem(m);
                dx->sgdx_mcnt = -len;
                dx->sgdx_mcnt = -len;
-               dx->sgdx_flags = SG_OWN | SG_TUI | (0xff & dx->sgdx_flags);
+               dx->sgdx_flags = (SG_OWN|SG_TUI|SG_SLF|SG_ELF) |
+                       (0xff & dx->sgdx_flags);
                SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
                SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
+               DELAY(20);
                if (++apx->apx_txnum >= SGTBUF)
                        apx->apx_txnum = 0;
        } while (++apx->apx_txcnt < SGTBUF);
                if (++apx->apx_txnum >= SGTBUF)
                        apx->apx_txnum = 0;
        } while (++apx->apx_txcnt < SGTBUF);
-       apx->apx_txcnt = SGTBUF;
+       apx->apx_txcnt = SGTBUF; /* in case txcnt > SGTBUF by mistake */
        ifp->if_flags |= IFF_OACTIVE;
        return (0);
 }
 
        ifp->if_flags |= IFF_OACTIVE;
        return (0);
 }
 
+void
 apxintr()
 {
 apxintr()
 {
-       register struct apx_softc *apx = apx_lastsoftc;
-       struct apx_softc *apxlim = apx_softc + NAPX + NAPX;
+       register struct apx_softc *apx;
        int reply;
 
        int reply;
 
-       do {
-               if (apx->ap_if.if_flags & IFF_UP)
+       apxstat.anyint++;
+       for (apx = apx_softc + NAPX + NAPX; --apx >= apx_softc;) {
+               if (apx->apx_flags & APXF_CHIPHERE)
                    /* Try to turn off interrupt cause */
                    while ((reply = SG_RCSR(apx, 0)) & 0xff) {
                        SG_WCSR(apx, 0, SG_INEA | 0xfe);
                    /* Try to turn off interrupt cause */
                    while ((reply = SG_RCSR(apx, 0)) & 0xff) {
                        SG_WCSR(apx, 0, SG_INEA | 0xfe);
@@ -321,24 +399,24 @@ apxintr()
                        if (reply & SG_PINT)
                                apxstat.pint++;
                }
                        if (reply & SG_PINT)
                                apxstat.pint++;
                }
-               if (++apx >= apxlim)
-                       apx = apx_softc;
-       } while (apx != apx_lastsoftc);
+       }
 }
 
 }
 
+void
 apxtint(apx)
        register struct apx_softc *apx;
 {
 apxtint(apx)
        register struct apx_softc *apx;
 {
-       register struct apc_mem *apc = apx->apx_mem;
+       register struct apc_mem *apc = apx->apx_hmem;
        int i, loopcount = 0;
 
        int i, loopcount = 0;
 
+       apxstat.tint++;
        do {
                if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
                        i += SGTBUF;
                if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
                        if (loopcount)
                                break;
        do {
                if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
                        i += SGTBUF;
                if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
                        if (loopcount)
                                break;
-                       apxstat.nulltx++;
+                       apxstat.txnull++;
                        return;
                }
                loopcount++;
                        return;
                }
                loopcount++;
@@ -347,20 +425,27 @@ apxtint(apx)
        apxstart(&apx->apx_if);
 }
 
        apxstart(&apx->apx_if);
 }
 
+void
 apxrint(apx)
        register struct apx_softc *apx;
 {
 apxrint(apx)
        register struct apx_softc *apx;
 {
-       register struct apc_mem *apc = apx->apx_mem;
+       register struct apc_mem *apc = apx->apx_hmem;
        register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
        register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
+       int i = 0;
 #define SGNEXTRXMD \
 dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
 
 #define SGNEXTRXMD \
 dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
 
+       apxstat.rint++;
        /*
         * Out of sync with hardware, should never happen?
         */
        /*
         * Out of sync with hardware, should never happen?
         */
-       if (dx->sgdx_flags & SG_OWN) {
-               apxerror(apx, "out of sync");
-               return;
+       while (dx->sgdx_flags & SG_OWN) {
+               apxstat.rxnrdy++;
+               if (++i == SGRBUF) {
+                       apxstat.rxnull++;
+                       return;
+               }
+               SGNEXTRXMD;
        }
        /*
         * Process all buffers with valid data
        }
        /*
         * Process all buffers with valid data
@@ -368,11 +453,12 @@ dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
        while ((dx->sgdx_flags & SG_OWN) == 0) {
                if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
                        /*
        while ((dx->sgdx_flags & SG_OWN) == 0) {
                if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
                        /*
-                        * Find the end of the packet so we can see how long
-                        * it was.  We still throw it away.
+                        * Find the end of the packet so we synch up.
+                        * We throw the data away.
                         */
                         */
-                       apxerror(apx, "chained buffer", ds->sgdx_flags);
+                       apxerror(apx, "chained buffer", dx->sgdx_flags);
                        do {
                        do {
+                               apxstat.rx2big++;
                                dx->sgdx_bcnt = 0;
                                dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
                                SGNEXTRXMD;
                                dx->sgdx_bcnt = 0;
                                dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
                                SGNEXTRXMD;
@@ -382,32 +468,35 @@ dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
                         * we reset the hardware (conservative).
                         */
                        if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
                         * we reset the hardware (conservative).
                         */
                        if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
-                           SG_ENP) {
+                           SG_ELF) {
                                apxreset(apx->apx_if.if_unit);
                                return;
                        }
                } else
                        apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
                                apxreset(apx->apx_if.if_unit);
                                return;
                        }
                } else
                        apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
-                                       -dx->sgdx_bcnt);
+                                       -dx->sgdx_mcnt);
                dx->sgdx_bcnt = 0;
                dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
                SGNEXTRXMD;
        }
 }
 
                dx->sgdx_bcnt = 0;
                dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
                SGNEXTRXMD;
        }
 }
 
+void
 apxinput(ifp, buffer, len)
 apxinput(ifp, buffer, len)
-register struct ifnet *ifp;
-caddr_t buffer;
+       register struct ifnet *ifp;
+       caddr_t buffer;
 {
 {
-       register struct ifqueue *inq;
-       struct mbuf *m, *apxget();
        extern struct ifqueue hdintrq, ipintrq;
        extern struct ifqueue hdintrq, ipintrq;
+       register struct ifqueue *inq;
+       register u_char *cp = (u_char *)buffer;
+       struct mbuf *m, *m_devget();
        int isr;
 
        ifp->if_ipackets++;
        int isr;
 
        ifp->if_ipackets++;
-    {
-       register u_char *cp = (u_char *)buffer;
-
+       if ((ifp->if_flags & IFF_UP) == 0) {
+               apxstat.nxpctd++;
+               return;
+       }
        if (cp[0] == 0xff && cp[1] == 0x3) {
                /* This is a UI HDLC Packet, so we'll assume PPP
                   protocol.  for now, IP only. */
        if (cp[0] == 0xff && cp[1] == 0x3) {
                /* This is a UI HDLC Packet, so we'll assume PPP
                   protocol.  for now, IP only. */
@@ -416,93 +505,27 @@ caddr_t buffer;
                inq = &ipintrq;
                isr = NETISR_IP;
        } else {
                inq = &ipintrq;
                isr = NETISR_IP;
        } else {
+#ifdef CCITT
                inq = &hdintrq;
                isr = NETISR_CCITT;
        }
                inq = &hdintrq;
                isr = NETISR_CCITT;
        }
-    }
-       if (len <= 0)
+       if (len <= 0) {
+#endif
                return;
                return;
-
-       m = apxget(buffer, len , 0, ifp);
+       }
+       m = m_devget(buffer, len, 0, ifp, (void (*)())0);
        if (m == 0)
                return;
        if (m == 0)
                return;
-
        if(IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
        } else {
        if(IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
        } else {
+               apxstat.queued++;
                IF_ENQUEUE(inq, m);
                schednetisr(isr);
        }
 }
 
                IF_ENQUEUE(inq, m);
                schednetisr(isr);
        }
 }
 
-/*
- * Routine to copy from board local memory into mbufs.
- */
-struct mbuf *
-apxget(buf, totlen, off0, ifp)
-       char *buf;
-       int totlen, off0;
-       struct ifnet *ifp;
-{
-       register struct mbuf *m;
-       struct mbuf *top = 0, **mp = &top;
-       register int off = off0, len;
-       register char *cp;
-       char *epkt;
-
-       cp = buf;
-       epkt = cp + totlen;
-       if (off) {
-               cp += off + 2 * sizeof(u_short);
-               totlen -= 2 * sizeof(u_short);
-       }
-
-       MGETHDR(m, M_DONTWAIT, MT_DATA);
-       if (m == 0)
-               return (0);
-       m->m_pkthdr.rcvif = ifp;
-       m->m_pkthdr.len = totlen;
-       m->m_len = MHLEN;
-
-       while (totlen > 0) {
-               if (top) {
-                       MGET(m, M_DONTWAIT, MT_DATA);
-                       if (m == 0) {
-                               m_freem(top);
-                               return (0);
-                       }
-                       m->m_len = MLEN;
-               }
-               len = min(totlen, epkt - cp);
-               if (len >= MINCLSIZE) {
-                       MCLGET(m, M_DONTWAIT);
-                       if (m->m_flags & M_EXT)
-                               m->m_len = len = min(len, MCLBYTES);
-                       else
-                               len = m->m_len;
-               } else {
-                       /*
-                        * Place initial small packet/header at end of mbuf.
-                        */
-                       if (len < m->m_len) {
-                               if (top == 0 && len + max_linkhdr <= m->m_len)
-                                       m->m_data += max_linkhdr;
-                               m->m_len = len;
-                       } else
-                               len = m->m_len;
-               }
-               bcopy(cp, mtod(m, caddr_t), (unsigned)len);
-               cp += len;
-               *mp = m;
-               mp = &m->m_next;
-               totlen -= len;
-               if (cp == epkt)
-                       cp = buf;
-       }
-       return (top);
-}
-
 /*
  * Process an ioctl request.
  */
 /*
  * Process an ioctl request.
  */
@@ -516,15 +539,19 @@ apxioctl(ifp, cmd, data)
        struct apx_softc *apx = &apx_softc[ifp->if_unit];
 
        switch (cmd) {
        struct apx_softc *apx = &apx_softc[ifp->if_unit];
 
        switch (cmd) {
+
+       case SIOCSIFADDR:
+#ifdef CCITT
+               ifa->ifa_rtrequest = x25_rtrequest;
+               break;
+
        case SIOCSIFCONF_X25:
        case SIOCSIFCONF_X25:
+               ifp->if_output = x25_ifoutput;
                ifp->if_flags |= IFF_UP;
                error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
                if (error == 0)
                        apxinit(ifp->if_unit);
                ifp->if_flags |= IFF_UP;
                error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
                if (error == 0)
                        apxinit(ifp->if_unit);
-               break;
-
-       case SIOCSIFADDR:
-               ifa->ifa_rtrequest = x25_rtrequest;
+#endif
                break;
 
        case SIOCSIFFLAGS:
                break;
 
        case SIOCSIFFLAGS:
@@ -537,7 +564,7 @@ apxioctl(ifp, cmd, data)
 
        case SIOCSIFMODE:
                if ((ifp->if_flags & IFF_UP) == 0)
 
        case SIOCSIFMODE:
                if ((ifp->if_flags & IFF_UP) == 0)
-                       apx->apx_modes = *(struct apx_modes *)data;
+                       apx->apx_modes = *(struct apc_modes *)data;
                else
        default:
                        error = EINVAL;
                else
        default:
                        error = EINVAL;
@@ -554,4 +581,39 @@ apxerror(apx, msg, data)
        log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
                apx->apx_if.if_unit, msg, data);
 }
        log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
                apx->apx_if.if_unit, msg, data);
 }
+
+/*
+ * For debugging loopback activity.
+ */
+apxoutput(ifp, m, dst, rt)
+register struct ifnet *ifp;
+register struct mbuf *m;
+struct sockaddr *dst;
+struct rtentry *rt;
+{
+       int s = splimp(), error = 0;
+       static char pppheader[4] = { -1, 3, 0, 0x21 };
+       /*
+        * Queue message on interface, and start output if interface
+        * not yet active.
+        */
+       ifp->if_opackets++;
+       M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
+       if (m == 0) {
+               splx(s);
+               return ENOBUFS;
+       }
+       bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               m_freem(m);
+               error = ENOBUFS;
+       } else {
+               IF_ENQUEUE(&ifp->if_snd, m);
+               if ((ifp->if_flags & IFF_OACTIVE) == 0)
+                       (*ifp->if_start)(ifp);
+       }
+       splx(s);
+       return (error);
+}
 #endif /* NAPX */
 #endif /* NAPX */