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