xref: /csrg-svn/sys/i386/isa/if_apx.c (revision 52848)
150824Ssklower /*
250824Ssklower  * Copyright (c) 1982, 1990 The Regents of the University of California.
350824Ssklower  * All rights reserved.
450824Ssklower  *
550824Ssklower  * %sccs.include.redist.c%
650824Ssklower  *
7*52848Ssklower  *	@(#)if_apx.c	7.7 (Berkeley) 03/05/92
850824Ssklower  */
950824Ssklower 
1050824Ssklower /*
1150824Ssklower  * Driver for SGS-THOMSON MK5025 based Link level controller.
1250824Ssklower  * The chip will do LAPB in hardware, although this driver only
1350824Ssklower  * attempts to use it for HDLC framing.
1450824Ssklower  *
1550824Ssklower  * Driver written by Keith Sklower, based on lance AMD7990
1650824Ssklower  * driver by Van Jacobsen, and information graciously supplied
1750824Ssklower  * by the ADAX corporation of Berkeley, CA.
1850824Ssklower  */
1950824Ssklower 
2050824Ssklower #include "apx.h"
2150824Ssklower #if NAPX > 0
2250824Ssklower 
2350824Ssklower #include "param.h"
2450824Ssklower #include "mbuf.h"
2550824Ssklower #include "socket.h"
2650824Ssklower #include "ioctl.h"
2750824Ssklower #include "errno.h"
2850824Ssklower #include "syslog.h"
2950824Ssklower 
3050824Ssklower #include "net/if.h"
3150824Ssklower #include "net/netisr.h"
3250825Ssklower #include "net/if_types.h"
3352828Ssklower #ifdef CCITT
3450824Ssklower #include "netccitt/x25.h"
3552828Ssklower int x25_rtrequest(), x25_ifoutput();
36*52848Ssklower struct mbuf_cache {
37*52848Ssklower 	int	mbc_size;
38*52848Ssklower 	int	mbc_num;
39*52848Ssklower 	int	mbc_oldsize;
40*52848Ssklower 	struct	mbuf **mbc_cache;
41*52848Ssklower } apx_cache = { 20 };
4252828Ssklower #endif
4350824Ssklower 
4450825Ssklower #include "if_apxreg.h"
4550824Ssklower 
4650824Ssklower int	apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
4752828Ssklower int	apxinit(), apxoutput(), apxioctl(), apxreset(), apxdebug = 1;
4852828Ssklower void	apx_ifattach(), apxtest(), apxinput(), apxintr(), apxtint(), apxrint();
49*52848Ssklower int	apxipdebug = 1;
5050824Ssklower 
5150824Ssklower struct apx_softc {
5250824Ssklower 	struct	ifnet apx_if;
5352828Ssklower 	caddr_t	apx_device;		/* e.g. isa_device, vme_device, etc. */
5450824Ssklower 	struct	apc_reg *apx_reg;	/* control regs for both subunits */
5550824Ssklower 	struct	apc_mem *apx_hmem;	/* Host addr for shared memory */
5650824Ssklower 	struct	apc_mem *apx_dmem;	/* Device (chip) addr for shared mem */
5750824Ssklower 	struct	sgcp *apx_sgcp;		/* IO control port for this subunit */
5852828Ssklower 	int	apx_flags;		/* Flags specific to this driver */
5952828Ssklower #define APXF_CHIPHERE	0x01		/* mk5025 present */
6050824Ssklower 	int	apx_rxnum;		/* Last receiver dx we looked at */
6150824Ssklower 	int	apx_txnum;		/* Last tranmistter dx we stomped on */
6250824Ssklower 	int	apx_txcnt;		/* Number of packets queued for tx*/
63*52848Ssklower 	u_int	apx_msize;
64*52848Ssklower 	u_short	apx_csr0;
65*52848Ssklower 	u_short	apx_csr1;
6652842Ssklower 	struct	sgae apx_csr23;		/* 24 bit init addr, as seen by chip */
6752828Ssklower 	u_short	apx_csr4;		/* byte gender, set in mach dep code */
6852828Ssklower 	struct	apc_modes apx_modes;	/* Parameters, as amended by ioctls */
6952828Ssklower } apx_softc[2 * NAPX];
7050824Ssklower 
7150824Ssklower struct apxstat {
7252842Ssklower 	int	rxnull;			/* no rx bufs ready this interrupt */
7352842Ssklower 	int	rxnrdy;			/* expected rx buf not ready */
7452842Ssklower 	int	rx2big;			/* expected rx buf not ready */
7552842Ssklower 	int	txnull;
7652842Ssklower 	int	pint;			/* new primitive available interrupt */
7752842Ssklower 	int	rint;			/* receive interrupts */
7852842Ssklower 	int	tint;			/* transmit interrupts */
7952842Ssklower 	int	anyint;			/* note all interrupts */
8052842Ssklower 	int	queued;			/* got through apxinput */
8152842Ssklower 	int	nxpctd;			/* received while if was down */
82*52848Ssklower 	int	rstfld;			/* reset didn't work */
8350825Ssklower } apxstat;
8450824Ssklower 
8550824Ssklower /* default operating paramters for devices */
8650824Ssklower struct	apc_modes apx_default_modes = {
8750824Ssklower  { 1,		/* apm_sgob.lsaddr; */
8850824Ssklower    3,		/* apm_sgob.rsaddr; */
8950824Ssklower    -SGMTU,	/* apm_sgob.n1; */
9050824Ssklower    ((-10)<<8),	/* apm_sgob.n2_scale; */
9150824Ssklower    -1250,	/* apm_sgob.t1; */
9250824Ssklower    -10000,	/* apm_sgob.t3; */
9350824Ssklower    -80,		/* apm_sgob.tp; */
9450824Ssklower  },
9550824Ssklower  2,		/* apm_txwin; */
9652842Ssklower  1,		/* apm_apxmode: RS_232 connector and modem clock; */
9752842Ssklower  0,		/* apm_apxaltmode: enable dtr, disable X.21 connector; */
9850824Ssklower  IFT_X25,	/* apm_iftype; */
9950824Ssklower };
10050824Ssklower 
10150824Ssklower /* Begin bus & endian dependence */
10250824Ssklower 
10350825Ssklower #include "isa_device.h"
10450824Ssklower 
10550824Ssklower struct	isa_driver apxdriver = {
10650824Ssklower 	apxprobe, apxattach, "apx",
10750824Ssklower };
10850824Ssklower 
10950824Ssklower #define SG_RCSR(apx, csrnum) \
11050825Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
11150825Ssklower 	  inw(&(apx->apx_sgcp->sgcp_rdp)))
11250824Ssklower 
11350824Ssklower #define SG_WCSR(apx, csrnum, data) \
11450825Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
11550824Ssklower 	  outw(&(apx->apx_sgcp->sgcp_rdp), data))
11650824Ssklower 
11750824Ssklower #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
11850824Ssklower #define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data)
11950824Ssklower 
12050824Ssklower #define TIMO 10000 /* used in apx_uprim */
12150824Ssklower 
12250824Ssklower apxprobe(id)
12350824Ssklower 	register struct	isa_device *id;
12450824Ssklower {
125*52848Ssklower 	int	moffset = 0, subunit, unit = id->id_unit << 1;
12650825Ssklower 	struct	apc_reg *reg = (struct apc_reg *)id->id_iobase;
12750824Ssklower 	register struct	apx_softc *apx = apx_softc + unit;
12850824Ssklower 
12952830Ssklower 	for (subunit = 0; subunit < 2; subunit++) {
130*52848Ssklower 		apx->apx_msize	= id->id_msize >> 1;
13150824Ssklower 		apx->apx_hmem	= (struct apc_mem *) (id->id_maddr + moffset);
132*52848Ssklower 		apx->apx_dmem	= (struct apc_mem *) moffset;
13350824Ssklower 		apx->apx_device = (caddr_t) id;
13450824Ssklower 		apx->apx_reg	= reg;
13552828Ssklower 		apx->apx_sgcp	= reg->axr_sgcp + subunit;
13652828Ssklower 		apx->apx_csr4	= 0x0210;	/* no byte swapping for PC-AT */
13752828Ssklower 		apx->apx_modes	= apx_default_modes;
13852828Ssklower 		apx->apx_if.if_unit = unit++;
13952830Ssklower 		apxtest(apx++);
140*52848Ssklower 		moffset = apx->apx_msize;
14150824Ssklower 	}
14250824Ssklower 	return 1;
14350824Ssklower }
14450824Ssklower 
14550824Ssklower apxattach(id)
14652830Ssklower 	struct	isa_device *id;
14750824Ssklower {
14852830Ssklower 	register struct	apx_softc *apx = apx_softc + (id->id_unit << 1);
14950824Ssklower 
15052830Ssklower 	apx_ifattach(&((apx++)->apx_if));
15152830Ssklower 	apx_ifattach(&(apx->apx_if));
15252828Ssklower 	return 0;
15350824Ssklower }
15450824Ssklower /* End bus & endian dependence */
15550824Ssklower 
15650824Ssklower /*
15750824Ssklower  * Interface exists: make available by filling in network interface
15850824Ssklower  * record.  System will initialize the interface when it is ready
15950824Ssklower  * to accept packets.
16050824Ssklower  */
16150825Ssklower void
16252830Ssklower apx_ifattach(ifp)
16352830Ssklower 	register struct ifnet *ifp;
16450824Ssklower {
16550824Ssklower 	/*
16650824Ssklower 	 * Initialize ifnet structure
16750824Ssklower 	 */
16852828Ssklower 	ifp->if_name	= "apc";
16952828Ssklower 	ifp->if_mtu	= SGMTU;
17052828Ssklower 	ifp->if_init	= apxinit;
17152828Ssklower 	ifp->if_output	= apxoutput;
17252828Ssklower 	ifp->if_start	= apxstart;
17352828Ssklower 	ifp->if_ioctl	= apxioctl;
17452828Ssklower 	ifp->if_reset	= apxreset;
17552828Ssklower 	ifp->if_type	= apx_default_modes.apm_iftype;
17652828Ssklower 	ifp->if_hdrlen	= 5;
17752828Ssklower 	ifp->if_addrlen	= 8;
17850824Ssklower 	if_attach(ifp);
17950824Ssklower }
18050824Ssklower /*
18150824Ssklower  * Initialization of interface
18250824Ssklower  */
18350824Ssklower apxinit(unit)
18450824Ssklower 	int unit;
18550824Ssklower {
18650824Ssklower 	struct ifnet *ifp = &apx_softc[unit].apx_if;
18750824Ssklower 	int s = splimp();
18850824Ssklower 
18950824Ssklower 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
19050824Ssklower 	if (apxreset(unit) && (ifp->if_flags & IFF_UP)) {
19150824Ssklower 		ifp->if_flags |= IFF_RUNNING;
19250824Ssklower 		(void)apxstart(ifp);
19350824Ssklower 	}
19450824Ssklower 	splx(s);
19550824Ssklower 	return 0;
19650824Ssklower }
19750824Ssklower 
19852672Ssklower apxctr(apx)
19952672Ssklower 	register struct apx_softc *apx;
20052672Ssklower {
20152828Ssklower 	APX_WCSR(apx, axr_ccr, 0xB0); /* select ctr 2, write lsb+msb, mode 0 */
20252672Ssklower 	APX_WCSR(apx, axr_cnt2, 0x1);
20352672Ssklower 	APX_WCSR(apx, axr_cnt2, 0x0);
20452672Ssklower 	DELAY(50);
20552828Ssklower 	APX_WCSR(apx, axr_ccr, 0xE8); /* latch status, ctr 2; */
20652828Ssklower 	return (APX_RCSR(apx, axr_cnt2));
20752672Ssklower }
20852672Ssklower 
20952828Ssklower void
21052828Ssklower apxtest(apx)
21152828Ssklower 	register struct apx_softc *apx;
21252828Ssklower {
21352828Ssklower 	int i =  0;
21452828Ssklower 
21552828Ssklower 	if ((apx->apx_if.if_unit & 1) == 0 && (i = apxctr(apx)) == 0)
21652828Ssklower 		apxerror(apx, "no response from timer chip", 0);
21752828Ssklower 	if (SG_RCSR(apx, 1) & 0x8000)
21852828Ssklower 		SG_WCSR(apx, 1, 0x8040);
21952828Ssklower 	SG_WCSR(apx, 4, apx->apx_csr4);
22052828Ssklower 	if (apxdebug && i) {
22152828Ssklower 		apxerror(apx, "counter 2 value", i);
22252828Ssklower 		apxerror(apx, "mk5025 csr4 value", SG_RCSR(apx, 4));
22352828Ssklower 	}
22452828Ssklower 	SG_WCSR(apx, 5, 0x08);		/* Set DTR mode in SGS thompson chip */
22552828Ssklower 	if (((i = SG_RCSR(apx, 5)) & 0xff08) != 0x08)
22652828Ssklower 		apxerror(apx, "no mk5025, csr5 high bits are", i);
22752828Ssklower 	else
22852828Ssklower 		apx->apx_flags |= APXF_CHIPHERE;
22952842Ssklower 	(void) apx_uprim(apx, SG_STOP, "stop after probing");
23052828Ssklower }
23152828Ssklower 
23250824Ssklower apxreset(unit)
23350824Ssklower 	int	unit;
23450824Ssklower {
23550824Ssklower 	register struct apx_softc *apx = &apx_softc[unit ^ 1];
23650824Ssklower 	u_char apm_apxmode = 0, apm_apxaltmode = 0;
23750824Ssklower #define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0))
23850824Ssklower 
23950824Ssklower 	MODE(apm_apxmode);
24050824Ssklower 	MODE(apm_apxaltmode);
24150824Ssklower 	apx = apx_softc + unit;
24250824Ssklower 	MODE(apm_apxmode);
24350824Ssklower 	MODE(apm_apxaltmode);
24450824Ssklower 	APX_WCSR(apx, axr_mode, apm_apxmode);
24550824Ssklower 	APX_WCSR(apx, axr_altmode, apm_apxaltmode);
24652842Ssklower 	(void) apxctr(apx);
24752842Ssklower 	(void) apx_uprim(apx, SG_STOP, "stop to reset");
24852842Ssklower 	if ((apx->apx_if.if_flags & IFF_UP) == 0)
24950824Ssklower 		return 0;
25052842Ssklower 	apx_meminit(apx->apx_hmem, apx);
25150824Ssklower 	SG_WCSR(apx, 4, apx->apx_csr4);
25252842Ssklower 	SG_WCSR(apx, 2, apx->apx_csr23.f_hi);
25352842Ssklower 	SG_WCSR(apx, 3, apx->apx_csr23.lo);
25450825Ssklower 	if (apx_uprim(apx, SG_INIT, "init request") ||
25550824Ssklower 	    apx_uprim(apx, SG_STAT, "status request") ||
256*52848Ssklower 	    apx_uprim(apx, SG_TRANS, "transparent mode")) {
257*52848Ssklower 		apxstat.rstfld++;
25850824Ssklower 		return 0;
259*52848Ssklower 	}
26050824Ssklower 	SG_WCSR(apx, 0, SG_INEA);
26150825Ssklower 	return 1;
26250824Ssklower }
26352842Ssklower int apx_doinit = 1, apx_dostat = 1;
26452842Ssklower int apx_didinit = 0, apx_didstat = 0;
26550824Ssklower 
26650824Ssklower apx_uprim(apx, request, ident)
26752830Ssklower 	register struct apx_softc *apx;
26850824Ssklower 	char *ident;
26950824Ssklower {
27050824Ssklower 	register int timo = 0;
27152830Ssklower 	int reply;
27250824Ssklower 
27352830Ssklower 	if ((apx->apx_flags & APXF_CHIPHERE) == 0)
27452830Ssklower 		return 1;	/* maybe even should panic . . . */
27552842Ssklower 
27652842Ssklower if (request == SG_STAT) { if (apx_dostat) apx_didstat = 1; else return 0;}
27752842Ssklower if (request == SG_INIT) { if (apx_doinit) apx_didinit = 1; else return 0;}
27852842Ssklower 
27952830Ssklower 	if ((reply = SG_RCSR(apx, 1)) & 0x8040)
28052828Ssklower 		SG_WCSR(apx, 1, 0x8040); /* Magic! */
281*52848Ssklower 	apx->apx_csr0 = SG_RCSR(apx, 0);
282*52848Ssklower 	if (request == SG_STOP && (apx->apx_csr0 & SG_STOPPED))
283*52848Ssklower 		return 0;
28450824Ssklower 	SG_WCSR(apx, 1, request | SG_UAV);
28550824Ssklower 	do {
286*52848Ssklower 		apx->apx_csr1 = reply = SG_RCSR(apx, 1);
28752842Ssklower 		if (timo++ >= TIMO || (reply & 0x8000)) {
28852842Ssklower 			if (request != SG_STOP || apxdebug)
28952842Ssklower 				apxerror(apx, ident, reply);
29052842Ssklower 			if (request != SG_STOP)
29152842Ssklower 				return 1;
29250824Ssklower 		}
29350824Ssklower 	} while (reply & SG_UAV);
294*52848Ssklower 	apx->apx_csr0 = SG_RCSR(apx, 0);
29550824Ssklower 	return 0;
29650824Ssklower }
29750824Ssklower 
29850824Ssklower apx_meminit(apc, apx)
29950824Ssklower 	register struct apc_mem *apc;
30050824Ssklower 	struct apx_softc *apx;
30150824Ssklower {
30250824Ssklower 	register struct apc_mem *apcbase = apx->apx_dmem;
30350824Ssklower 	register int i;
30450825Ssklower #define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff)
30550825Ssklower #define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff)
30652842Ssklower #define SET_SGAE(d, f, a) {(d).lo = LOWADDR(a); (d).f_hi = (f) | HIADDR(a);}
30752842Ssklower #define SET_SGDX(d, f, a, b) \
30852842Ssklower 	{SET_SGAE((d).sgdx_ae, f, a); (d).sgdx_mcnt = (d).sgdx_bcnt = (b);}
30950824Ssklower 
31052842Ssklower 	apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0;
311*52848Ssklower 	bzero((caddr_t)apc, apx->apx_msize);
312*52848Ssklower 	/*bzero((caddr_t)apc, ((caddr_t)(&apc->apc_rxmd[0])) - (caddr_t)apc);*/
313*52848Ssklower 	apc->apc_mode = 0x0108;	/* 2 flag spacing, leave addr&ctl, do CRC16 */
31450824Ssklower 	apc->apc_sgop = apx->apx_modes.apm_sgop;
31552842Ssklower 	SET_SGAE(apx->apx_csr23, SG_UIE | SG_PROM, apc_mode);
31652842Ssklower 	SET_SGAE(apc->apc_rxdd, SG_RLEN, apc_rxmd[0]);
317*52848Ssklower 	i = SG_TLEN | ((apx->apx_modes.apm_txwin)<< 8);
318*52848Ssklower 	SET_SGAE(apc->apc_txdd, i, apc_txmd[0]);
31952842Ssklower 	SET_SGAE(apc->apc_stdd, 0, apc_sgsb);
32052842Ssklower 	SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf[0], -SGMTU);
32152842Ssklower 	SET_SGDX(apc->apc_txtid, 0, apc_txidbuf[0], 0);
32250824Ssklower 	for (i = 0; i < SGRBUF; i++)
32352842Ssklower 		 SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU)
32450824Ssklower 	for (i = 0; i < SGTBUF; i++)
325*52848Ssklower 		 SET_SGDX(apc->apc_txmd[i], 0, apc_tbuf[i][0], 0)
32650824Ssklower }
32750824Ssklower 
32850824Ssklower /*
32950824Ssklower  * Start output on interface.  Get another datagram to send
33050824Ssklower  * off of the interface queue, and copy it to the interface
33150824Ssklower  * before starting the output.
33250824Ssklower  */
33350824Ssklower apxstart(ifp)
33450824Ssklower 	struct ifnet *ifp;
33550824Ssklower {
33650824Ssklower 	register struct apx_softc *apx = &apx_softc[ifp->if_unit];
33750824Ssklower 	register struct sgdx *dx;
33850825Ssklower 	struct apc_mem *apc = apx->apx_hmem;
33950824Ssklower 	struct mbuf *m;
34050824Ssklower 	int len;
34150824Ssklower 
34250824Ssklower 	if ((ifp->if_flags & IFF_RUNNING) == 0)
34350824Ssklower 		return (0);
34450824Ssklower 	do {
34550825Ssklower 		dx = apc->apc_txmd + apx->apx_txnum;
34650824Ssklower 		if (dx->sgdx_flags & SG_OWN)
34750824Ssklower 			return (0);
34850824Ssklower 		IF_DEQUEUE(&ifp->if_snd, m);
34950824Ssklower 		if (m == 0)
35050824Ssklower 			return (0);
35150824Ssklower 		len = min(m->m_pkthdr.len, SGMTU);
35250825Ssklower 		m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]);
35350824Ssklower 		dx->sgdx_mcnt = -len;
35452842Ssklower 		dx->sgdx_flags = (SG_OWN|SG_TUI|SG_SLF|SG_ELF) |
35552842Ssklower 			(0xff & dx->sgdx_flags);
35650824Ssklower 		SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
357*52848Ssklower 		DELAY(20);
358*52848Ssklower 		apx->apx_csr1 = SG_RCSR(apx, 1);
359*52848Ssklower 		apx->apx_csr0 = SG_RCSR(apx, 0);
36050824Ssklower 		if (++apx->apx_txnum >= SGTBUF)
36150824Ssklower 			apx->apx_txnum = 0;
36250824Ssklower 	} while (++apx->apx_txcnt < SGTBUF);
36352830Ssklower 	apx->apx_txcnt = SGTBUF; /* in case txcnt > SGTBUF by mistake */
36450824Ssklower 	ifp->if_flags |= IFF_OACTIVE;
36550824Ssklower 	return (0);
36650824Ssklower }
36750824Ssklower 
36850825Ssklower void
36950824Ssklower apxintr()
37050824Ssklower {
37152828Ssklower 	register struct apx_softc *apx;
37250824Ssklower 	int reply;
37350824Ssklower 
37452842Ssklower 	apxstat.anyint++;
37552828Ssklower 	for (apx = apx_softc + NAPX + NAPX; --apx >= apx_softc;) {
37652828Ssklower 		if (apx->apx_flags & APXF_CHIPHERE)
37750824Ssklower 		    /* Try to turn off interrupt cause */
378*52848Ssklower 		    while ((apx->apx_csr0 = SG_RCSR(apx, 0)) & 0xff) {
379*52848Ssklower 			reply = apx->apx_csr0;
38050824Ssklower 			SG_WCSR(apx, 0, SG_INEA | 0xfe);
38150824Ssklower 			if (reply & (SG_MERR|SG_TUR|SG_ROR)) {
38250824Ssklower 				apxerror(apx, "mem, rx, or tx error", reply);
38350824Ssklower 				apxinit(apx->apx_if.if_unit);
38450824Ssklower 				break;
38550824Ssklower 			}
38650824Ssklower 			if (reply & SG_RINT)
38750824Ssklower 				apxrint(apx);
38850824Ssklower 			if (reply & SG_TINT)
38950824Ssklower 				apxtint(apx);
39050824Ssklower 			if (reply & SG_PINT)
39150824Ssklower 				apxstat.pint++;
39250824Ssklower 		}
39352828Ssklower 	}
39450824Ssklower }
39550824Ssklower 
39650825Ssklower void
39750824Ssklower apxtint(apx)
39850824Ssklower 	register struct apx_softc *apx;
39950824Ssklower {
40050825Ssklower 	register struct apc_mem *apc = apx->apx_hmem;
40150824Ssklower 	int i, loopcount = 0;
40250824Ssklower 
40352842Ssklower 	apxstat.tint++;
40450824Ssklower 	do {
40550824Ssklower 		if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
40650824Ssklower 			i += SGTBUF;
40750824Ssklower 		if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
40850824Ssklower 			if (loopcount)
40950824Ssklower 				break;
41052842Ssklower 			apxstat.txnull++;
41150824Ssklower 			return;
41250824Ssklower 		}
41350824Ssklower 		loopcount++;
41450824Ssklower 		apx->apx_if.if_flags &= ~IFF_OACTIVE;
41550824Ssklower 	} while (--apx->apx_txcnt > 0);
41650824Ssklower 	apxstart(&apx->apx_if);
41750824Ssklower }
41850824Ssklower 
41952828Ssklower void
42050824Ssklower apxrint(apx)
42150824Ssklower 	register struct apx_softc *apx;
42250824Ssklower {
42350825Ssklower 	register struct apc_mem *apc = apx->apx_hmem;
42450824Ssklower 	register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
42552842Ssklower 	int i = 0;
42650824Ssklower #define SGNEXTRXMD \
42750824Ssklower dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
42850824Ssklower 
42952842Ssklower 	apxstat.rint++;
43050824Ssklower 	/*
43150824Ssklower 	 * Out of sync with hardware, should never happen?
43250824Ssklower 	 */
43352842Ssklower 	while (dx->sgdx_flags & SG_OWN) {
43452842Ssklower 		apxstat.rxnrdy++;
43552842Ssklower 		if (++i == SGRBUF) {
43652842Ssklower 			apxstat.rxnull++;
43752842Ssklower 			return;
43852842Ssklower 		}
43952842Ssklower 		SGNEXTRXMD;
44050824Ssklower 	}
44150824Ssklower 	/*
44250824Ssklower 	 * Process all buffers with valid data
44350824Ssklower 	 */
44450824Ssklower 	while ((dx->sgdx_flags & SG_OWN) == 0) {
44550824Ssklower 		if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
44650824Ssklower 			/*
44752842Ssklower 			 * Find the end of the packet so we synch up.
44852842Ssklower 			 * We throw the data away.
44950824Ssklower 			 */
45050825Ssklower 			apxerror(apx, "chained buffer", dx->sgdx_flags);
45150824Ssklower 			do {
45252842Ssklower 				apxstat.rx2big++;
45350824Ssklower 				dx->sgdx_bcnt = 0;
45450824Ssklower 				dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
45550824Ssklower 				SGNEXTRXMD;
45650824Ssklower 			} while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)));
45750824Ssklower 			/*
45850824Ssklower 			 * If search terminated without successful completion
45950824Ssklower 			 * we reset the hardware (conservative).
46050824Ssklower 			 */
46150824Ssklower 			if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
46250825Ssklower 			    SG_ELF) {
46350824Ssklower 				apxreset(apx->apx_if.if_unit);
46450824Ssklower 				return;
46550824Ssklower 			}
46650824Ssklower 		} else
46750824Ssklower 			apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
46852842Ssklower 					-dx->sgdx_mcnt);
46950824Ssklower 		dx->sgdx_bcnt = 0;
47050824Ssklower 		dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
47150824Ssklower 		SGNEXTRXMD;
47250824Ssklower 	}
47350824Ssklower }
47450824Ssklower 
47550825Ssklower void
47650824Ssklower apxinput(ifp, buffer, len)
47752830Ssklower 	register struct ifnet *ifp;
47852830Ssklower 	caddr_t buffer;
47950824Ssklower {
48052830Ssklower 	extern struct ifqueue hdintrq, ipintrq;
48150824Ssklower 	register struct ifqueue *inq;
48252830Ssklower 	register u_char *cp = (u_char *)buffer;
48352672Ssklower 	struct mbuf *m, *m_devget();
48450824Ssklower 	int isr;
48550824Ssklower 
48650824Ssklower 	ifp->if_ipackets++;
48752842Ssklower 	if ((ifp->if_flags & IFF_UP) == 0) {
48852842Ssklower 		apxstat.nxpctd++;
48952842Ssklower 		return;
49052842Ssklower 	}
49150824Ssklower 	if (cp[0] == 0xff && cp[1] == 0x3) {
49250824Ssklower 		/* This is a UI HDLC Packet, so we'll assume PPP
49350824Ssklower 		   protocol.  for now, IP only. */
49450824Ssklower 		buffer += 4;
49550824Ssklower 		len -= 4;
49650824Ssklower 		inq = &ipintrq;
49750824Ssklower 		isr = NETISR_IP;
49850824Ssklower 	} else {
49952830Ssklower #ifdef CCITT
50050824Ssklower 		inq = &hdintrq;
50150824Ssklower 		isr = NETISR_CCITT;
50250824Ssklower 	}
50352830Ssklower 	if (len <= 0) {
50452830Ssklower #endif
50550824Ssklower 		return;
50652830Ssklower 	}
50752672Ssklower 	m = m_devget(buffer, len, 0, ifp, (void (*)())0);
50850824Ssklower 	if (m == 0)
50950824Ssklower 		return;
510*52848Ssklower #ifdef CCITT
511*52848Ssklower 	if (apxipdebug)
512*52848Ssklower 		mbuf_cache(&apx_cache, m);
513*52848Ssklower #endif
51450824Ssklower 	if(IF_QFULL(inq)) {
51550824Ssklower 		IF_DROP(inq);
51650824Ssklower 		m_freem(m);
51750824Ssklower 	} else {
51852842Ssklower 		apxstat.queued++;
51950824Ssklower 		IF_ENQUEUE(inq, m);
52050824Ssklower 		schednetisr(isr);
52150824Ssklower 	}
52250824Ssklower }
52350824Ssklower 
52450824Ssklower /*
52550824Ssklower  * Process an ioctl request.
52650824Ssklower  */
52750824Ssklower apxioctl(ifp, cmd, data)
52850824Ssklower 	register struct ifnet *ifp;
52950824Ssklower 	int cmd;
53050824Ssklower 	caddr_t data;
53150824Ssklower {
53250824Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
53350824Ssklower 	int s = splimp(), error = 0;
53450824Ssklower 	struct apx_softc *apx = &apx_softc[ifp->if_unit];
53550824Ssklower 
53650824Ssklower 	switch (cmd) {
53752828Ssklower 
53852828Ssklower 	case SIOCSIFADDR:
53952828Ssklower #ifdef CCITT
540*52848Ssklower 		if (apxipdebug) {
541*52848Ssklower 			ifp->if_flags |= IFF_UP;
542*52848Ssklower 			apxinit(ifp->if_unit);
543*52848Ssklower 		} else
544*52848Ssklower 			ifa->ifa_rtrequest = x25_rtrequest;
54552828Ssklower 		break;
54652828Ssklower 
54750824Ssklower 	case SIOCSIFCONF_X25:
54852828Ssklower 		ifp->if_output = x25_ifoutput;
54950824Ssklower 		ifp->if_flags |= IFF_UP;
55050824Ssklower 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
55150824Ssklower 		if (error == 0)
55250824Ssklower 			apxinit(ifp->if_unit);
55352828Ssklower #endif
55450824Ssklower 		break;
55550824Ssklower 
55650824Ssklower 	case SIOCSIFFLAGS:
55750824Ssklower 		if (((ifp->if_flags & IFF_UP) == 0 &&
55850824Ssklower 		     (ifp->if_flags & IFF_RUNNING)) ||
55950824Ssklower 		    (ifp->if_flags & IFF_UP) &&
56050824Ssklower 		     (ifp->if_flags & IFF_RUNNING) == 0)
56150824Ssklower 			apxinit(ifp->if_unit);
56250824Ssklower 		break;
56350824Ssklower 
56450824Ssklower 	case SIOCSIFMODE:
56550824Ssklower 		if ((ifp->if_flags & IFF_UP) == 0)
56650825Ssklower 			apx->apx_modes = *(struct apc_modes *)data;
56750824Ssklower 		else
56850824Ssklower 	default:
56950824Ssklower 			error = EINVAL;
57050824Ssklower 
57150824Ssklower 	}
57250824Ssklower 	splx(s);
57350824Ssklower 	return (error);
57450824Ssklower }
57550824Ssklower 
57650824Ssklower apxerror(apx, msg, data)
57750824Ssklower 	register struct	apx_softc *apx;
57850824Ssklower 	char	*msg;
57950824Ssklower {
58050824Ssklower 	log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
58150824Ssklower 		apx->apx_if.if_unit, msg, data);
58250824Ssklower }
58352828Ssklower /*
58452828Ssklower  * For debugging loopback activity.
58552828Ssklower  */
58652828Ssklower static char pppheader[4] = { -1, 3, 0, 0x21 };
58752828Ssklower 
58852828Ssklower apxoutput(ifp, m, dst, rt)
58952828Ssklower register struct ifnet *ifp;
59052828Ssklower register struct mbuf *m;
59152828Ssklower struct sockaddr *dst;
59252828Ssklower struct rtentry *rt;
59352828Ssklower {
59452828Ssklower 	/*
59552828Ssklower 	 * Queue message on interface, and start output if interface
59652828Ssklower 	 * not yet active.
59752828Ssklower 	 */
59852828Ssklower 	int s = splimp(), error = 0;
59952828Ssklower 	M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
60052828Ssklower 	if (m == 0) {
60152828Ssklower 		splx(s);
60252828Ssklower 		return ENOBUFS;
60352828Ssklower 	}
60452828Ssklower 	bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
60552828Ssklower 	if (IF_QFULL(&ifp->if_snd)) {
60652828Ssklower 		IF_DROP(&ifp->if_snd);
60752828Ssklower 	    /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
60852828Ssklower 			ifp->if_name, ifp->if_unit);*/
60952828Ssklower 		m_freem(m);
61052828Ssklower 		error = ENOBUFS;
61152828Ssklower 	} else {
61252828Ssklower 		IF_ENQUEUE(&ifp->if_snd, m);
61352828Ssklower 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
61452828Ssklower 			(*ifp->if_start)(ifp);
61552828Ssklower 	}
61652828Ssklower 	splx(s);
61752828Ssklower 	return (error);
61852828Ssklower }
61952828Ssklower 
62050824Ssklower #endif /* NAPX */
621