+/* if_enp.c 1.1 86/07/20 */
+
+#include "enp.h"
+#define ENPBPTE 128
+#if NENP > 0
+
+/*
+ * Modified 3 Com Ethernet Controller interface
+ * enp modifications added S. F. Holmgren
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "errno.h"
+#include "time.h"
+#include "kernel.h"
+#include "uio.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../h/ioctl.h"
+
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/if_ether.h"
+
+#include "../tahoevba/vbavar.h"
+#include "../tahoeif/if_enp.h"
+#include "../machine/mtpr.h"
+#include "../tahoeif/if_debug.h"
+
+#define ENP0_PHYSADDR 0xf40000 /* board # 0 physical base addr */
+#define ENP1_PHYSADDR 0xf60000 /* board # 1 physical base addr */
+#define ENPSTART 0xf02000 /* standard enp start addr */
+
+int enpprobe(), enpattach(), enpintr();
+extern nulldev();
+caddr_t vtoph();
+struct mbuf *m_tofree();
+struct vba_device *enpinfo[ NENP ];
+
+/* Maximun 2 controllers per system supported */
+
+long enpstd[] = { ENP0_PHYSADDR+0x1000,ENP1_PHYSADDR+0x1000, 0 };
+extern char enp0utl[], enp1utl[]; /* enp accessible ram map */
+char *enpmap[]= { enp0utl, enp1utl };
+extern long ENP0map[], ENP1map[];
+long *ENPmap[] = {ENP0map, ENP1map};
+long ENPmapa[] = {0xfff41000, 0xfff61000};
+long enpismapped[NENP];
+
+unsigned short intvec[4] =
+ { 0xc1, 0xc2, 0xc3, 0xc4 }; /* intrvec of upto 4 enps */
+
+struct vba_driver enpdriver =
+{
+/* use of prom based version
+ enpprobe, 0, enpattach, 0, 0, enpintr,
+*/
+ enpprobe, 0, nulldev, 0,
+ enpstd, "enp", enpinfo, "ENP 20", 0
+};
+
+int enpinit(),
+ enpioctl(),
+ enpoutput(),
+ enpreset(),
+ enpbroadcast(),
+ enptimeout();
+
+int enpcopy();
+
+struct mbuf *enpget();
+
+extern struct ifnet loif;
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * es_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+
+struct enp_softc enp_softc[NENP];
+long stat_addr[NENP]; /* enp statistic addr (for nstat use) */
+long ring_addr[NENP]; /* enp dev ring addresses (for nstat use) */
+int numenp = NENP;
+int enp_intr = 0, /* no. of enp_to_host interrupts */
+ host_intr = 0; /* no. of host_to_enp interrupts */
+short enpram[NENP]; /* open/close flags for enp devices */
+/* Debugging tools, used to trace input packets */
+extern int printerror; /* error print flag, from if_ace.c */
+int save_enp_inpkt = 0;
+#define ENPTRACE(X) if (save_enp_inpkt) X;
+
+struct inp_err enperr[NENP];
+
+/*
+ * Probe for device.
+ */
+
+enpprobe(reg)
+caddr_t reg;
+{
+ static int unit=0;
+ register ENPDEVICE *addr = (ENPDEVICE *)reg;
+
+ if( (badaddr( addr, 2 ) ) || (badaddr( &addr->enp_ram[0], 2 ) ) )
+ return( 0 );
+ addr->enp_state = S_ENPRESET; /* controller is reset by vbus reset */
+ /* save address of statistic area for nstat uses */
+
+ stat_addr[unit] = (long) &(addr->enp_stat);
+ ring_addr[unit++] = (long) &(addr->enp_toenp);
+
+ return( ENPSIZE );
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
+
+enpattach( md )
+register struct vba_device *md;
+{
+ struct enp_softc *es = &enp_softc[md->ui_unit];
+ register struct ifnet *ifp = &es->es_if;
+ register ENPDEVICE *addr = (ENPDEVICE *)md->ui_addr;
+ struct sockaddr_in *sin;
+
+ enpgetaddr( md->ui_unit );
+
+ ifp->if_unit = md->ui_unit;
+ ifp->if_name = "enp";
+ ifp->if_mtu = ETHERMTU;
+
+/* bcopy(&es->es_boardaddr, es->es_enaddr, sizeof(es->es_enaddr)); */
+
+ sin = (struct sockaddr_in *)&es->es_if.if_addr;
+ sin->sin_family = AF_INET;
+
+ ifp->if_init = enpinit;
+ ifp->if_ioctl = enpioctl;
+ ifp->if_output = enpoutput;
+ ifp->if_reset = enpreset;
+ if_attach(ifp);
+}
+
+
+/*
+ * Reset of interface after UNIBUS reset.
+ */
+enpreset(unit)
+int unit;
+{
+ register struct vba_device *md;
+
+ if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
+ return(ENODEV);
+
+ enpinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations.
+ */
+
+enpinit( unit )
+int unit;
+{
+ struct enp_softc *es = &enp_softc[unit];
+ ENPDEVICE *addr;
+ int i, s;
+ u_char *cp, *ap;
+ register struct ifnet *ifp = &es->es_if;
+ register struct sockaddr_in *sin, *sinb;
+
+ sin = (struct sockaddr_in *)&ifp->if_addr;
+
+ if ( !enpismapped[unit] ) {
+ ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
+ ++enpismapped[unit];
+ }
+ if ((addr = (ENPDEVICE *)enpinfo[unit]->ui_addr) == (ENPDEVICE *)0)
+ return(ENODEV);
+ s = splimp();
+ RESET_ENP( addr );
+ DELAY( 200000 );
+
+#ifdef notdef
+/* only needed if not downloading ( ie, ROM-resident ENP code) */
+ addr->enp_intrvec = intvec[unit];
+ ENP_GO( addr,ENPSTART );
+ DELAY( 200000 );
+/* end of ROM-resident */
+#endif notdef
+
+ es->es_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business*/
+ splx(s);
+
+ if_rtinit( &es->es_if,RTF_UP );
+ arpwhohas(&es->es_ac, &sin->sin_addr);
+}
+
+
+/*
+ * Ethernet interface interrupt.
+ */
+
+enpintr( unit )
+{
+ register ENPDEVICE *addr;
+ register BCB *bcbp;
+ register struct vba_device *md;
+
+ enp_intr++;
+
+ if (unit >= NENP || (md = enpinfo[unit]) == 0)
+ return;
+
+ addr = (ENPDEVICE *)md->ui_addr;
+
+ if( IS_ENP_INTR(addr) == 0 )
+ return;
+
+ ACK_ENP_INTR( addr );
+
+ while( (bcbp = (BCB *)ringget( &addr->enp_tohost )) != 0 )
+ {
+ enpread( &enp_softc[ unit ],bcbp, unit );
+ ringput( &addr->enp_enpfree,bcbp );
+ }
+ return(0);
+}
+
+#define MAXBLEN 1500
+char errpkt[MAXBLEN];
+int bufptr = 0;
+int maxl_tosave = 200; /* save only the first 200 bytes */
+
+saverrpkt(errbuf, errtype, len)
+register u_char *errbuf;
+int errtype, len;
+{
+ int remain, newptr;
+
+ remain = MAXBLEN - bufptr;
+ if (remain < 50) /* if too small */
+ return; /* no space avail */
+ len = (len > maxl_tosave || len <= 0) ? maxl_tosave : len;
+ len = len > remain ? (remain - 2*sizeof(len)): len;
+ newptr = bufptr + len + 2*sizeof(len);
+ if (newptr <= MAXBLEN) {
+ enpcopy((char *)&len, &errpkt[bufptr], sizeof(len));
+ enpcopy((char *)&errtype, &errpkt[bufptr+sizeof(len)],
+ sizeof(errtype));
+ enpcopy(errbuf, &errpkt[bufptr+(2*sizeof(len))], len);
+ }
+ bufptr = newptr;
+}
+
+/*
+ * Read input packet, examine its packet type, and enqueue it.
+ */
+
+enpread( es, bcbp, unit )
+struct enp_softc *es;
+register BCB *bcbp;
+int unit;
+{
+ register struct ether_header *enp;
+ struct mbuf *m;
+ long int s, v;
+ register short *vp = (short *)&v,
+ *sp;
+ int len, off, resid, enptype;
+ register struct ifqueue *inq;
+
+ es->es_if.if_ipackets++;
+
+ /*
+ * Get input data length.
+ * Get pointer to ethernet header (in input buffer).
+ * Deal with trailer protocol: if type is PUP trailer
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+
+ len = bcbp->b_msglen - SIZEOF_ETHEADER;
+#ifdef TAHOE
+ sp = (short *)&bcbp->b_addr;
+ *vp = *sp; vp[1] = sp[1];
+ enp = (struct ether_header *) v;
+#else
+ enp = (struct ether_header *)bcbp->b_addr;
+#endif TAHOE
+
+#define enpdataaddr(enp, off, type) ((type)(((caddr_t)(((char *)enp)+SIZEOF_ETHEADER)+(off))))
+
+ enptype = enp->ether_type;
+ if (enptype >= ETHERPUP_TRAIL && enptype < ETHERPUP_TRAIL+ETHERPUP_NTRAILER)
+ {
+ off = (enptype - ETHERPUP_TRAIL) * 512;
+ if (off >= ETHERMTU) {
+ enperr[unit].bad_offset++;
+ ENPTRACE(saverrpkt((char *)enp, B_OFFSET, bcbp->b_msglen));
+
+ goto badinput;
+ }
+ enptype = *enpdataaddr(enp, off, u_short *);
+ resid = *(enpdataaddr(enp, off+2, u_short *));
+
+ if (off + resid > len) {
+ enperr[unit].bad_length++;
+ ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen));
+ goto badinput;
+ }
+ len = off + resid;
+ }
+ else
+ off = 0;
+
+ if( len == 0 ) {
+ enperr[unit].bad_length++;
+ ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen));
+ goto badinput;
+ }
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; enpget will then force this header
+ * information to be at the front, but we still have to drop
+ * the type and length which are at the front of any trailer data.
+ */
+
+ m = enpget(bcbp, len, off);
+ if( m == 0 ) {
+ enperr[unit].h_nobuffer++; /* host runs out of buf */
+ goto badinput;
+ }
+ if( off )
+ {
+ m->m_off += 2 * sizeof (u_short);
+ m->m_len -= 2 * sizeof (u_short);
+ }
+
+ switch (enptype)
+ {
+#ifdef INET
+ case ETHERPUP_IPTYPE:
+#ifdef notdef
+ arpipin(enp, m);
+#endif notdef
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+
+ case ETHERPUP_ARPTYPE:
+ arpinput(&es->es_ac, m);
+ return(0);
+#endif
+ default: /* unrecognized ethernet header */
+ enperr[unit].bad_packetype++;
+ if (printerror) {
+ printf("\nenp%d: Undefined packet type 0x%x ", unit,
+ enp->ether_type);
+ printf("from host: %x.%x.%x.%x.%x.%x\n",
+ enp->ether_shost[0], enp->ether_shost[1],
+ enp->ether_shost[2], enp->ether_shost[3],
+ enp->ether_shost[4], enp->ether_shost[5]);
+ } /* end debugging aid */
+ ENPTRACE(saverrpkt((char *)enp, B_PACKETYPE, bcbp->b_msglen));
+ m_freem(m);
+ goto badinput;
+ }
+
+ if (IF_QFULL(inq))
+ {
+ enperr[unit].inq_full++;
+ IF_DROP(inq);
+ m_freem(m);
+ return(0);
+ }
+ s = splimp();
+ IF_ENQUEUE(inq, m);
+ splx(s);
+badinput:
+ return(0); /* sanity */
+}
+
+/*
+ * Ethernet output routine. (called by user)
+ * Encapsulate a packet of type family for the local net.
+ * Use trailer local net encapsulation if enough data in first
+ * packet leaves a multiple of 512 bytes of data in remainder.
+ * If destination is this address or broadcast, send packet to
+ * loop device to kludge around the fact that 3com interfaces can't
+ * talk to themselves.
+ */
+
+enpoutput(ifp, m0, dst)
+struct ifnet *ifp;
+struct mbuf *m0;
+struct sockaddr *dst;
+{
+ int type, s, error;
+ struct ether_addr edst;
+ struct in_addr idst;
+
+ register struct enp_softc *es = &enp_softc[ifp->if_unit];
+ register struct mbuf *m = m0;
+ register struct ether_header *enp;
+ register int off, i;
+
+ struct mbuf *mcopy = (struct mbuf *) 0; /* Null */
+ int unit = ifp->if_unit;
+
+ switch( dst->sa_family )
+ {
+#ifdef INET
+ case AF_INET:
+ idst = ((struct sockaddr_in *)dst)->sin_addr;
+
+ /* translate internet to ethernet address */
+
+ switch(arpresolve(&es->es_ac, m, &idst, &edst)) {
+
+ case ARPRESOLVE_WILLSEND:
+ return (0); /* if not yet resolved */
+ case ARPRESOLVE_BROADCAST:
+ mcopy = m_copy(m, 0, (int)M_COPYALL);
+ if (mcopy)
+ looutput(&loif, mcopy, dst);
+
+ /* falls through ... */
+ case ARPRESOLVE_OK:
+ break;
+ }
+ off = ((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+ if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+ if (off > 0 && (off & 0x1ff) == 0 &&
+ m->m_off >= MMINOFF + 2 * sizeof (u_short))
+ {
+ type = ETHERPUP_TRAIL + (off>>9);
+ m->m_off -= 2 * sizeof (u_short);
+ m->m_len += 2 * sizeof (u_short);
+ *mtod(m, u_short *) = ETHERPUP_IPTYPE;
+ *(mtod(m, u_short *) + 1) = m->m_len;
+ goto gottrailertype;
+ }
+
+ type = ETHERPUP_IPTYPE;
+ off = 0;
+ goto gottype;
+#endif
+
+#ifdef notdef
+ case AF_RAW:
+ enp = mtod(m, struct ether_header *);
+ if (m->m_len < sizeof *enp)
+ {
+ error = EMSGSIZE;
+ goto bad;
+ }
+ goto gotheader;
+#endif
+
+ case AF_UNSPEC:
+ enp = (struct ether_header *)dst->sa_data;
+ bcopy( enp->ether_dhost, &edst, sizeof(edst));
+ type = enp->ether_type;
+ goto gottype;
+
+ default:
+ if (printerror)
+ printf("enp%d: can't handle af%d\n", unit,dst->sa_family);
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+
+gottrailertype:
+ /*
+ * Packet to be sent as trailer: move first packet
+ * (control information) to end of chain.
+ */
+ while (m->m_next)
+ m = m->m_next;
+ m->m_next = m0;
+ m = m0->m_next;
+ m0->m_next = 0;
+ m0 = m;
+
+gottype:
+ /*
+ * Add local net header. If no space in first mbuf,
+ * allocate another.
+ */
+ if (m->m_off > MMAXOFF ||
+ MMINOFF + SIZEOF_ETHEADER > m->m_off)
+ {
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0)
+ {
+ enperr[unit].h_nobuffer++; /* host runs out of buf */
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_next = m0;
+ m->m_off = MMINOFF;
+ m->m_len = SIZEOF_ETHEADER;
+ }
+ else
+ {
+ m->m_off -= SIZEOF_ETHEADER;
+ m->m_len += SIZEOF_ETHEADER;
+ }
+ enp = mtod(m, struct ether_header *);
+ bcopy( &edst, enp->ether_dhost, sizeof(enp->ether_dhost) );
+ enp->ether_type = type;
+gotheader:
+ bcopy( es->es_enaddr, enp->ether_shost, sizeof(enp->ether_shost));
+
+ /*
+ * Queue message on interface if possible
+ */
+
+ s = splimp();
+ if( enpput( unit,m ) )
+ {
+ error = ENOBUFS;
+ enperr[unit].c_nobuffer++; /* controller runs out of buf */
+ goto qfull;
+ }
+ splx( s );
+ es->es_if.if_opackets++;
+ return(0);
+qfull:
+ splx( s );
+ m0 = m;
+bad:
+ m_freem(m0);
+ return(error);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmitter
+ * buffer in Multibus memory.
+ */
+
+enpput( unit,m )
+int unit;
+struct mbuf *m;
+{
+ register BCB *bcbp;
+ register ENPDEVICE *addr;
+ register struct mbuf *mp;
+ register u_char *bp;
+ int ctr = 0;
+ long int v;
+ register short *vp = (short *)&v,
+ *sp;
+
+ addr = (ENPDEVICE *)enpinfo[ unit ]->ui_addr;
+
+ if ( ringempty( &addr->enp_hostfree ) )
+ return( 1 );
+
+ bcbp = (BCB *)ringget( &addr->enp_hostfree );
+ bcbp->b_len = 0;
+#ifdef TAHOE
+ sp = (short *)&bcbp->b_addr;
+ *vp = *sp; vp[1] = sp[1];
+ bp = (u_char *)v;
+#else
+ bp = (u_char *)bcbp->b_addr;
+#endif TAHOE
+ for (mp = m; mp; mp = mp->m_next)
+ {
+ register unsigned len;
+ u_char *mcp;
+
+ len = mp->m_len;
+ if( len == 0 )
+ continue;
+ mcp = mtod( mp,u_char * );
+ enpcopy( mcp,bp,len );
+ bp += len;
+ bcbp->b_len += len;
+ }
+ bcbp->b_len = max( MINPKTSIZE,bcbp->b_len );
+ bcbp->b_reserved = 0;
+ if ( ringput( &addr->enp_toenp,bcbp ) == 1 ) {
+ host_intr++;
+ INTR_ENP( addr );
+ }
+ m_freem(m);
+ return( 0 );
+}
+
+/*
+ * Routine to copy from Multibus memory into mbufs.
+ *
+ * Warning: This makes the fairly safe assumption that
+ * mbufs have even lengths.
+ */
+struct mbuf *
+enpget( bcbp, totlen, off0 )
+register BCB *bcbp;
+int totlen, off0;
+{
+ register struct mbuf *m;
+ register int off = off0;
+ register unsigned char *cp;
+ long int v;
+ register short *vp = (short *)&v,
+ *sp;
+
+ int len;
+ struct mbuf *top = 0;
+ struct mbuf **mp = ⊤
+
+#ifdef TAHOE
+ sp = (short *)&bcbp->b_addr;
+ *vp = *sp; vp[1] = sp[1];
+ cp = (unsigned char *)v + SIZEOF_ETHEADER;
+#else
+ cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
+#endif TAHOE
+
+ while( totlen > 0 )
+ {
+ u_char *mcp;
+
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto bad;
+ if( off )
+ {
+ len = totlen - off;
+#ifdef TAHOE
+ sp = (short *)&bcbp->b_addr;
+ *vp = *sp; vp[1] = sp[1];
+ cp = (unsigned char *)v + SIZEOF_ETHEADER
+ + off;
+#else
+ cp = (unsigned char *)bcbp->b_addr +
+ SIZEOF_ETHEADER + off;
+#endif TAHOE
+ }
+ else
+ len = totlen;
+
+
+ if (len >= CLBYTES) {
+ struct mbuf *p;
+
+ MCLGET(p, 1);
+ if (p != 0) {
+ m->m_len = len = CLBYTES;
+ m->m_off = (int)p - (int)m;
+ } else {
+ m->m_len = len = MIN(MLEN, len);
+ m->m_off = MMINOFF;
+ }
+ } else {
+ m->m_len = len = MIN(MLEN, len);
+ m->m_off = MMINOFF;
+ }
+
+ mcp = mtod(m, u_char *);
+ enpcopy(cp, mcp, len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ if (off == 0)
+ {
+ totlen -= len;
+ continue;
+ }
+ off += len;
+ if (off == totlen)
+ {
+#ifdef TAHOE
+ sp = (short *)&bcbp->b_addr;
+ *vp = *sp; vp[1] = sp[1];
+ cp = (unsigned char *)v + SIZEOF_ETHEADER;
+#else
+ cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
+#endif TAHOE
+ off = 0;
+ totlen = off0;
+ }
+ }
+ return (top);
+bad:
+ m_freem(top);
+ return (0);
+}
+
+/*
+ * Process an ioctl request.
+ * this can be called via the "socket" route for SIOCSIFADDR or
+ * by the cdev/inode route for SIOCSIFCCFWR/RD
+ *
+ */
+
+enpioctl(ifp, cmd, data)
+register struct ifnet *ifp;
+int cmd;
+caddr_t data;
+{
+ register int unit = ifp->if_unit;
+ register struct vba_device *md;
+ int s, error = 0;
+ struct sockaddr_in *sin;
+ struct sockaddr *sa;
+ struct enp_softc *es = &enp_softc[ifp->if_unit];
+ ENPDEVICE *addr;
+ struct config_entry *cf;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct sockaddr_in *et_addr;
+ int code, i;
+
+
+ if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
+ return(ENODEV);
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ s = splimp();
+ sa = (struct sockaddr *)&ifr->ifr_addr;
+ if (sa->sa_family == AF_UNSPEC ) {
+ if (sa->sa_data[0] & 1){ /*broad or multi-cast*/
+ splx( s );
+ return( EINVAL );
+ }
+ bcopy(sa->sa_data,es->es_enaddr,sizeof(es->es_enaddr));
+ enpinit( ifp->if_unit);
+ break;
+ }
+ sin = (struct sockaddr_in *)&ifr->ifr_addr;
+ if (sin->sin_family != AF_INET){
+ splx( s );
+ return( EINVAL );
+ }
+ if (ifp->if_flags & IFF_RUNNING)
+ if_rtinit(ifp, -1); /* delete previous route */
+ enpsetaddr(ifp, sin);
+ enpinit(ifp->if_unit);
+ enpgetaddr( ifp->if_unit );
+ splx(s);
+ break;
+
+
+ case SIOCSETETADDR: /* Set Ethernet station address */
+ s = splimp();
+ ifp->if_flags &= (~IFF_RUNNING | IFF_UP);
+ et_addr = (struct sockaddr_in *)&ifr->ifr_addr;
+ addr = (ENPDEVICE *)enpinfo[ifp->if_unit]->ui_addr;
+
+ /* Set station address and reset controller board */
+ {
+ u_char *to = &addr->enp_addr.e_baseaddr.ea_addr[0];
+ char *from = &et_addr->sin_zero[2];
+ int i;
+
+ for (i = 0 ; i < ETHADDR_SIZE; i++)
+ *to++ = (u_char) (~(*from++ & 0xff));
+ }
+ enpcopy(&addr->enp_addr.e_listsize, &code, sizeof(code));
+ code |= E_ADDR_SUPP;
+ enpcopy(&code, &addr->enp_addr.e_listsize, sizeof(code));
+ enpreset(ifp->if_unit); /* Re-initialize */
+ enpgetaddr(ifp->if_unit);
+ splx(s);
+ break;
+
+ case SIOCGETETADDR: /* Get Foreign Hosts' Ethernet addresses */
+ arpwhohas(&es->es_ac, (struct in_addr *)ifr->ifr_data);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return(error);
+}
+
+enpsetaddr(ifp, sin)
+register struct ifnet *ifp;
+register struct sockaddr_in *sin;
+{
+
+ ifp->if_addr = *(struct sockaddr *)sin;
+ ifp->if_net = in_netof(sin->sin_addr);
+ ifp->if_host[0] = in_lnaof(sin->sin_addr);
+ sin = (struct sockaddr_in *)&ifp->if_broadaddr;
+ sin->sin_family = AF_INET;
+ sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+ ifp->if_flags |= IFF_BROADCAST;
+}
+
+
+/*
+ * Get the ethernet addr, store it and print it
+ * Read the ethernet address off the board, one byte at a time.
+ * put it in enp_softc
+ */
+
+
+enpgetaddr( unit )
+int unit;
+{
+ register struct enp_softc *es = &enp_softc[unit];
+ register ENPDEVICE *addr =(ENPDEVICE *)enpinfo[unit]->ui_addr;
+ int i;
+
+#ifdef TAHOE
+ enpcopy(&addr->enp_addr.e_baseaddr, &es->es_boardaddr, sizeof(es->es_boardaddr));
+#else
+ es->es_boardaddr = addr->enp_addr.e_baseaddr;
+#endif TAHOE
+ bcopy(&es->es_boardaddr, es->es_enaddr, ETHADDR_SIZE);
+ return( 1 );
+}
+
+/*
+ * enpram device
+ *
+ */
+
+enpr_open( dev )
+{
+ register int unit = minor(dev);
+ register struct vba_device *md;
+ register ENPDEVICE *addr;
+
+ if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
+ (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
+ return(ENODEV);
+ if (addr->enp_state != S_ENPRESET)
+ return(EACCES); /* enp is not in reset state, don't open */
+ if ( !enpismapped[unit] ) {
+ ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
+ ++enpismapped[unit];
+ }
+ enpram[unit] = ENP_OPEN;
+ return( 0 );
+}
+
+enpr_close(dev)
+{
+ enpram[minor(dev)] = ENP_CLOSE;
+ return( 0 );
+}
+
+enpr_read( dev,uio )
+int dev;
+register struct uio *uio;
+{
+ register ENPDEVICE *addr;
+ register struct iovec *iov;
+ register r=0;
+
+ if (enpram[minor(dev)] != ENP_OPEN)
+ return(EACCES);
+ if ( uio->uio_offset > RAM_SIZE )
+ return( ENODEV );
+ if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
+ iov->iov_len = RAM_SIZE - uio->uio_offset;
+ addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
+ iov = uio->uio_iov;
+
+ if( r = enpcopyout( &addr->enp_ram[ uio->uio_offset ], iov->iov_base,
+ iov->iov_len ) )
+ return( r );
+
+ uio->uio_resid -= iov->iov_len;
+ iov->iov_len = 0;
+
+ return( 0 );
+}
+
+enpr_write( dev,uio )
+int dev;
+register struct uio *uio;
+{
+ register ENPDEVICE *addr;
+ register struct iovec *iov;
+ register r=0;
+
+ if (enpram[minor(dev)] != ENP_OPEN)
+ return(EACCES);
+ addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
+ iov = uio->uio_iov;
+
+ if ( uio->uio_offset > RAM_SIZE )
+ return( ENODEV );
+ if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
+ iov->iov_len = RAM_SIZE - uio->uio_offset;
+ if( r = enpcopyin( iov->iov_base, &addr->enp_ram[ uio->uio_offset ],
+ iov->iov_len ) )
+ return( r );
+
+ uio->uio_resid -= iov->iov_len;
+ iov->iov_len = 0;
+
+ return( 0 );
+}
+
+enpr_ioctl( dev,cmd,arg,fflag )
+dev_t dev;
+caddr_t *arg;
+{
+ register ENPDEVICE *addr;
+ long int v;
+ register short *vp = (short *)&v, *sp;
+ register unit = minor(dev);
+ register struct vba_device *md;
+
+ if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
+ (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
+ return(ENODEV);
+ switch( cmd )
+ {
+ case ENPIOGO:
+/* not needed if prom based version */
+#ifdef TAHOE
+ sp = (short *)&addr->enp_base;
+ v = (int)addr;
+ *sp = *vp; sp[1] = vp[1];
+#else
+ addr->enp_base = (int)addr;
+#endif TAHOE
+ addr->enp_intrvec = intvec[ unit ];
+ ENP_GO( addr, ENPSTART );
+ DELAY( 200000 );
+ enpattach( enpinfo[ unit ] );
+ enpinit( unit );
+ addr->enp_state = S_ENPRUN; /* it is running now */
+/* end of not needed */
+
+ break;
+
+ case ENPIORESET:
+ RESET_ENP( addr );
+ addr->enp_state = S_ENPRESET; /* it is reset now */
+ DELAY( 100000 );
+ break;
+ }
+ return( 0 );
+}
+
+/*
+ * routines to synchronize enp and host
+ */
+
+static
+ringinit( rp,size )
+register RING *rp;
+{
+ register int i;
+ register short *sp;
+
+ rp->r_rdidx = rp->r_wrtidx = 0;
+ rp->r_size = size;
+}
+
+static
+ringempty( rp )
+register RING *rp;
+{
+ return( rp->r_rdidx == rp->r_wrtidx );
+}
+
+static
+ringfull( rp )
+register RING *rp;
+{
+ register short idx;
+
+ idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
+ return( idx == rp->r_rdidx );
+}
+
+static
+ringput( rp,v )
+register RING *rp;
+{
+ register int idx;
+ register short *vp = (short *)&v,
+ *sp;
+
+ idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
+ if( idx != rp->r_rdidx )
+ {
+#ifdef TAHOE
+ sp = (short *)&rp->r_slot[ rp->r_wrtidx ];
+ *sp = *vp; sp[1] = vp[1];
+#else
+ rp->r_slot[ rp->r_wrtidx ] = v;
+#endif TAHOE
+ rp->r_wrtidx = idx;
+ if( (idx -= rp->r_rdidx) < 0 )
+ idx += rp->r_size;
+ return( idx ); /* num ring entries */
+ }
+ return( 0 );
+}
+
+static
+ringget( rp )
+register RING *rp;
+{
+ register int i = 0;
+ long int v;
+ register short *vp = (short *)&v,
+ *sp;
+
+ if( rp->r_rdidx != rp->r_wrtidx )
+ {
+#ifdef TAHOE
+ sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+ *vp = *sp; vp[1] = sp[1];
+ i = v;
+#else
+ i = rp->r_slot[ rp->r_rdidx ];
+#endif TAHOE
+ rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
+ }
+ return( i );
+}
+
+#ifdef notdef
+struct mbuf *
+m_tofree( rp )
+register RING *rp;
+{
+ long int v = 0;
+ register short *vp = (short *)&v,
+ *sp;
+
+ if( rp->r_rdidx != rp->r_wrtidx )
+ {
+#ifdef TAHOE
+ sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+ *vp = *sp; vp[1] = sp[1];
+ /* *sp = 0xffff; sp[1] = 0xffff; */
+#else
+ v = rp->r_slot[ rp->r_rdidx ];
+#endif TAHOE
+ rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
+ }
+ return( (struct mbuf *)v );
+}
+#endif
+static
+fir( rp )
+register RING *rp;
+{
+ long int v;
+ register short *vp = (short *)&v,
+ *sp;
+
+ if( rp->r_rdidx != rp->r_wrtidx )
+#ifdef TAHOE
+ {
+ sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+ *vp = *sp; vp[1] = sp[1];
+ return( v );
+ }
+#else
+ return( rp->r_slot[ rp->r_rdidx ] );
+#endif TAHOE
+ else
+ return( 0 );
+}
+
+
+static
+prtbytes( addr )
+register char *addr;
+{
+ register int i;
+
+ for( i = 0; i < 12; i++ )
+ {
+ printf("%X ",*addr&0377);
+ addr++;
+ }
+ printf("\n");
+}
+
+static
+enpcopy(from, to, cnt)
+register char *from, *to;
+register cnt;
+{
+ register c;
+ register short *f, *t;
+
+ if (((int)from & 01) && ((int)to & 01)) {
+ /* source & dest at odd addresses */
+ *to++ = *from++;
+ --cnt;
+ }
+ if (cnt > 1 && (((int)to & 01)==0) && (((int)from & 01)==0)) {
+ t = (short *) to;
+ f = (short *) from;
+ for( c = cnt>>1; c; --c) /* even address copy */
+ *t++ = *f++;
+ cnt &= 1;
+ if ( cnt ) { /* odd len */
+ from = (char *) f;
+ to = (char *) t;
+ *to = *from;
+ }
+ }
+ while (cnt-- > 0) /* one of the address(es) must be odd */
+ *to++ = *from++;
+
+}
+
+static
+enpcopyin(userv, kernv, cnt)
+{
+
+ if (useracc(userv, cnt, 1)) {
+ enpcopy( userv, kernv, cnt );
+ return( 0 );
+ }
+ else return( EFAULT );
+}
+
+
+static
+enpcopyout(kernv, userv, cnt)
+{
+
+ if (useracc(userv, cnt, 0)) {
+ enpcopy( kernv, userv, cnt );
+ return( 0 );
+ }
+ else return( EFAULT );
+}
+#endif