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