xref: /csrg-svn/sys/i386/isa/if_apx.c (revision 50825)
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*50825Ssklower  *	@(#)if_apx.c	7.2 (Berkeley) 08/09/91
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"
32*50825Ssklower #include "net/if_types.h"
3350824Ssklower #include "netccitt/x25.h"
3450824Ssklower 
35*50825Ssklower #include "if_apxreg.h"
3650824Ssklower 
3750824Ssklower int	apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
38*50825Ssklower int	apxinit(), x25_ifoutput(), x25_rtrequest(), apxioctl(), apxreset();
3950824Ssklower void	apx_ifattach(), apxinput(), apxintr(), apxtint(), apaxrint();
4050824Ssklower 
4150824Ssklower struct apx_softc {
4250824Ssklower 	struct	ifnet apx_if;
4350824Ssklower 	caddr_t	apx_device;		/* e.g. isa_device */
4450824Ssklower 	u_short	apx_csr4;		/* byte gender, set in mach dep code */
4550824Ssklower 	struct	apc_reg *apx_reg;	/* control regs for both subunits */
4650824Ssklower 	struct	apc_mem *apx_hmem;	/* Host addr for shared memory */
4750824Ssklower 	struct	apc_mem *apx_dmem;	/* Device (chip) addr for shared mem */
4850824Ssklower 	struct	sgcp *apx_sgcp;		/* IO control port for this subunit */
4950824Ssklower 	struct	apc_modes apx_modes;	/* Parameters, as amended by ioctls */
5050824Ssklower 	int	apx_rxnum;		/* Last receiver dx we looked at */
5150824Ssklower 	int	apx_txnum;		/* Last tranmistter dx we stomped on */
5250824Ssklower 	int	apx_txcnt;		/* Number of packets queued for tx*/
5350824Ssklower } apx_softc[2 * NAPX], *apx_lastsoftc = apx_softc;
5450824Ssklower 
5550824Ssklower struct apxstat {
5650824Ssklower 	int	nulltx;
5750824Ssklower 	int	pint;
58*50825Ssklower } apxstat;
5950824Ssklower 
6050824Ssklower /* default operating paramters for devices */
6150824Ssklower struct	apc_modes apx_default_modes = {
6250824Ssklower  { 1,		/* apm_sgob.lsaddr; */
6350824Ssklower    3,		/* apm_sgob.rsaddr; */
6450824Ssklower    -SGMTU,	/* apm_sgob.n1; */
6550824Ssklower    ((-10)<<8),	/* apm_sgob.n2_scale; */
6650824Ssklower    -1250,	/* apm_sgob.t1; */
6750824Ssklower    -10000,	/* apm_sgob.t3; */
6850824Ssklower    -80,		/* apm_sgob.tp; */
6950824Ssklower  },
7050824Ssklower  2,		/* apm_txwin; */
7150824Ssklower  5,		/* apm_apxmode; */
7250824Ssklower  0,		/* apm_apxaltmode; */
7350824Ssklower  IFT_X25,	/* apm_iftype; */
7450824Ssklower };
7550824Ssklower 
7650824Ssklower /* Begin bus & endian dependence */
7750824Ssklower 
78*50825Ssklower #include "isa_device.h"
7950824Ssklower 
8050824Ssklower struct	isa_driver apxdriver = {
8150824Ssklower 	apxprobe, apxattach, "apx",
8250824Ssklower };
8350824Ssklower 
8450824Ssklower #define SG_RCSR(apx, csrnum) \
85*50825Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
86*50825Ssklower 	  inw(&(apx->apx_sgcp->sgcp_rdp)))
8750824Ssklower 
8850824Ssklower #define SG_WCSR(apx, csrnum, data) \
89*50825Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
9050824Ssklower 	  outw(&(apx->apx_sgcp->sgcp_rdp), data))
9150824Ssklower 
9250824Ssklower #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
9350824Ssklower #define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data)
9450824Ssklower 
9550824Ssklower #define TIMO 10000 /* used in apx_uprim */
9650824Ssklower 
9750824Ssklower apxprobe(id)
9850824Ssklower 	register struct	isa_device *id;
9950824Ssklower {
10050824Ssklower 	int	moffset, subunit, unit = id->id_unit << 1;
101*50825Ssklower 	struct	apc_reg *reg = (struct apc_reg *)id->id_iobase;
10250824Ssklower 	register struct	apx_softc *apx = apx_softc + unit;
10350824Ssklower 
10450824Ssklower 	/* Set and read DTR defeat in channel 0 to test presence of apc */
10550824Ssklower 	outb(&reg->axr_altmode, 4);
10650824Ssklower 	if (inb(&reg->axr_altmode) == 0)
10750824Ssklower 		return 0;			/* No board present */
10850824Ssklower 
10950824Ssklower 	for (subunit = 0; subunit < 2; subunit++, apx++) {
11050824Ssklower 		/* Set and read DTR mode to test present of SGS thompson chip */
11150824Ssklower 		apx->apx_if.if_unit = unit++;
112*50825Ssklower 		apx->apx_sgcp = reg->axr_sgcp + subunit;
11350824Ssklower 		SG_WCSR(apx, 5, 0x08);
114*50825Ssklower 		if (((SG_RCSR(apx, 5) & 0xff08) != 0x08)) {
11550824Ssklower 			apxerror(apx, "no mk5025 for channel", subunit);
11650824Ssklower 			continue;
11750824Ssklower 		}
11850824Ssklower 		moffset = subunit ? id->id_msize >> 1 : 0;
11950824Ssklower 		apx->apx_hmem	= (struct apc_mem *) (id->id_maddr + moffset);
12050824Ssklower 		apx->apx_dmem	= (struct apc_mem *) (moffset);
12150824Ssklower 		apx->apx_modes	= apx_default_modes;
12250824Ssklower 		apx->apx_device = (caddr_t) id;
12350824Ssklower 		apx->apx_reg	= reg;
12450824Ssklower 		apx->apx_csr4	= 0x0110;	/* no byte swapping for PC-AT */
12550824Ssklower 	}
12650824Ssklower 	return 1;
12750824Ssklower }
12850824Ssklower 
12950824Ssklower apxattach(id)
13050824Ssklower 	register struct isa_device *id;
13150824Ssklower {
13250824Ssklower 	int	unit = id->id_unit + id->id_unit;
13350824Ssklower 
13450824Ssklower 	apx_ifattach(unit);
13550824Ssklower 	apx_ifattach(unit + 1);
13650824Ssklower 	return (0);
13750824Ssklower }
13850824Ssklower 
13950824Ssklower /* End bus & endian dependence */
14050824Ssklower 
14150824Ssklower /*
14250824Ssklower  * Interface exists: make available by filling in network interface
14350824Ssklower  * record.  System will initialize the interface when it is ready
14450824Ssklower  * to accept packets.
14550824Ssklower  */
146*50825Ssklower void
14750824Ssklower apx_ifattach(unit)
14850824Ssklower {
14950824Ssklower 	register struct ifnet *ifp = &(apx_softc[unit].apx_if);
15050824Ssklower 	/*
15150824Ssklower 	 * Initialize ifnet structure
15250824Ssklower 	 */
15350824Ssklower 	if (apx_softc[unit].apx_device == 0)
15450824Ssklower 		return;
15550824Ssklower 	ifp->if_name = "apc";
15650824Ssklower 	ifp->if_mtu = SGMTU;
15750824Ssklower 	ifp->if_init = apxinit;
15850824Ssklower 	ifp->if_output = x25_ifoutput;
15950824Ssklower 	ifp->if_start = apxstart;
16050824Ssklower 	ifp->if_ioctl = apxioctl;
16150824Ssklower 	ifp->if_reset = apxreset;
162*50825Ssklower 	ifp->if_type = apx_default_modes.apm_iftype;
16350824Ssklower 	ifp->if_hdrlen = 5;
16450824Ssklower 	ifp->if_addrlen = 8;
16550824Ssklower 	if_attach(ifp);
16650824Ssklower }
16750824Ssklower /*
16850824Ssklower  * Initialization of interface
16950824Ssklower  */
17050824Ssklower apxinit(unit)
17150824Ssklower 	int unit;
17250824Ssklower {
17350824Ssklower 	struct ifnet *ifp = &apx_softc[unit].apx_if;
17450824Ssklower 	int s = splimp();
17550824Ssklower 
17650824Ssklower 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
17750824Ssklower 	if (apxreset(unit) && (ifp->if_flags & IFF_UP)) {
17850824Ssklower 		ifp->if_flags |= IFF_RUNNING;
17950824Ssklower 		(void)apxstart(ifp);
18050824Ssklower 	}
18150824Ssklower 	splx(s);
18250824Ssklower 	return 0;
18350824Ssklower }
18450824Ssklower 
18550824Ssklower apxreset(unit)
18650824Ssklower 	int	unit;
18750824Ssklower {
18850824Ssklower 	register struct apx_softc *apx = &apx_softc[unit ^ 1];
18950824Ssklower 	u_char apm_apxmode = 0, apm_apxaltmode = 0;
19050824Ssklower #define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0))
19150824Ssklower 
19250824Ssklower 	MODE(apm_apxmode);
19350824Ssklower 	MODE(apm_apxaltmode);
19450824Ssklower 	apx = apx_softc + unit;
19550824Ssklower 	MODE(apm_apxmode);
19650824Ssklower 	MODE(apm_apxaltmode);
19750824Ssklower 	APX_WCSR(apx, axr_mode, apm_apxmode);
19850824Ssklower 	APX_WCSR(apx, axr_altmode, apm_apxaltmode);
199*50825Ssklower 	apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0;
20050824Ssklower 
20150824Ssklower 	if (apx_uprim(apx, SG_STOP, "stop") ||
20250824Ssklower 	    !(apx->apx_if.if_flags & IFF_UP))
20350824Ssklower 		return 0;
204*50825Ssklower 	apx_meminit(apx->apx_hmem, apx); /* also sets CSR2 */
20550824Ssklower 	SG_WCSR(apx, 3, (int)apx->apx_dmem);
20650824Ssklower 	SG_WCSR(apx, 4, apx->apx_csr4);
207*50825Ssklower 	if (apx_uprim(apx, SG_INIT, "init request") ||
20850824Ssklower 	    apx_uprim(apx, SG_STAT, "status request") ||
20950824Ssklower 	    apx_uprim(apx, SG_TRANS, "transparent mode"))
21050824Ssklower 		return 0;
21150824Ssklower 	SG_WCSR(apx, 0, SG_INEA);
212*50825Ssklower 	return 1;
21350824Ssklower }
21450824Ssklower 
21550824Ssklower apx_uprim(apx, request, ident)
21650824Ssklower 	int request;
21750824Ssklower 	char *ident;
21850824Ssklower 	register struct apx_softc *apx;
21950824Ssklower {
22050824Ssklower 	register int timo = 0;
22150824Ssklower 	int reply = SG_RCSR(apx, 1);
22250824Ssklower 
223*50825Ssklower 	if (reply & 0x8040)
224*50825Ssklower 		SG_WCRS(1, 0x8040); /* Magic! */
22550824Ssklower 	SG_WCSR(apx, 1, request | SG_UAV);
22650824Ssklower 	do {
22750824Ssklower 		reply = SG_RCRS(1);
22850824Ssklower 		if (timo >= TIMO | reply & 0x8000) {
22950824Ssklower 			apxerror(apx, ident, reply);
23050824Ssklower 			return 1;
23150824Ssklower 		}
23250824Ssklower 	} while (reply & SG_UAV);
23350824Ssklower 	return 0;
23450824Ssklower }
23550824Ssklower 
23650824Ssklower apx_meminit(apc, apx)
23750824Ssklower 	register struct apc_mem *apc;
23850824Ssklower 	struct apx_softc *apx;
23950824Ssklower {
24050824Ssklower 	register struct apc_mem *apcbase = apx->apx_dmem;
24150824Ssklower 	register int i;
242*50825Ssklower #define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff)
243*50825Ssklower #define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff)
24450824Ssklower #define SET_SGDX(dx, f, a, b, m) \
24550824Ssklower 	{ (dx).sgdx_addr = LOWADDR(a); (dx).sgdx_bcnt = (b);\
24650824Ssklower 	  (dx).sgdx_mcnt = (m); (dx).sgdx_flags = (f) | HIADDR(a); }
24750824Ssklower 
24850824Ssklower 	bzero((caddr_t)apc, LOWADDR(apc_rxmd[0]));
24950824Ssklower 	apc->apc_mode = 0x8040;	/* 2 flag spacing, trans mode, 16bit FCS */
25050824Ssklower 	apc->apc_sgop = apx->apx_modes.apm_sgop;
25150824Ssklower 	apc->apc_rlen = SG_RLEN | HIADDR(apc_rxmd[0]);
25250824Ssklower 	apc->apc_rdra = LOWADDR(apc_rxmd[0]);
25350824Ssklower 	apc->apc_rlen = SG_TLEN | apx->apx_modes.apm_txwin |HIADDR(apc_txmd[0]);
25450824Ssklower 	apc->apc_tdra = LOWADDR(apc_txmd[0]);
25550824Ssklower 	SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf, -SGMTU, 0);
25650824Ssklower 	SET_SGDX(apc->apc_txtid, 0, apc_txidbuf, -SGMTU, 0);
25750824Ssklower 	apc->apc_stathi = HIADDR(apc_sgsb);
25850824Ssklower 	apc->apc_statlo = LOWADDR(apc_sgsb);
25950824Ssklower 	for (i = 0; i < SGRBUF; i++)
26050824Ssklower 		 SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU, 0)
26150824Ssklower 	for (i = 0; i < SGTBUF; i++)
26250824Ssklower 		 SET_SGDX(apc->apc_txmd[i], SG_TUI, apc_tbuf[i][0], 0, 0)
26350824Ssklower 	SG_WCSR(apx, 2, SG_UIE | SG_PROM | HIADDR(apc_mode));
26450824Ssklower }
26550824Ssklower 
26650824Ssklower /*
26750824Ssklower  * Start output on interface.  Get another datagram to send
26850824Ssklower  * off of the interface queue, and copy it to the interface
26950824Ssklower  * before starting the output.
27050824Ssklower  */
27150824Ssklower apxstart(ifp)
27250824Ssklower 	struct ifnet *ifp;
27350824Ssklower {
27450824Ssklower 	register struct apx_softc *apx = &apx_softc[ifp->if_unit];
27550824Ssklower 	register struct sgdx *dx;
276*50825Ssklower 	struct apc_mem *apc = apx->apx_hmem;
27750824Ssklower 	struct mbuf *m;
27850824Ssklower 	int len;
27950824Ssklower 
28050824Ssklower 	if ((ifp->if_flags & IFF_RUNNING) == 0)
28150824Ssklower 		return (0);
28250824Ssklower 	do {
283*50825Ssklower 		dx = apc->apc_txmd + apx->apx_txnum;
28450824Ssklower 		if (dx->sgdx_flags & SG_OWN)
28550824Ssklower 			return (0);
28650824Ssklower 		IF_DEQUEUE(&ifp->if_snd, m);
28750824Ssklower 		if (m == 0)
28850824Ssklower 			return (0);
28950824Ssklower 		len = min(m->m_pkthdr.len, SGMTU);
290*50825Ssklower 		m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]);
29150824Ssklower 		dx->sgdx_mcnt = -len;
29250824Ssklower 		dx->sgdx_flags = SG_OWN | SG_TUI | (0xff & dx->sgdx_flags);
29350824Ssklower 		SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
29450824Ssklower 		if (++apx->apx_txnum >= SGTBUF)
29550824Ssklower 			apx->apx_txnum = 0;
29650824Ssklower 	} while (++apx->apx_txcnt < SGTBUF);
29750824Ssklower 	apx->apx_txcnt = SGTBUF;
29850824Ssklower 	ifp->if_flags |= IFF_OACTIVE;
29950824Ssklower 	return (0);
30050824Ssklower }
30150824Ssklower 
302*50825Ssklower void
30350824Ssklower apxintr()
30450824Ssklower {
30550824Ssklower 	register struct apx_softc *apx = apx_lastsoftc;
30650824Ssklower 	struct apx_softc *apxlim = apx_softc + NAPX + NAPX;
30750824Ssklower 	int reply;
30850824Ssklower 
30950824Ssklower 	do {
310*50825Ssklower 		if (apx->apx_if.if_flags & IFF_UP)
31150824Ssklower 		    /* Try to turn off interrupt cause */
31250824Ssklower 		    while ((reply = SG_RCSR(apx, 0)) & 0xff) {
31350824Ssklower 			SG_WCSR(apx, 0, SG_INEA | 0xfe);
31450824Ssklower 			if (reply & (SG_MERR|SG_TUR|SG_ROR)) {
31550824Ssklower 				apxerror(apx, "mem, rx, or tx error", reply);
31650824Ssklower 				apxinit(apx->apx_if.if_unit);
31750824Ssklower 				break;
31850824Ssklower 			}
31950824Ssklower 			if (reply & SG_RINT)
32050824Ssklower 				apxrint(apx);
32150824Ssklower 			if (reply & SG_TINT)
32250824Ssklower 				apxtint(apx);
32350824Ssklower 			if (reply & SG_PINT)
32450824Ssklower 				apxstat.pint++;
32550824Ssklower 		}
32650824Ssklower 		if (++apx >= apxlim)
32750824Ssklower 			apx = apx_softc;
32850824Ssklower 	} while (apx != apx_lastsoftc);
32950824Ssklower }
33050824Ssklower 
331*50825Ssklower void
33250824Ssklower apxtint(apx)
33350824Ssklower 	register struct apx_softc *apx;
33450824Ssklower {
335*50825Ssklower 	register struct apc_mem *apc = apx->apx_hmem;
33650824Ssklower 	int i, loopcount = 0;
33750824Ssklower 
33850824Ssklower 	do {
33950824Ssklower 		if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
34050824Ssklower 			i += SGTBUF;
34150824Ssklower 		if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
34250824Ssklower 			if (loopcount)
34350824Ssklower 				break;
34450824Ssklower 			apxstat.nulltx++;
34550824Ssklower 			return;
34650824Ssklower 		}
34750824Ssklower 		loopcount++;
34850824Ssklower 		apx->apx_if.if_flags &= ~IFF_OACTIVE;
34950824Ssklower 	} while (--apx->apx_txcnt > 0);
35050824Ssklower 	apxstart(&apx->apx_if);
35150824Ssklower }
35250824Ssklower 
35350824Ssklower apxrint(apx)
35450824Ssklower 	register struct apx_softc *apx;
35550824Ssklower {
356*50825Ssklower 	register struct apc_mem *apc = apx->apx_hmem;
35750824Ssklower 	register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
35850824Ssklower #define SGNEXTRXMD \
35950824Ssklower dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
36050824Ssklower 
36150824Ssklower 	/*
36250824Ssklower 	 * Out of sync with hardware, should never happen?
36350824Ssklower 	 */
36450824Ssklower 	if (dx->sgdx_flags & SG_OWN) {
36550824Ssklower 		apxerror(apx, "out of sync");
36650824Ssklower 		return;
36750824Ssklower 	}
36850824Ssklower 	/*
36950824Ssklower 	 * Process all buffers with valid data
37050824Ssklower 	 */
37150824Ssklower 	while ((dx->sgdx_flags & SG_OWN) == 0) {
37250824Ssklower 		if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
37350824Ssklower 			/*
37450824Ssklower 			 * Find the end of the packet so we can see how long
37550824Ssklower 			 * it was.  We still throw it away.
37650824Ssklower 			 */
377*50825Ssklower 			apxerror(apx, "chained buffer", dx->sgdx_flags);
37850824Ssklower 			do {
37950824Ssklower 				dx->sgdx_bcnt = 0;
38050824Ssklower 				dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
38150824Ssklower 				SGNEXTRXMD;
38250824Ssklower 			} while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)));
38350824Ssklower 			/*
38450824Ssklower 			 * If search terminated without successful completion
38550824Ssklower 			 * we reset the hardware (conservative).
38650824Ssklower 			 */
38750824Ssklower 			if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
388*50825Ssklower 			    SG_ELF) {
38950824Ssklower 				apxreset(apx->apx_if.if_unit);
39050824Ssklower 				return;
39150824Ssklower 			}
39250824Ssklower 		} else
39350824Ssklower 			apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
39450824Ssklower 					-dx->sgdx_bcnt);
39550824Ssklower 		dx->sgdx_bcnt = 0;
39650824Ssklower 		dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
39750824Ssklower 		SGNEXTRXMD;
39850824Ssklower 	}
39950824Ssklower }
40050824Ssklower 
401*50825Ssklower void
40250824Ssklower apxinput(ifp, buffer, len)
40350824Ssklower register struct ifnet *ifp;
40450824Ssklower caddr_t buffer;
40550824Ssklower {
40650824Ssklower 	register struct ifqueue *inq;
40750824Ssklower 	struct mbuf *m, *apxget();
40850824Ssklower 	extern struct ifqueue hdintrq, ipintrq;
40950824Ssklower 	int isr;
41050824Ssklower 
41150824Ssklower 	ifp->if_ipackets++;
41250824Ssklower     {
41350824Ssklower 	register u_char *cp = (u_char *)buffer;
41450824Ssklower 
41550824Ssklower 	if (cp[0] == 0xff && cp[1] == 0x3) {
41650824Ssklower 		/* This is a UI HDLC Packet, so we'll assume PPP
41750824Ssklower 		   protocol.  for now, IP only. */
41850824Ssklower 		buffer += 4;
41950824Ssklower 		len -= 4;
42050824Ssklower 		inq = &ipintrq;
42150824Ssklower 		isr = NETISR_IP;
42250824Ssklower 	} else {
42350824Ssklower 		inq = &hdintrq;
42450824Ssklower 		isr = NETISR_CCITT;
42550824Ssklower 	}
42650824Ssklower     }
42750824Ssklower 	if (len <= 0)
42850824Ssklower 		return;
42950824Ssklower 
43050824Ssklower 	m = apxget(buffer, len , 0, ifp);
43150824Ssklower 	if (m == 0)
43250824Ssklower 		return;
43350824Ssklower 
43450824Ssklower 	if(IF_QFULL(inq)) {
43550824Ssklower 		IF_DROP(inq);
43650824Ssklower 		m_freem(m);
43750824Ssklower 	} else {
43850824Ssklower 		IF_ENQUEUE(inq, m);
43950824Ssklower 		schednetisr(isr);
44050824Ssklower 	}
44150824Ssklower }
44250824Ssklower 
44350824Ssklower /*
44450824Ssklower  * Routine to copy from board local memory into mbufs.
44550824Ssklower  */
44650824Ssklower struct mbuf *
44750824Ssklower apxget(buf, totlen, off0, ifp)
44850824Ssklower 	char *buf;
44950824Ssklower 	int totlen, off0;
45050824Ssklower 	struct ifnet *ifp;
45150824Ssklower {
45250824Ssklower 	register struct mbuf *m;
45350824Ssklower 	struct mbuf *top = 0, **mp = &top;
45450824Ssklower 	register int off = off0, len;
45550824Ssklower 	register char *cp;
45650824Ssklower 	char *epkt;
45750824Ssklower 
45850824Ssklower 	cp = buf;
45950824Ssklower 	epkt = cp + totlen;
46050824Ssklower 	if (off) {
46150824Ssklower 		cp += off + 2 * sizeof(u_short);
46250824Ssklower 		totlen -= 2 * sizeof(u_short);
46350824Ssklower 	}
46450824Ssklower 
46550824Ssklower 	MGETHDR(m, M_DONTWAIT, MT_DATA);
46650824Ssklower 	if (m == 0)
46750824Ssklower 		return (0);
46850824Ssklower 	m->m_pkthdr.rcvif = ifp;
46950824Ssklower 	m->m_pkthdr.len = totlen;
47050824Ssklower 	m->m_len = MHLEN;
47150824Ssklower 
47250824Ssklower 	while (totlen > 0) {
47350824Ssklower 		if (top) {
47450824Ssklower 			MGET(m, M_DONTWAIT, MT_DATA);
47550824Ssklower 			if (m == 0) {
47650824Ssklower 				m_freem(top);
47750824Ssklower 				return (0);
47850824Ssklower 			}
47950824Ssklower 			m->m_len = MLEN;
48050824Ssklower 		}
48150824Ssklower 		len = min(totlen, epkt - cp);
48250824Ssklower 		if (len >= MINCLSIZE) {
48350824Ssklower 			MCLGET(m, M_DONTWAIT);
48450824Ssklower 			if (m->m_flags & M_EXT)
48550824Ssklower 				m->m_len = len = min(len, MCLBYTES);
48650824Ssklower 			else
48750824Ssklower 				len = m->m_len;
48850824Ssklower 		} else {
48950824Ssklower 			/*
49050824Ssklower 			 * Place initial small packet/header at end of mbuf.
49150824Ssklower 			 */
49250824Ssklower 			if (len < m->m_len) {
49350824Ssklower 				if (top == 0 && len + max_linkhdr <= m->m_len)
49450824Ssklower 					m->m_data += max_linkhdr;
49550824Ssklower 				m->m_len = len;
49650824Ssklower 			} else
49750824Ssklower 				len = m->m_len;
49850824Ssklower 		}
49950824Ssklower 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
50050824Ssklower 		cp += len;
50150824Ssklower 		*mp = m;
50250824Ssklower 		mp = &m->m_next;
50350824Ssklower 		totlen -= len;
50450824Ssklower 		if (cp == epkt)
50550824Ssklower 			cp = buf;
50650824Ssklower 	}
50750824Ssklower 	return (top);
50850824Ssklower }
50950824Ssklower 
51050824Ssklower /*
51150824Ssklower  * Process an ioctl request.
51250824Ssklower  */
51350824Ssklower apxioctl(ifp, cmd, data)
51450824Ssklower 	register struct ifnet *ifp;
51550824Ssklower 	int cmd;
51650824Ssklower 	caddr_t data;
51750824Ssklower {
51850824Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
51950824Ssklower 	int s = splimp(), error = 0;
52050824Ssklower 	struct apx_softc *apx = &apx_softc[ifp->if_unit];
52150824Ssklower 
52250824Ssklower 	switch (cmd) {
52350824Ssklower 	case SIOCSIFCONF_X25:
52450824Ssklower 		ifp->if_flags |= IFF_UP;
52550824Ssklower 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
52650824Ssklower 		if (error == 0)
52750824Ssklower 			apxinit(ifp->if_unit);
52850824Ssklower 		break;
52950824Ssklower 
53050824Ssklower 	case SIOCSIFADDR:
53150824Ssklower 		ifa->ifa_rtrequest = x25_rtrequest;
53250824Ssklower 		break;
53350824Ssklower 
53450824Ssklower 	case SIOCSIFFLAGS:
53550824Ssklower 		if (((ifp->if_flags & IFF_UP) == 0 &&
53650824Ssklower 		     (ifp->if_flags & IFF_RUNNING)) ||
53750824Ssklower 		    (ifp->if_flags & IFF_UP) &&
53850824Ssklower 		     (ifp->if_flags & IFF_RUNNING) == 0)
53950824Ssklower 			apxinit(ifp->if_unit);
54050824Ssklower 		break;
54150824Ssklower 
54250824Ssklower 	case SIOCSIFMODE:
54350824Ssklower 		if ((ifp->if_flags & IFF_UP) == 0)
544*50825Ssklower 			apx->apx_modes = *(struct apc_modes *)data;
54550824Ssklower 		else
54650824Ssklower 	default:
54750824Ssklower 			error = EINVAL;
54850824Ssklower 
54950824Ssklower 	}
55050824Ssklower 	splx(s);
55150824Ssklower 	return (error);
55250824Ssklower }
55350824Ssklower 
55450824Ssklower apxerror(apx, msg, data)
55550824Ssklower 	register struct	apx_softc *apx;
55650824Ssklower 	char	*msg;
55750824Ssklower {
55850824Ssklower 	log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
55950824Ssklower 		apx->apx_if.if_unit, msg, data);
56050824Ssklower }
56150824Ssklower #endif /* NAPX */
562