xref: /csrg-svn/sys/i386/isa/if_apx.c (revision 50824)
1*50824Ssklower /*
2*50824Ssklower  * Copyright (c) 1982, 1990 The Regents of the University of California.
3*50824Ssklower  * All rights reserved.
4*50824Ssklower  *
5*50824Ssklower  * %sccs.include.redist.c%
6*50824Ssklower  *
7*50824Ssklower  *	@(#)if_apx.c	7.1 (Berkeley) 08/09/91
8*50824Ssklower  */
9*50824Ssklower 
10*50824Ssklower /*
11*50824Ssklower  * Driver for SGS-THOMSON MK5025 based Link level controller.
12*50824Ssklower  * The chip will do LAPB in hardware, although this driver only
13*50824Ssklower  * attempts to use it for HDLC framing.
14*50824Ssklower  *
15*50824Ssklower  * Driver written by Keith Sklower, based on lance AMD7990
16*50824Ssklower  * driver by Van Jacobsen, and information graciously supplied
17*50824Ssklower  * by the ADAX corporation of Berkeley, CA.
18*50824Ssklower  */
19*50824Ssklower 
20*50824Ssklower #include "apx.h"
21*50824Ssklower #if NAPX > 0
22*50824Ssklower 
23*50824Ssklower #include "param.h"
24*50824Ssklower #include "mbuf.h"
25*50824Ssklower #include "socket.h"
26*50824Ssklower #include "ioctl.h"
27*50824Ssklower #include "errno.h"
28*50824Ssklower #include "syslog.h"
29*50824Ssklower 
30*50824Ssklower #include "net/if.h"
31*50824Ssklower #include "net/netisr.h"
32*50824Ssklower #include "netccitt/x25.h"
33*50824Ssklower 
34*50824Ssklower #include "apxreg.h"
35*50824Ssklower 
36*50824Ssklower int	apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
37*50824Ssklower int	apxinit(), x25_ifoutput(), apxioctl(), apxreset();
38*50824Ssklower void	apx_ifattach(), apxinput(), apxintr(), apxtint(), apaxrint();
39*50824Ssklower 
40*50824Ssklower struct apx_softc {
41*50824Ssklower 	struct	ifnet apx_if;
42*50824Ssklower 	caddr_t	apx_device;		/* e.g. isa_device */
43*50824Ssklower 	u_short	apx_csr4;		/* byte gender, set in mach dep code */
44*50824Ssklower 	struct	apc_reg *apx_reg;	/* control regs for both subunits */
45*50824Ssklower 	struct	apc_mem *apx_hmem;	/* Host addr for shared memory */
46*50824Ssklower 	struct	apc_mem *apx_dmem;	/* Device (chip) addr for shared mem */
47*50824Ssklower 	struct	sgcp *apx_sgcp;		/* IO control port for this subunit */
48*50824Ssklower 	struct	apc_modes apx_modes;	/* Parameters, as amended by ioctls */
49*50824Ssklower 	int	apx_rxnum;		/* Last receiver dx we looked at */
50*50824Ssklower 	int	apx_txnum;		/* Last tranmistter dx we stomped on */
51*50824Ssklower 	int	apx_txcnt;		/* Number of packets queued for tx*/
52*50824Ssklower } apx_softc[2 * NAPX], *apx_lastsoftc = apx_softc;
53*50824Ssklower 
54*50824Ssklower struct apxstat {
55*50824Ssklower 	int	nulltx;
56*50824Ssklower 	int	pint;
57*50824Ssklower };
58*50824Ssklower 
59*50824Ssklower /* default operating paramters for devices */
60*50824Ssklower struct	apc_modes apx_default_modes = {
61*50824Ssklower  { 1,		/* apm_sgob.lsaddr; */
62*50824Ssklower    3,		/* apm_sgob.rsaddr; */
63*50824Ssklower    -SGMTU,	/* apm_sgob.n1; */
64*50824Ssklower    ((-10)<<8),	/* apm_sgob.n2_scale; */
65*50824Ssklower    -1250,	/* apm_sgob.t1; */
66*50824Ssklower    -10000,	/* apm_sgob.t3; */
67*50824Ssklower    -80,		/* apm_sgob.tp; */
68*50824Ssklower  },
69*50824Ssklower  2,		/* apm_txwin; */
70*50824Ssklower  5,		/* apm_apxmode; */
71*50824Ssklower  0,		/* apm_apxaltmode; */
72*50824Ssklower  IFT_X25,	/* apm_iftype; */
73*50824Ssklower };
74*50824Ssklower 
75*50824Ssklower /* Begin bus & endian dependence */
76*50824Ssklower 
77*50824Ssklower #include "i386/isa/if_apxreg.h"
78*50824Ssklower #include "i386/isa/isa_device.h"
79*50824Ssklower 
80*50824Ssklower struct	isa_driver apxdriver = {
81*50824Ssklower 	apxprobe, apxattach, "apx",
82*50824Ssklower };
83*50824Ssklower 
84*50824Ssklower #define SG_RCSR(apx, csrnum) \
85*50824Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1),
86*50824Ssklower 	  inw(&(apx->apx_sgcp->sgcp_rdp))
87*50824Ssklower 
88*50824Ssklower #define SG_WCSR(apx, csrnum, data) \
89*50824Ssklower 	 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1),
90*50824Ssklower 	  outw(&(apx->apx_sgcp->sgcp_rdp), data))
91*50824Ssklower 
92*50824Ssklower #define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
93*50824Ssklower #define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data)
94*50824Ssklower 
95*50824Ssklower #define TIMO 10000 /* used in apx_uprim */
96*50824Ssklower 
97*50824Ssklower apxprobe(id)
98*50824Ssklower 	register struct	isa_device *id;
99*50824Ssklower {
100*50824Ssklower 	int	moffset, subunit, unit = id->id_unit << 1;
101*50824Ssklower 	struct	apc_reg *reg = id->id_iobase;
102*50824Ssklower 	register struct	apx_softc *apx = apx_softc + unit;
103*50824Ssklower 
104*50824Ssklower 	/* Set and read DTR defeat in channel 0 to test presence of apc */
105*50824Ssklower 	outb(&reg->axr_altmode, 4);
106*50824Ssklower 	if (inb(&reg->axr_altmode) == 0)
107*50824Ssklower 		return 0;			/* No board present */
108*50824Ssklower 
109*50824Ssklower 	for (subunit = 0; subunit < 2; subunit++, apx++) {
110*50824Ssklower 		/* Set and read DTR mode to test present of SGS thompson chip */
111*50824Ssklower 		apx->apx_if.if_unit = unit++;
112*50824Ssklower 		apx->apx_sgcp = reg->axr_sgcb + subunit;
113*50824Ssklower 		SG_WCSR(apx, 5, 0x08);
114*50824Ssklower 		if ((SG_RCSR(apx, 5) & 0xff08) != 0x08)) {
115*50824Ssklower 			apxerror(apx, "no mk5025 for channel", subunit);
116*50824Ssklower 			continue;
117*50824Ssklower 		}
118*50824Ssklower 		moffset = subunit ? id->id_msize >> 1 : 0;
119*50824Ssklower 		apx->apx_hmem	= (struct apc_mem *) (id->id_maddr + moffset);
120*50824Ssklower 		apx->apx_dmem	= (struct apc_mem *) (moffset);
121*50824Ssklower 		apx->apx_modes	= apx_default_modes;
122*50824Ssklower 		apx->apx_device = (caddr_t) id;
123*50824Ssklower 		apx->apx_reg	= reg;
124*50824Ssklower 		apx->apx_csr4	= 0x0110;	/* no byte swapping for PC-AT */
125*50824Ssklower 	}
126*50824Ssklower 	return 1;
127*50824Ssklower }
128*50824Ssklower 
129*50824Ssklower apxattach(id)
130*50824Ssklower 	register struct isa_device *id;
131*50824Ssklower {
132*50824Ssklower 	int	unit = id->id_unit + id->id_unit;
133*50824Ssklower 
134*50824Ssklower 	apx_ifattach(unit);
135*50824Ssklower 	apx_ifattach(unit + 1);
136*50824Ssklower 	return (0);
137*50824Ssklower }
138*50824Ssklower 
139*50824Ssklower /* End bus & endian dependence */
140*50824Ssklower 
141*50824Ssklower /*
142*50824Ssklower  * Interface exists: make available by filling in network interface
143*50824Ssklower  * record.  System will initialize the interface when it is ready
144*50824Ssklower  * to accept packets.
145*50824Ssklower  */
146*50824Ssklower apx_ifattach(unit)
147*50824Ssklower {
148*50824Ssklower 	register struct ifnet *ifp = &(apx_softc[unit].apx_if);
149*50824Ssklower 	/*
150*50824Ssklower 	 * Initialize ifnet structure
151*50824Ssklower 	 */
152*50824Ssklower 	if (apx_softc[unit].apx_device == 0)
153*50824Ssklower 		return;
154*50824Ssklower 	ifp->if_name = "apc";
155*50824Ssklower 	ifp->if_mtu = SGMTU;
156*50824Ssklower 	ifp->if_init = apxinit;
157*50824Ssklower 	ifp->if_output = x25_ifoutput;
158*50824Ssklower 	ifp->if_start = apxstart;
159*50824Ssklower 	ifp->if_ioctl = apxioctl;
160*50824Ssklower 	ifp->if_reset = apxreset;
161*50824Ssklower 	ifp->if_type = apx_default_modes.axp_iftype;
162*50824Ssklower 	ifp->if_hdrlen = 5;
163*50824Ssklower 	ifp->if_addrlen = 8;
164*50824Ssklower 	if_attach(ifp);
165*50824Ssklower }
166*50824Ssklower /*
167*50824Ssklower  * Initialization of interface
168*50824Ssklower  */
169*50824Ssklower apxinit(unit)
170*50824Ssklower 	int unit;
171*50824Ssklower {
172*50824Ssklower 	struct ifnet *ifp = &apx_softc[unit].apx_if;
173*50824Ssklower 	int s = splimp();
174*50824Ssklower 
175*50824Ssklower 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
176*50824Ssklower 	if (apxreset(unit) && (ifp->if_flags & IFF_UP)) {
177*50824Ssklower 		ifp->if_flags |= IFF_RUNNING;
178*50824Ssklower 		(void)apxstart(ifp);
179*50824Ssklower 	}
180*50824Ssklower 	splx(s);
181*50824Ssklower 	return 0;
182*50824Ssklower }
183*50824Ssklower 
184*50824Ssklower apxreset(unit)
185*50824Ssklower 	int	unit;
186*50824Ssklower {
187*50824Ssklower 	register struct apx_softc *apx = &apx_softc[unit ^ 1];
188*50824Ssklower 	u_char apm_apxmode = 0, apm_apxaltmode = 0;
189*50824Ssklower #define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0))
190*50824Ssklower 
191*50824Ssklower 	MODE(apm_apxmode);
192*50824Ssklower 	MODE(apm_apxaltmode);
193*50824Ssklower 	apx = apx_softc + unit;
194*50824Ssklower 	MODE(apm_apxmode);
195*50824Ssklower 	MODE(apm_apxaltmode);
196*50824Ssklower 	APX_WCSR(apx, axr_mode, apm_apxmode);
197*50824Ssklower 	APX_WCSR(apx, axr_altmode, apm_apxaltmode);
198*50824Ssklower 	apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = apx->apx_rxnt = 0;
199*50824Ssklower 
200*50824Ssklower 	if (apx_uprim(apx, SG_STOP, "stop") ||
201*50824Ssklower 	    !(apx->apx_if.if_flags & IFF_UP))
202*50824Ssklower 		return 0;
203*50824Ssklower 	apx_meminit(apx->apc_mem, apx); /* also sets CSR2 */
204*50824Ssklower 	SG_WCSR(apx, 3, (int)apx->apx_dmem);
205*50824Ssklower 	SG_WCSR(apx, 4, apx->apx_csr4);
206*50824Ssklower 	if (apx_uprim(apx, SG_INIT, "init request")) ||
207*50824Ssklower 	    apx_uprim(apx, SG_STAT, "status request") ||
208*50824Ssklower 	    apx_uprim(apx, SG_TRANS, "transparent mode"))
209*50824Ssklower 		return 0;
210*50824Ssklower 	SG_WCSR(apx, 0, SG_INEA);
211*50824Ssklower 	return 1:
212*50824Ssklower }
213*50824Ssklower 
214*50824Ssklower apx_uprim(apx, request, ident)
215*50824Ssklower 	int request;
216*50824Ssklower 	char *ident;
217*50824Ssklower 	register struct apx_softc *apx;
218*50824Ssklower {
219*50824Ssklower 	register int timo = 0;
220*50824Ssklower 	int reply = SG_RCSR(apx, 1);
221*50824Ssklower 
222*50824Ssklower 	if (reply & x8040)
223*50824Ssklower 		SG_WCRS(1, x8040); /* Magic! */
224*50824Ssklower 	SG_WCSR(apx, 1, request | SG_UAV);
225*50824Ssklower 	do {
226*50824Ssklower 		reply = SG_RCRS(1);
227*50824Ssklower 		if (timo >= TIMO | reply & 0x8000) {
228*50824Ssklower 			apxerror(apx, ident, reply);
229*50824Ssklower 			return 1;
230*50824Ssklower 		}
231*50824Ssklower 	} while (reply & SG_UAV);
232*50824Ssklower 	return 0;
233*50824Ssklower }
234*50824Ssklower 
235*50824Ssklower apx_meminit(apc, apx)
236*50824Ssklower 	register struct apc_mem *apc;
237*50824Ssklower 	struct apx_softc *apx;
238*50824Ssklower {
239*50824Ssklower 	register struct apc_mem *apcbase = apx->apx_dmem;
240*50824Ssklower 	register int i;
241*50824Ssklower #define LOWADDR(e) (((u_long)&(apcbase->(e))) & 0xffff)
242*50824Ssklower #define HIADDR(e) ((((u_long)&(apcbase->(e))) >> 16) & 0xff)
243*50824Ssklower #define SET_SGDX(dx, f, a, b, m) \
244*50824Ssklower 	{ (dx).sgdx_addr = LOWADDR(a); (dx).sgdx_bcnt = (b);\
245*50824Ssklower 	  (dx).sgdx_mcnt = (m); (dx).sgdx_flags = (f) | HIADDR(a); }
246*50824Ssklower 
247*50824Ssklower 	bzero((caddr_t)apc, LOWADDR(apc_rxmd[0]));
248*50824Ssklower 	apc->apc_mode = 0x8040;	/* 2 flag spacing, trans mode, 16bit FCS */
249*50824Ssklower 	apc->apc_sgop = apx->apx_modes.apm_sgop;
250*50824Ssklower 	apc->apc_rlen = SG_RLEN | HIADDR(apc_rxmd[0]);
251*50824Ssklower 	apc->apc_rdra = LOWADDR(apc_rxmd[0]);
252*50824Ssklower 	apc->apc_rlen = SG_TLEN | apx->apx_modes.apm_txwin |HIADDR(apc_txmd[0]);
253*50824Ssklower 	apc->apc_tdra = LOWADDR(apc_txmd[0]);
254*50824Ssklower 	SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf, -SGMTU, 0);
255*50824Ssklower 	SET_SGDX(apc->apc_txtid, 0, apc_txidbuf, -SGMTU, 0);
256*50824Ssklower 	apc->apc_stathi = HIADDR(apc_sgsb);
257*50824Ssklower 	apc->apc_statlo = LOWADDR(apc_sgsb);
258*50824Ssklower 	for (i = 0; i < SGRBUF; i++)
259*50824Ssklower 		 SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU, 0)
260*50824Ssklower 	for (i = 0; i < SGTBUF; i++)
261*50824Ssklower 		 SET_SGDX(apc->apc_txmd[i], SG_TUI, apc_tbuf[i][0], 0, 0)
262*50824Ssklower 	SG_WCSR(apx, 2, SG_UIE | SG_PROM | HIADDR(apc_mode));
263*50824Ssklower }
264*50824Ssklower 
265*50824Ssklower /*
266*50824Ssklower  * Start output on interface.  Get another datagram to send
267*50824Ssklower  * off of the interface queue, and copy it to the interface
268*50824Ssklower  * before starting the output.
269*50824Ssklower  */
270*50824Ssklower apxstart(ifp)
271*50824Ssklower 	struct ifnet *ifp;
272*50824Ssklower {
273*50824Ssklower 	register struct apx_softc *apx = &apx_softc[ifp->if_unit];
274*50824Ssklower 	register struct sgdx *dx;
275*50824Ssklower 	struct apc_mem *apc = apx->apx_mem;
276*50824Ssklower 	struct mbuf *m;
277*50824Ssklower 	int len;
278*50824Ssklower 
279*50824Ssklower 	if ((ifp->if_flags & IFF_RUNNING) == 0)
280*50824Ssklower 		return (0);
281*50824Ssklower 	do {
282*50824Ssklower 		dx = apc->apc_txmd + apc->apc_txnum;
283*50824Ssklower 		if (dx->sgdx_flags & SG_OWN)
284*50824Ssklower 			return (0);
285*50824Ssklower 		IF_DEQUEUE(&ifp->if_snd, m);
286*50824Ssklower 		if (m == 0)
287*50824Ssklower 			return (0);
288*50824Ssklower 		len = min(m->m_pkthdr.len, SGMTU);
289*50824Ssklower 		m_copydata(m, 0, len, apc->apc_txbuf[apx->apx_txnum]);
290*50824Ssklower 		dx->sgdx_mcnt = -len;
291*50824Ssklower 		dx->sgdx_flags = SG_OWN | SG_TUI | (0xff & dx->sgdx_flags);
292*50824Ssklower 		SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
293*50824Ssklower 		if (++apx->apx_txnum >= SGTBUF)
294*50824Ssklower 			apx->apx_txnum = 0;
295*50824Ssklower 	} while (++apx->apx_txcnt < SGTBUF);
296*50824Ssklower 	apx->apx_txcnt = SGTBUF;
297*50824Ssklower 	ifp->if_flags |= IFF_OACTIVE;
298*50824Ssklower 	return (0);
299*50824Ssklower }
300*50824Ssklower 
301*50824Ssklower apxintr()
302*50824Ssklower {
303*50824Ssklower 	register struct apx_softc *apx = apx_lastsoftc;
304*50824Ssklower 	struct apx_softc *apxlim = apx_softc + NAPX + NAPX;
305*50824Ssklower 	int reply;
306*50824Ssklower 
307*50824Ssklower 	do {
308*50824Ssklower 		if (apx->ap_if.if_flags & IFF_UP)
309*50824Ssklower 		    /* Try to turn off interrupt cause */
310*50824Ssklower 		    while ((reply = SG_RCSR(apx, 0)) & 0xff) {
311*50824Ssklower 			SG_WCSR(apx, 0, SG_INEA | 0xfe);
312*50824Ssklower 			if (reply & (SG_MERR|SG_TUR|SG_ROR)) {
313*50824Ssklower 				apxerror(apx, "mem, rx, or tx error", reply);
314*50824Ssklower 				apxinit(apx->apx_if.if_unit);
315*50824Ssklower 				break;
316*50824Ssklower 			}
317*50824Ssklower 			if (reply & SG_RINT)
318*50824Ssklower 				apxrint(apx);
319*50824Ssklower 			if (reply & SG_TINT)
320*50824Ssklower 				apxtint(apx);
321*50824Ssklower 			if (reply & SG_PINT)
322*50824Ssklower 				apxstat.pint++;
323*50824Ssklower 		}
324*50824Ssklower 		if (++apx >= apxlim)
325*50824Ssklower 			apx = apx_softc;
326*50824Ssklower 	} while (apx != apx_lastsoftc);
327*50824Ssklower }
328*50824Ssklower 
329*50824Ssklower apxtint(apx)
330*50824Ssklower 	register struct apx_softc *apx;
331*50824Ssklower {
332*50824Ssklower 	register struct apc_mem *apc = apx->apx_mem;
333*50824Ssklower 	int i, loopcount = 0;
334*50824Ssklower 
335*50824Ssklower 	do {
336*50824Ssklower 		if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
337*50824Ssklower 			i += SGTBUF;
338*50824Ssklower 		if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
339*50824Ssklower 			if (loopcount)
340*50824Ssklower 				break;
341*50824Ssklower 			apxstat.nulltx++;
342*50824Ssklower 			return;
343*50824Ssklower 		}
344*50824Ssklower 		loopcount++;
345*50824Ssklower 		apx->apx_if.if_flags &= ~IFF_OACTIVE;
346*50824Ssklower 	} while (--apx->apx_txcnt > 0);
347*50824Ssklower 	apxstart(&apx->apx_if);
348*50824Ssklower }
349*50824Ssklower 
350*50824Ssklower apxrint(apx)
351*50824Ssklower 	register struct apx_softc *apx;
352*50824Ssklower {
353*50824Ssklower 	register struct apc_mem *apc = apx->apx_mem;
354*50824Ssklower 	register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
355*50824Ssklower #define SGNEXTRXMD \
356*50824Ssklower dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
357*50824Ssklower 
358*50824Ssklower 	/*
359*50824Ssklower 	 * Out of sync with hardware, should never happen?
360*50824Ssklower 	 */
361*50824Ssklower 	if (dx->sgdx_flags & SG_OWN) {
362*50824Ssklower 		apxerror(apx, "out of sync");
363*50824Ssklower 		return;
364*50824Ssklower 	}
365*50824Ssklower 	/*
366*50824Ssklower 	 * Process all buffers with valid data
367*50824Ssklower 	 */
368*50824Ssklower 	while ((dx->sgdx_flags & SG_OWN) == 0) {
369*50824Ssklower 		if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
370*50824Ssklower 			/*
371*50824Ssklower 			 * Find the end of the packet so we can see how long
372*50824Ssklower 			 * it was.  We still throw it away.
373*50824Ssklower 			 */
374*50824Ssklower 			apxerror(apx, "chained buffer", ds->sgdx_flags);
375*50824Ssklower 			do {
376*50824Ssklower 				dx->sgdx_bcnt = 0;
377*50824Ssklower 				dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
378*50824Ssklower 				SGNEXTRXMD;
379*50824Ssklower 			} while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)));
380*50824Ssklower 			/*
381*50824Ssklower 			 * If search terminated without successful completion
382*50824Ssklower 			 * we reset the hardware (conservative).
383*50824Ssklower 			 */
384*50824Ssklower 			if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
385*50824Ssklower 			    SG_ENP) {
386*50824Ssklower 				apxreset(apx->apx_if.if_unit);
387*50824Ssklower 				return;
388*50824Ssklower 			}
389*50824Ssklower 		} else
390*50824Ssklower 			apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
391*50824Ssklower 					-dx->sgdx_bcnt);
392*50824Ssklower 		dx->sgdx_bcnt = 0;
393*50824Ssklower 		dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
394*50824Ssklower 		SGNEXTRXMD;
395*50824Ssklower 	}
396*50824Ssklower }
397*50824Ssklower 
398*50824Ssklower apxinput(ifp, buffer, len)
399*50824Ssklower register struct ifnet *ifp;
400*50824Ssklower caddr_t buffer;
401*50824Ssklower {
402*50824Ssklower 	register struct ifqueue *inq;
403*50824Ssklower 	struct mbuf *m, *apxget();
404*50824Ssklower 	extern struct ifqueue hdintrq, ipintrq;
405*50824Ssklower 	int isr;
406*50824Ssklower 
407*50824Ssklower 	ifp->if_ipackets++;
408*50824Ssklower     {
409*50824Ssklower 	register u_char *cp = (u_char *)buffer;
410*50824Ssklower 
411*50824Ssklower 	if (cp[0] == 0xff && cp[1] == 0x3) {
412*50824Ssklower 		/* This is a UI HDLC Packet, so we'll assume PPP
413*50824Ssklower 		   protocol.  for now, IP only. */
414*50824Ssklower 		buffer += 4;
415*50824Ssklower 		len -= 4;
416*50824Ssklower 		inq = &ipintrq;
417*50824Ssklower 		isr = NETISR_IP;
418*50824Ssklower 	} else {
419*50824Ssklower 		inq = &hdintrq;
420*50824Ssklower 		isr = NETISR_CCITT;
421*50824Ssklower 	}
422*50824Ssklower     }
423*50824Ssklower 	if (len <= 0)
424*50824Ssklower 		return;
425*50824Ssklower 
426*50824Ssklower 	m = apxget(buffer, len , 0, ifp);
427*50824Ssklower 	if (m == 0)
428*50824Ssklower 		return;
429*50824Ssklower 
430*50824Ssklower 	if(IF_QFULL(inq)) {
431*50824Ssklower 		IF_DROP(inq);
432*50824Ssklower 		m_freem(m);
433*50824Ssklower 	} else {
434*50824Ssklower 		IF_ENQUEUE(inq, m);
435*50824Ssklower 		schednetisr(isr);
436*50824Ssklower 	}
437*50824Ssklower }
438*50824Ssklower 
439*50824Ssklower /*
440*50824Ssklower  * Routine to copy from board local memory into mbufs.
441*50824Ssklower  */
442*50824Ssklower struct mbuf *
443*50824Ssklower apxget(buf, totlen, off0, ifp)
444*50824Ssklower 	char *buf;
445*50824Ssklower 	int totlen, off0;
446*50824Ssklower 	struct ifnet *ifp;
447*50824Ssklower {
448*50824Ssklower 	register struct mbuf *m;
449*50824Ssklower 	struct mbuf *top = 0, **mp = &top;
450*50824Ssklower 	register int off = off0, len;
451*50824Ssklower 	register char *cp;
452*50824Ssklower 	char *epkt;
453*50824Ssklower 
454*50824Ssklower 	cp = buf;
455*50824Ssklower 	epkt = cp + totlen;
456*50824Ssklower 	if (off) {
457*50824Ssklower 		cp += off + 2 * sizeof(u_short);
458*50824Ssklower 		totlen -= 2 * sizeof(u_short);
459*50824Ssklower 	}
460*50824Ssklower 
461*50824Ssklower 	MGETHDR(m, M_DONTWAIT, MT_DATA);
462*50824Ssklower 	if (m == 0)
463*50824Ssklower 		return (0);
464*50824Ssklower 	m->m_pkthdr.rcvif = ifp;
465*50824Ssklower 	m->m_pkthdr.len = totlen;
466*50824Ssklower 	m->m_len = MHLEN;
467*50824Ssklower 
468*50824Ssklower 	while (totlen > 0) {
469*50824Ssklower 		if (top) {
470*50824Ssklower 			MGET(m, M_DONTWAIT, MT_DATA);
471*50824Ssklower 			if (m == 0) {
472*50824Ssklower 				m_freem(top);
473*50824Ssklower 				return (0);
474*50824Ssklower 			}
475*50824Ssklower 			m->m_len = MLEN;
476*50824Ssklower 		}
477*50824Ssklower 		len = min(totlen, epkt - cp);
478*50824Ssklower 		if (len >= MINCLSIZE) {
479*50824Ssklower 			MCLGET(m, M_DONTWAIT);
480*50824Ssklower 			if (m->m_flags & M_EXT)
481*50824Ssklower 				m->m_len = len = min(len, MCLBYTES);
482*50824Ssklower 			else
483*50824Ssklower 				len = m->m_len;
484*50824Ssklower 		} else {
485*50824Ssklower 			/*
486*50824Ssklower 			 * Place initial small packet/header at end of mbuf.
487*50824Ssklower 			 */
488*50824Ssklower 			if (len < m->m_len) {
489*50824Ssklower 				if (top == 0 && len + max_linkhdr <= m->m_len)
490*50824Ssklower 					m->m_data += max_linkhdr;
491*50824Ssklower 				m->m_len = len;
492*50824Ssklower 			} else
493*50824Ssklower 				len = m->m_len;
494*50824Ssklower 		}
495*50824Ssklower 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
496*50824Ssklower 		cp += len;
497*50824Ssklower 		*mp = m;
498*50824Ssklower 		mp = &m->m_next;
499*50824Ssklower 		totlen -= len;
500*50824Ssklower 		if (cp == epkt)
501*50824Ssklower 			cp = buf;
502*50824Ssklower 	}
503*50824Ssklower 	return (top);
504*50824Ssklower }
505*50824Ssklower 
506*50824Ssklower /*
507*50824Ssklower  * Process an ioctl request.
508*50824Ssklower  */
509*50824Ssklower apxioctl(ifp, cmd, data)
510*50824Ssklower 	register struct ifnet *ifp;
511*50824Ssklower 	int cmd;
512*50824Ssklower 	caddr_t data;
513*50824Ssklower {
514*50824Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
515*50824Ssklower 	int s = splimp(), error = 0;
516*50824Ssklower 	struct apx_softc *apx = &apx_softc[ifp->if_unit];
517*50824Ssklower 
518*50824Ssklower 	switch (cmd) {
519*50824Ssklower 	case SIOCSIFCONF_X25:
520*50824Ssklower 		ifp->if_flags |= IFF_UP;
521*50824Ssklower 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
522*50824Ssklower 		if (error == 0)
523*50824Ssklower 			apxinit(ifp->if_unit);
524*50824Ssklower 		break;
525*50824Ssklower 
526*50824Ssklower 	case SIOCSIFADDR:
527*50824Ssklower 		ifa->ifa_rtrequest = x25_rtrequest;
528*50824Ssklower 		break;
529*50824Ssklower 
530*50824Ssklower 	case SIOCSIFFLAGS:
531*50824Ssklower 		if (((ifp->if_flags & IFF_UP) == 0 &&
532*50824Ssklower 		     (ifp->if_flags & IFF_RUNNING)) ||
533*50824Ssklower 		    (ifp->if_flags & IFF_UP) &&
534*50824Ssklower 		     (ifp->if_flags & IFF_RUNNING) == 0)
535*50824Ssklower 			apxinit(ifp->if_unit);
536*50824Ssklower 		break;
537*50824Ssklower 
538*50824Ssklower 	case SIOCSIFMODE:
539*50824Ssklower 		if ((ifp->if_flags & IFF_UP) == 0)
540*50824Ssklower 			apx->apx_modes = *(struct apx_modes *)data;
541*50824Ssklower 		else
542*50824Ssklower 	default:
543*50824Ssklower 			error = EINVAL;
544*50824Ssklower 
545*50824Ssklower 	}
546*50824Ssklower 	splx(s);
547*50824Ssklower 	return (error);
548*50824Ssklower }
549*50824Ssklower 
550*50824Ssklower apxerror(apx, msg, data)
551*50824Ssklower 	register struct	apx_softc *apx;
552*50824Ssklower 	char	*msg;
553*50824Ssklower {
554*50824Ssklower 	log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
555*50824Ssklower 		apx->apx_if.if_unit, msg, data);
556*50824Ssklower }
557*50824Ssklower #endif /* NAPX */
558