xref: /original-bsd/sys/i386/isa/if_apx.c (revision 2dc74e6c)
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