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(®->axr_altmode, 4); 106*50824Ssklower if (inb(®->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 = ⊤ 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