158c494a2Ssklower /*
2*2dc74e6cSbostic * Copyright (c) 1982, 1990, 1993
3*2dc74e6cSbostic * The Regents of the University of California. All rights reserved.
458c494a2Ssklower *
558c494a2Ssklower * %sccs.include.redist.c%
658c494a2Ssklower *
7*2dc74e6cSbostic * @(#)if_apx.c 8.1 (Berkeley) 06/11/93
858c494a2Ssklower */
958c494a2Ssklower
1058c494a2Ssklower /*
1158c494a2Ssklower * Driver for SGS-THOMSON MK5025 based Link level controller.
1258c494a2Ssklower * The chip will do LAPB in hardware, although this driver only
1358c494a2Ssklower * attempts to use it for HDLC framing.
1458c494a2Ssklower *
1558c494a2Ssklower * Driver written by Keith Sklower, based on lance AMD7990
1658c494a2Ssklower * driver by Van Jacobsen, and information graciously supplied
1758c494a2Ssklower * by the ADAX corporation of Berkeley, CA.
1858c494a2Ssklower */
1958c494a2Ssklower
2058c494a2Ssklower #include "apx.h"
2158c494a2Ssklower #if NAPX > 0
2258c494a2Ssklower
23fb81e5fdSbostic #include <sys/param.h>
24fb81e5fdSbostic #include <sys/mbuf.h>
25fb81e5fdSbostic #include <sys/socket.h>
26fb81e5fdSbostic #include <sys/ioctl.h>
27fb81e5fdSbostic #include <sys/errno.h>
28fb81e5fdSbostic #include <sys/syslog.h>
2958c494a2Ssklower
30fb81e5fdSbostic #include <net/if.h>
31fb81e5fdSbostic #include <net/netisr.h>
32fb81e5fdSbostic #include <net/if_types.h>
334467b080Ssklower #ifdef CCITT
34fb81e5fdSbostic #include <netccitt/x25.h>
354467b080Ssklower int x25_rtrequest(), x25_ifoutput();
364467b080Ssklower #endif
3758c494a2Ssklower
38fb81e5fdSbostic #include <i386/isa/if_apxreg.h>
3958c494a2Ssklower
4058c494a2Ssklower int apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
41a259c195Ssklower int apxinit(), apxoutput(), apxioctl(), apxreset(), apxdebug = 0;
424467b080Ssklower void apx_ifattach(), apxtest(), apxinput(), apxintr(), apxtint(), apxrint();
4358c494a2Ssklower
4458c494a2Ssklower struct apx_softc {
4558c494a2Ssklower struct ifnet apx_if;
464467b080Ssklower caddr_t apx_device; /* e.g. isa_device, vme_device, etc. */
4758c494a2Ssklower struct apc_reg *apx_reg; /* control regs for both subunits */
4858c494a2Ssklower struct apc_mem *apx_hmem; /* Host addr for shared memory */
4958c494a2Ssklower struct apc_mem *apx_dmem; /* Device (chip) addr for shared mem */
5058c494a2Ssklower struct sgcp *apx_sgcp; /* IO control port for this subunit */
514467b080Ssklower int apx_flags; /* Flags specific to this driver */
524467b080Ssklower #define APXF_CHIPHERE 0x01 /* mk5025 present */
5358c494a2Ssklower int apx_rxnum; /* Last receiver dx we looked at */
5458c494a2Ssklower int apx_txnum; /* Last tranmistter dx we stomped on */
5558c494a2Ssklower int apx_txcnt; /* Number of packets queued for tx*/
564be5f162Ssklower u_int apx_msize;
5716b56411Ssklower struct sgae apx_csr23; /* 24 bit init addr, as seen by chip */
584467b080Ssklower u_short apx_csr4; /* byte gender, set in mach dep code */
594467b080Ssklower struct apc_modes apx_modes; /* Parameters, as amended by ioctls */
604467b080Ssklower } apx_softc[2 * NAPX];
6158c494a2Ssklower
6258c494a2Ssklower struct apxstat {
6316b56411Ssklower int rxnull; /* no rx bufs ready this interrupt */
6416b56411Ssklower int rxnrdy; /* expected rx buf not ready */
6516b56411Ssklower int rx2big; /* expected rx buf not ready */
6616b56411Ssklower int txnull;
6716b56411Ssklower int pint; /* new primitive available interrupt */
6816b56411Ssklower int rint; /* receive interrupts */
6916b56411Ssklower int tint; /* transmit interrupts */
7016b56411Ssklower int anyint; /* note all interrupts */
7116b56411Ssklower int queued; /* got through apxinput */
7216b56411Ssklower int nxpctd; /* received while if was down */
734be5f162Ssklower int rstfld; /* reset didn't work */
74e273d8d9Ssklower } apxstat;
7558c494a2Ssklower
7658c494a2Ssklower /* default operating paramters for devices */
7758c494a2Ssklower struct apc_modes apx_default_modes = {
7858c494a2Ssklower { 1, /* apm_sgob.lsaddr; */
7958c494a2Ssklower 3, /* apm_sgob.rsaddr; */
8058c494a2Ssklower -SGMTU, /* apm_sgob.n1; */
8158c494a2Ssklower ((-10)<<8), /* apm_sgob.n2_scale; */
8258c494a2Ssklower -1250, /* apm_sgob.t1; */
8358c494a2Ssklower -10000, /* apm_sgob.t3; */
8458c494a2Ssklower -80, /* apm_sgob.tp; */
8558c494a2Ssklower },
8658c494a2Ssklower 2, /* apm_txwin; */
8716b56411Ssklower 1, /* apm_apxmode: RS_232 connector and modem clock; */
8816b56411Ssklower 0, /* apm_apxaltmode: enable dtr, disable X.21 connector; */
8958c494a2Ssklower IFT_X25, /* apm_iftype; */
9058c494a2Ssklower };
9158c494a2Ssklower
9258c494a2Ssklower /* Begin bus & endian dependence */
9358c494a2Ssklower
94fb81e5fdSbostic #include <i386/isa/isa_device.h>
9558c494a2Ssklower
9658c494a2Ssklower struct isa_driver apxdriver = {
9758c494a2Ssklower apxprobe, apxattach, "apx",
9858c494a2Ssklower };
9958c494a2Ssklower
10058c494a2Ssklower #define SG_RCSR(apx, csrnum) \
101e273d8d9Ssklower (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
102e273d8d9Ssklower inw(&(apx->apx_sgcp->sgcp_rdp)))
10358c494a2Ssklower
10458c494a2Ssklower #define SG_WCSR(apx, csrnum, data) \
105e273d8d9Ssklower (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
10658c494a2Ssklower outw(&(apx->apx_sgcp->sgcp_rdp), data))
10758c494a2Ssklower
10858c494a2Ssklower #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
10958c494a2Ssklower #define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data)
11058c494a2Ssklower
11158c494a2Ssklower #define TIMO 10000 /* used in apx_uprim */
11258c494a2Ssklower
apxprobe(id)11358c494a2Ssklower apxprobe(id)
11458c494a2Ssklower register struct isa_device *id;
11558c494a2Ssklower {
11627f607d8Ssklower int moffset = 0, nchips = 2, unit = id->id_unit << 1, subunit;
117e273d8d9Ssklower struct apc_reg *reg = (struct apc_reg *)id->id_iobase;
11858c494a2Ssklower register struct apx_softc *apx = apx_softc + unit;
11958c494a2Ssklower
12027f607d8Ssklower /*
12127f607d8Ssklower * Probing for the second MK5025 on all ISA/EISA adax boards
12227f607d8Ssklower * manufactured prior to July 1992 (and some time following)
12327f607d8Ssklower * will hang the bus and the system. Thus, it is essential
12427f607d8Ssklower * not to probe for the second mk5025 if it is known not to be there.
12527f607d8Ssklower * As the current config scheme for 386BSD does not have a flags
12627f607d8Ssklower * field, we adopt the convention of using the low order bit of
12727f607d8Ssklower * the memsize to warn us that we have a single chip board.
12827f607d8Ssklower */
12927f607d8Ssklower if (id->id_msize & 1)
13027f607d8Ssklower nchips = 1;
13127f607d8Ssklower for (subunit = 0; subunit < nchips; subunit++) {
1324be5f162Ssklower apx->apx_msize = id->id_msize >> 1;
13358c494a2Ssklower apx->apx_hmem = (struct apc_mem *) (id->id_maddr + moffset);
1344be5f162Ssklower apx->apx_dmem = (struct apc_mem *) moffset;
13558c494a2Ssklower apx->apx_device = (caddr_t) id;
13658c494a2Ssklower apx->apx_reg = reg;
1374467b080Ssklower apx->apx_sgcp = reg->axr_sgcp + subunit;
1384467b080Ssklower apx->apx_csr4 = 0x0210; /* no byte swapping for PC-AT */
1394467b080Ssklower apx->apx_modes = apx_default_modes;
1404467b080Ssklower apx->apx_if.if_unit = unit++;
1414be5f162Ssklower moffset = apx->apx_msize;
1428b885162Ssklower apxtest(apx++);
14358c494a2Ssklower }
14458c494a2Ssklower return 1;
14558c494a2Ssklower }
14658c494a2Ssklower
14758c494a2Ssklower apxattach(id)
1484009f3c2Ssklower struct isa_device *id;
14958c494a2Ssklower {
1504009f3c2Ssklower register struct apx_softc *apx = apx_softc + (id->id_unit << 1);
15158c494a2Ssklower
1524009f3c2Ssklower apx_ifattach(&((apx++)->apx_if));
1534009f3c2Ssklower apx_ifattach(&(apx->apx_if));
1544467b080Ssklower return 0;
15558c494a2Ssklower }
15658c494a2Ssklower /* End bus & endian dependence */
15758c494a2Ssklower
15858c494a2Ssklower /*
15958c494a2Ssklower * Interface exists: make available by filling in network interface
16058c494a2Ssklower * record. System will initialize the interface when it is ready
16158c494a2Ssklower * to accept packets.
16258c494a2Ssklower */
163e273d8d9Ssklower void
apx_ifattach(ifp)1644009f3c2Ssklower apx_ifattach(ifp)
1654009f3c2Ssklower register struct ifnet *ifp;
16658c494a2Ssklower {
16758c494a2Ssklower /*
16858c494a2Ssklower * Initialize ifnet structure
16958c494a2Ssklower */
17058c494a2Ssklower ifp->if_name = "apc";
17158c494a2Ssklower ifp->if_mtu = SGMTU;
17258c494a2Ssklower ifp->if_init = apxinit;
1734467b080Ssklower ifp->if_output = apxoutput;
17458c494a2Ssklower ifp->if_start = apxstart;
17558c494a2Ssklower ifp->if_ioctl = apxioctl;
17658c494a2Ssklower ifp->if_reset = apxreset;
177e273d8d9Ssklower ifp->if_type = apx_default_modes.apm_iftype;
17858c494a2Ssklower ifp->if_hdrlen = 5;
17958c494a2Ssklower ifp->if_addrlen = 8;
18058c494a2Ssklower if_attach(ifp);
18158c494a2Ssklower }
18258c494a2Ssklower /*
18358c494a2Ssklower * Initialization of interface
18458c494a2Ssklower */
apxinit(unit)18558c494a2Ssklower apxinit(unit)
18658c494a2Ssklower int unit;
18758c494a2Ssklower {
18858c494a2Ssklower struct ifnet *ifp = &apx_softc[unit].apx_if;
18958c494a2Ssklower int s = splimp();
19058c494a2Ssklower
19158c494a2Ssklower ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
19258c494a2Ssklower if (apxreset(unit) && (ifp->if_flags & IFF_UP)) {
19358c494a2Ssklower ifp->if_flags |= IFF_RUNNING;
19458c494a2Ssklower (void)apxstart(ifp);
19558c494a2Ssklower }
19658c494a2Ssklower splx(s);
19758c494a2Ssklower return 0;
19858c494a2Ssklower }
19958c494a2Ssklower
apxctr(apx)200c020f28aSsklower apxctr(apx)
201c020f28aSsklower register struct apx_softc *apx;
202c020f28aSsklower {
2034467b080Ssklower APX_WCSR(apx, axr_ccr, 0xB0); /* select ctr 2, write lsb+msb, mode 0 */
204c020f28aSsklower APX_WCSR(apx, axr_cnt2, 0x1);
205c020f28aSsklower APX_WCSR(apx, axr_cnt2, 0x0);
206c020f28aSsklower DELAY(50);
2074467b080Ssklower APX_WCSR(apx, axr_ccr, 0xE8); /* latch status, ctr 2; */
2084467b080Ssklower return (APX_RCSR(apx, axr_cnt2));
2094467b080Ssklower }
2104467b080Ssklower
2114467b080Ssklower void
apxtest(apx)2124467b080Ssklower apxtest(apx)
2134467b080Ssklower register struct apx_softc *apx;
2144467b080Ssklower {
2154467b080Ssklower int i = 0;
2164467b080Ssklower
2174467b080Ssklower if ((apx->apx_if.if_unit & 1) == 0 && (i = apxctr(apx)) == 0)
2184467b080Ssklower apxerror(apx, "no response from timer chip", 0);
2194467b080Ssklower if (SG_RCSR(apx, 1) & 0x8000)
2204467b080Ssklower SG_WCSR(apx, 1, 0x8040);
2214467b080Ssklower SG_WCSR(apx, 4, apx->apx_csr4);
2224467b080Ssklower SG_WCSR(apx, 5, 0x08); /* Set DTR mode in SGS thompson chip */
2234467b080Ssklower if (((i = SG_RCSR(apx, 5)) & 0xff08) != 0x08)
2244467b080Ssklower apxerror(apx, "no mk5025, csr5 high bits are", i);
2254467b080Ssklower else
2264467b080Ssklower apx->apx_flags |= APXF_CHIPHERE;
22716b56411Ssklower (void) apx_uprim(apx, SG_STOP, "stop after probing");
228c020f28aSsklower }
229c020f28aSsklower
apxreset(unit)23058c494a2Ssklower apxreset(unit)
23158c494a2Ssklower int unit;
23258c494a2Ssklower {
23358c494a2Ssklower register struct apx_softc *apx = &apx_softc[unit ^ 1];
23458c494a2Ssklower u_char apm_apxmode = 0, apm_apxaltmode = 0;
23558c494a2Ssklower #define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0))
23658c494a2Ssklower
23758c494a2Ssklower MODE(apm_apxmode);
23858c494a2Ssklower MODE(apm_apxaltmode);
23958c494a2Ssklower apx = apx_softc + unit;
24058c494a2Ssklower MODE(apm_apxmode);
24158c494a2Ssklower MODE(apm_apxaltmode);
24258c494a2Ssklower APX_WCSR(apx, axr_mode, apm_apxmode);
24358c494a2Ssklower APX_WCSR(apx, axr_altmode, apm_apxaltmode);
24416b56411Ssklower (void) apxctr(apx);
24516b56411Ssklower (void) apx_uprim(apx, SG_STOP, "stop to reset");
24616b56411Ssklower if ((apx->apx_if.if_flags & IFF_UP) == 0)
24758c494a2Ssklower return 0;
24816b56411Ssklower apx_meminit(apx->apx_hmem, apx);
24958c494a2Ssklower SG_WCSR(apx, 4, apx->apx_csr4);
25016b56411Ssklower SG_WCSR(apx, 2, apx->apx_csr23.f_hi);
25116b56411Ssklower SG_WCSR(apx, 3, apx->apx_csr23.lo);
252e273d8d9Ssklower if (apx_uprim(apx, SG_INIT, "init request") ||
25358c494a2Ssklower apx_uprim(apx, SG_STAT, "status request") ||
254a259c195Ssklower apx_uprim(apx, SG_TRANS, "transparent mode"))
25558c494a2Ssklower return 0;
25658c494a2Ssklower SG_WCSR(apx, 0, SG_INEA);
257e273d8d9Ssklower return 1;
25858c494a2Ssklower }
25958c494a2Ssklower
apx_uprim(apx,request,ident)26058c494a2Ssklower apx_uprim(apx, request, ident)
26158c494a2Ssklower register struct apx_softc *apx;
2624009f3c2Ssklower char *ident;
26358c494a2Ssklower {
26458c494a2Ssklower register int timo = 0;
2654009f3c2Ssklower int reply;
26658c494a2Ssklower
2674009f3c2Ssklower if ((apx->apx_flags & APXF_CHIPHERE) == 0)
2684009f3c2Ssklower return 1; /* maybe even should panic . . . */
2694009f3c2Ssklower if ((reply = SG_RCSR(apx, 1)) & 0x8040)
2704467b080Ssklower SG_WCSR(apx, 1, 0x8040); /* Magic! */
271a259c195Ssklower if (request == SG_STOP && (SG_RCSR(apx, 0) & SG_STOPPED))
2724be5f162Ssklower return 0;
27358c494a2Ssklower SG_WCSR(apx, 1, request | SG_UAV);
27458c494a2Ssklower do {
275a259c195Ssklower reply = SG_RCSR(apx, 1);
27616b56411Ssklower if (timo++ >= TIMO || (reply & 0x8000)) {
27758c494a2Ssklower apxerror(apx, ident, reply);
27858c494a2Ssklower return 1;
27958c494a2Ssklower }
28058c494a2Ssklower } while (reply & SG_UAV);
28158c494a2Ssklower return 0;
28258c494a2Ssklower }
28358c494a2Ssklower
apx_meminit(apc,apx)28458c494a2Ssklower apx_meminit(apc, apx)
28558c494a2Ssklower register struct apc_mem *apc;
28658c494a2Ssklower struct apx_softc *apx;
28758c494a2Ssklower {
28858c494a2Ssklower register struct apc_mem *apcbase = apx->apx_dmem;
28958c494a2Ssklower register int i;
290e273d8d9Ssklower #define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff)
291e273d8d9Ssklower #define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff)
29216b56411Ssklower #define SET_SGAE(d, f, a) {(d).lo = LOWADDR(a); (d).f_hi = (f) | HIADDR(a);}
29316b56411Ssklower #define SET_SGDX(d, f, a, b) \
29416b56411Ssklower {SET_SGAE((d).sgdx_ae, f, a); (d).sgdx_mcnt = (d).sgdx_bcnt = (b);}
29558c494a2Ssklower
29616b56411Ssklower apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0;
297a259c195Ssklower bzero((caddr_t)apc, ((caddr_t)(&apc->apc_rxmd[0])) - (caddr_t)apc);
2984be5f162Ssklower apc->apc_mode = 0x0108; /* 2 flag spacing, leave addr & ctl, do CRC16 */
29958c494a2Ssklower apc->apc_sgop = apx->apx_modes.apm_sgop;
30016b56411Ssklower SET_SGAE(apx->apx_csr23, SG_UIE | SG_PROM, apc_mode);
30116b56411Ssklower SET_SGAE(apc->apc_rxdd, SG_RLEN, apc_rxmd[0]);
3024be5f162Ssklower i = SG_TLEN | ((apx->apx_modes.apm_txwin)<< 8);
3034be5f162Ssklower SET_SGAE(apc->apc_txdd, i, apc_txmd[0]);
30416b56411Ssklower SET_SGAE(apc->apc_stdd, 0, apc_sgsb);
30516b56411Ssklower SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf[0], -SGMTU);
30616b56411Ssklower SET_SGDX(apc->apc_txtid, 0, apc_txidbuf[0], 0);
30758c494a2Ssklower for (i = 0; i < SGRBUF; i++)
30816b56411Ssklower SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU)
30958c494a2Ssklower for (i = 0; i < SGTBUF; i++)
3104be5f162Ssklower SET_SGDX(apc->apc_txmd[i], 0, apc_tbuf[i][0], 0)
31158c494a2Ssklower }
31258c494a2Ssklower
31358c494a2Ssklower /*
31458c494a2Ssklower * Start output on interface. Get another datagram to send
31558c494a2Ssklower * off of the interface queue, and copy it to the interface
31658c494a2Ssklower * before starting the output.
31758c494a2Ssklower */
31858c494a2Ssklower apxstart(ifp)
31958c494a2Ssklower struct ifnet *ifp;
32058c494a2Ssklower {
32158c494a2Ssklower register struct apx_softc *apx = &apx_softc[ifp->if_unit];
32258c494a2Ssklower register struct sgdx *dx;
323e273d8d9Ssklower struct apc_mem *apc = apx->apx_hmem;
32458c494a2Ssklower struct mbuf *m;
32558c494a2Ssklower int len;
32658c494a2Ssklower
32758c494a2Ssklower if ((ifp->if_flags & IFF_RUNNING) == 0)
32858c494a2Ssklower return (0);
32958c494a2Ssklower do {
330e273d8d9Ssklower dx = apc->apc_txmd + apx->apx_txnum;
33158c494a2Ssklower if (dx->sgdx_flags & SG_OWN)
33258c494a2Ssklower return (0);
33358c494a2Ssklower IF_DEQUEUE(&ifp->if_snd, m);
33458c494a2Ssklower if (m == 0)
33558c494a2Ssklower return (0);
33658c494a2Ssklower len = min(m->m_pkthdr.len, SGMTU);
337e273d8d9Ssklower m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]);
33827f607d8Ssklower m_freem(m);
33958c494a2Ssklower dx->sgdx_mcnt = -len;
34016b56411Ssklower dx->sgdx_flags = (SG_OWN|SG_TUI|SG_SLF|SG_ELF) |
34116b56411Ssklower (0xff & dx->sgdx_flags);
34258c494a2Ssklower SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
3434be5f162Ssklower DELAY(20);
34458c494a2Ssklower if (++apx->apx_txnum >= SGTBUF)
34558c494a2Ssklower apx->apx_txnum = 0;
34658c494a2Ssklower } while (++apx->apx_txcnt < SGTBUF);
3474009f3c2Ssklower apx->apx_txcnt = SGTBUF; /* in case txcnt > SGTBUF by mistake */
34858c494a2Ssklower ifp->if_flags |= IFF_OACTIVE;
34958c494a2Ssklower return (0);
35058c494a2Ssklower }
35158c494a2Ssklower
352e273d8d9Ssklower void
apxintr()35358c494a2Ssklower apxintr()
35458c494a2Ssklower {
3554467b080Ssklower register struct apx_softc *apx;
35658c494a2Ssklower int reply;
35758c494a2Ssklower
35816b56411Ssklower apxstat.anyint++;
3594467b080Ssklower for (apx = apx_softc + NAPX + NAPX; --apx >= apx_softc;) {
3604467b080Ssklower if (apx->apx_flags & APXF_CHIPHERE)
36158c494a2Ssklower /* Try to turn off interrupt cause */
362a259c195Ssklower while ((reply = SG_RCSR(apx, 0)) & 0xff) {
36358c494a2Ssklower SG_WCSR(apx, 0, SG_INEA | 0xfe);
36458c494a2Ssklower if (reply & (SG_MERR|SG_TUR|SG_ROR)) {
36558c494a2Ssklower apxerror(apx, "mem, rx, or tx error", reply);
36658c494a2Ssklower apxinit(apx->apx_if.if_unit);
36758c494a2Ssklower break;
36858c494a2Ssklower }
36958c494a2Ssklower if (reply & SG_RINT)
37058c494a2Ssklower apxrint(apx);
37158c494a2Ssklower if (reply & SG_TINT)
37258c494a2Ssklower apxtint(apx);
37358c494a2Ssklower if (reply & SG_PINT)
37458c494a2Ssklower apxstat.pint++;
37558c494a2Ssklower }
3764467b080Ssklower }
37758c494a2Ssklower }
37858c494a2Ssklower
379e273d8d9Ssklower void
apxtint(apx)38058c494a2Ssklower apxtint(apx)
38158c494a2Ssklower register struct apx_softc *apx;
38258c494a2Ssklower {
383e273d8d9Ssklower register struct apc_mem *apc = apx->apx_hmem;
38458c494a2Ssklower int i, loopcount = 0;
38558c494a2Ssklower
38616b56411Ssklower apxstat.tint++;
38758c494a2Ssklower do {
38858c494a2Ssklower if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
38958c494a2Ssklower i += SGTBUF;
39058c494a2Ssklower if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
39158c494a2Ssklower if (loopcount)
39258c494a2Ssklower break;
39316b56411Ssklower apxstat.txnull++;
39458c494a2Ssklower return;
39558c494a2Ssklower }
39658c494a2Ssklower loopcount++;
39758c494a2Ssklower apx->apx_if.if_flags &= ~IFF_OACTIVE;
39858c494a2Ssklower } while (--apx->apx_txcnt > 0);
39958c494a2Ssklower apxstart(&apx->apx_if);
40058c494a2Ssklower }
40158c494a2Ssklower
4024467b080Ssklower void
apxrint(apx)40358c494a2Ssklower apxrint(apx)
40458c494a2Ssklower register struct apx_softc *apx;
40558c494a2Ssklower {
406e273d8d9Ssklower register struct apc_mem *apc = apx->apx_hmem;
40758c494a2Ssklower register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
40816b56411Ssklower int i = 0;
40958c494a2Ssklower #define SGNEXTRXMD \
41058c494a2Ssklower dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
41158c494a2Ssklower
41216b56411Ssklower apxstat.rint++;
41358c494a2Ssklower /*
41458c494a2Ssklower * Out of sync with hardware, should never happen?
41558c494a2Ssklower */
41616b56411Ssklower while (dx->sgdx_flags & SG_OWN) {
41716b56411Ssklower apxstat.rxnrdy++;
41816b56411Ssklower if (++i == SGRBUF) {
41916b56411Ssklower apxstat.rxnull++;
42058c494a2Ssklower return;
42158c494a2Ssklower }
42216b56411Ssklower SGNEXTRXMD;
42316b56411Ssklower }
42458c494a2Ssklower /*
42558c494a2Ssklower * Process all buffers with valid data
42658c494a2Ssklower */
42758c494a2Ssklower while ((dx->sgdx_flags & SG_OWN) == 0) {
42858c494a2Ssklower if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
42958c494a2Ssklower /*
43016b56411Ssklower * Find the end of the packet so we synch up.
43116b56411Ssklower * We throw the data away.
43258c494a2Ssklower */
433e273d8d9Ssklower apxerror(apx, "chained buffer", dx->sgdx_flags);
43458c494a2Ssklower do {
43516b56411Ssklower apxstat.rx2big++;
43658c494a2Ssklower dx->sgdx_bcnt = 0;
43758c494a2Ssklower dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
43858c494a2Ssklower SGNEXTRXMD;
43958c494a2Ssklower } while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)));
44058c494a2Ssklower /*
44158c494a2Ssklower * If search terminated without successful completion
44258c494a2Ssklower * we reset the hardware (conservative).
44358c494a2Ssklower */
44458c494a2Ssklower if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
445e273d8d9Ssklower SG_ELF) {
44658c494a2Ssklower apxreset(apx->apx_if.if_unit);
44758c494a2Ssklower return;
44858c494a2Ssklower }
44958c494a2Ssklower } else
45058c494a2Ssklower apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
45116b56411Ssklower -dx->sgdx_mcnt);
45258c494a2Ssklower dx->sgdx_bcnt = 0;
45358c494a2Ssklower dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
45458c494a2Ssklower SGNEXTRXMD;
45558c494a2Ssklower }
45658c494a2Ssklower }
45758c494a2Ssklower
458e273d8d9Ssklower void
apxinput(ifp,buffer,len)45958c494a2Ssklower apxinput(ifp, buffer, len)
46058c494a2Ssklower register struct ifnet *ifp;
46158c494a2Ssklower caddr_t buffer;
46258c494a2Ssklower {
46358c494a2Ssklower extern struct ifqueue hdintrq, ipintrq;
4644009f3c2Ssklower register struct ifqueue *inq;
4654009f3c2Ssklower register u_char *cp = (u_char *)buffer;
4664009f3c2Ssklower struct mbuf *m, *m_devget();
46758c494a2Ssklower int isr;
46858c494a2Ssklower
46958c494a2Ssklower ifp->if_ipackets++;
47016b56411Ssklower if ((ifp->if_flags & IFF_UP) == 0) {
47116b56411Ssklower apxstat.nxpctd++;
47216b56411Ssklower return;
47316b56411Ssklower }
47458c494a2Ssklower if (cp[0] == 0xff && cp[1] == 0x3) {
47558c494a2Ssklower /* This is a UI HDLC Packet, so we'll assume PPP
47658c494a2Ssklower protocol. for now, IP only. */
47758c494a2Ssklower buffer += 4;
47858c494a2Ssklower len -= 4;
47958c494a2Ssklower inq = &ipintrq;
48058c494a2Ssklower isr = NETISR_IP;
48158c494a2Ssklower } else {
4824009f3c2Ssklower #ifdef CCITT
48358c494a2Ssklower inq = &hdintrq;
48458c494a2Ssklower isr = NETISR_CCITT;
48558c494a2Ssklower }
4864009f3c2Ssklower if (len <= 0) {
4874009f3c2Ssklower #endif
48858c494a2Ssklower return;
4894009f3c2Ssklower }
490c020f28aSsklower m = m_devget(buffer, len, 0, ifp, (void (*)())0);
49158c494a2Ssklower if (m == 0)
49258c494a2Ssklower return;
49358c494a2Ssklower if(IF_QFULL(inq)) {
49458c494a2Ssklower IF_DROP(inq);
49558c494a2Ssklower m_freem(m);
49658c494a2Ssklower } else {
49716b56411Ssklower apxstat.queued++;
49858c494a2Ssklower IF_ENQUEUE(inq, m);
49958c494a2Ssklower schednetisr(isr);
50058c494a2Ssklower }
50158c494a2Ssklower }
50258c494a2Ssklower
50358c494a2Ssklower /*
50458c494a2Ssklower * Process an ioctl request.
50558c494a2Ssklower */
apxioctl(ifp,cmd,data)50658c494a2Ssklower apxioctl(ifp, cmd, data)
50758c494a2Ssklower register struct ifnet *ifp;
50858c494a2Ssklower int cmd;
50958c494a2Ssklower caddr_t data;
51058c494a2Ssklower {
51158c494a2Ssklower register struct ifaddr *ifa = (struct ifaddr *)data;
51258c494a2Ssklower int s = splimp(), error = 0;
51358c494a2Ssklower struct apx_softc *apx = &apx_softc[ifp->if_unit];
51458c494a2Ssklower
51558c494a2Ssklower switch (cmd) {
5164467b080Ssklower
5174467b080Ssklower case SIOCSIFADDR:
5184467b080Ssklower #ifdef CCITT
5194467b080Ssklower ifa->ifa_rtrequest = x25_rtrequest;
5204467b080Ssklower break;
5214467b080Ssklower
52258c494a2Ssklower case SIOCSIFCONF_X25:
5234467b080Ssklower ifp->if_output = x25_ifoutput;
52458c494a2Ssklower ifp->if_flags |= IFF_UP;
52558c494a2Ssklower error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
52658c494a2Ssklower if (error == 0)
52758c494a2Ssklower apxinit(ifp->if_unit);
5284467b080Ssklower #endif
52958c494a2Ssklower break;
53058c494a2Ssklower
53158c494a2Ssklower case SIOCSIFFLAGS:
53258c494a2Ssklower if (((ifp->if_flags & IFF_UP) == 0 &&
53358c494a2Ssklower (ifp->if_flags & IFF_RUNNING)) ||
53458c494a2Ssklower (ifp->if_flags & IFF_UP) &&
53558c494a2Ssklower (ifp->if_flags & IFF_RUNNING) == 0)
53658c494a2Ssklower apxinit(ifp->if_unit);
53758c494a2Ssklower break;
53858c494a2Ssklower
53958c494a2Ssklower case SIOCSIFMODE:
54058c494a2Ssklower if ((ifp->if_flags & IFF_UP) == 0)
541e273d8d9Ssklower apx->apx_modes = *(struct apc_modes *)data;
54258c494a2Ssklower else
54358c494a2Ssklower default:
54458c494a2Ssklower error = EINVAL;
54558c494a2Ssklower
54658c494a2Ssklower }
54758c494a2Ssklower splx(s);
54858c494a2Ssklower return (error);
54958c494a2Ssklower }
55058c494a2Ssklower
apxerror(apx,msg,data)55158c494a2Ssklower apxerror(apx, msg, data)
55258c494a2Ssklower register struct apx_softc *apx;
55358c494a2Ssklower char *msg;
55458c494a2Ssklower {
55558c494a2Ssklower log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
55658c494a2Ssklower apx->apx_if.if_unit, msg, data);
55758c494a2Ssklower }
558a259c195Ssklower
5594467b080Ssklower /*
5604467b080Ssklower * For debugging loopback activity.
5614467b080Ssklower */
apxoutput(ifp,m,dst,rt)5624467b080Ssklower apxoutput(ifp, m, dst, rt)
5634467b080Ssklower register struct ifnet *ifp;
5644467b080Ssklower register struct mbuf *m;
5654467b080Ssklower struct sockaddr *dst;
5664467b080Ssklower struct rtentry *rt;
5674467b080Ssklower {
568a259c195Ssklower int s = splimp(), error = 0;
569a259c195Ssklower static char pppheader[4] = { -1, 3, 0, 0x21 };
5704467b080Ssklower /*
5714467b080Ssklower * Queue message on interface, and start output if interface
5724467b080Ssklower * not yet active.
5734467b080Ssklower */
574a259c195Ssklower ifp->if_opackets++;
5754467b080Ssklower M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
5764467b080Ssklower if (m == 0) {
5774467b080Ssklower splx(s);
5784467b080Ssklower return ENOBUFS;
5794467b080Ssklower }
5804467b080Ssklower bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
5814467b080Ssklower if (IF_QFULL(&ifp->if_snd)) {
5824467b080Ssklower IF_DROP(&ifp->if_snd);
5834467b080Ssklower m_freem(m);
5844467b080Ssklower error = ENOBUFS;
5854467b080Ssklower } else {
5864467b080Ssklower IF_ENQUEUE(&ifp->if_snd, m);
5874467b080Ssklower if ((ifp->if_flags & IFF_OACTIVE) == 0)
5884467b080Ssklower (*ifp->if_start)(ifp);
5894467b080Ssklower }
5904467b080Ssklower splx(s);
5914467b080Ssklower return (error);
5924467b080Ssklower }
59358c494a2Ssklower #endif /* NAPX */
594