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