xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 45795)
134508Skarels /*
234508Skarels  * Copyright (c) 1988 Regents of the University of California.
334508Skarels  * All rights reserved.
434508Skarels  *
535383Skarels  * This code is derived from software contributed to Berkeley by
635383Skarels  * Computer Consoles Inc.
735383Skarels  *
844532Sbostic  * %sccs.include.redist.c%
934508Skarels  *
10*45795Sbostic  *	@(#)if_enp.c	7.8 (Berkeley) 12/16/90
1134508Skarels  */
1229649Ssam 
1329649Ssam #include "enp.h"
1429649Ssam #if NENP > 0
1529649Ssam /*
1630986Ssam  * CMC ENP-20 Ethernet Controller.
1729649Ssam  */
18*45795Sbostic #include "sys/param.h"
19*45795Sbostic #include "sys/systm.h"
20*45795Sbostic #include "sys/mbuf.h"
21*45795Sbostic #include "sys/buf.h"
22*45795Sbostic #include "sys/protosw.h"
23*45795Sbostic #include "sys/socket.h"
24*45795Sbostic #include "sys/vmmac.h"
25*45795Sbostic #include "sys/ioctl.h"
26*45795Sbostic #include "sys/errno.h"
27*45795Sbostic #include "sys/vmparam.h"
28*45795Sbostic #include "sys/syslog.h"
29*45795Sbostic #include "sys/uio.h"
3029649Ssam 
31*45795Sbostic #include "net/if.h"
32*45795Sbostic #include "net/netisr.h"
33*45795Sbostic #include "net/route.h"
3430230Ssam #ifdef INET
35*45795Sbostic #include "netinet/in.h"
36*45795Sbostic #include "netinet/in_systm.h"
37*45795Sbostic #include "netinet/in_var.h"
38*45795Sbostic #include "netinet/ip.h"
39*45795Sbostic #include "netinet/ip_var.h"
40*45795Sbostic #include "netinet/if_ether.h"
4130230Ssam #endif
4230230Ssam #ifdef NS
43*45795Sbostic #include "netns/ns.h"
44*45795Sbostic #include "netns/ns_if.h"
4530230Ssam #endif
4629649Ssam 
47*45795Sbostic #include "../include/cpu.h"
48*45795Sbostic #include "../include/pte.h"
49*45795Sbostic #include "../include/mtpr.h"
5030230Ssam 
51*45795Sbostic #include "../vba/vbavar.h"
52*45795Sbostic #include "../if/if_enpreg.h"
5329649Ssam 
5430230Ssam #define ENPSTART	0xf02000	/* standard enp start addr */
5530230Ssam #define	ENPUNIT(dev)	(minor(dev))	/* for enp ram devices */
5630986Ssam /* macros for dealing with longs in i/o space */
5730986Ssam #define	ENPGETLONG(a)	((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
5830986Ssam #define	ENPSETLONG(a,v) \
5930986Ssam    { register u_short *wp = (u_short *)(a); \
6030986Ssam      wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
6129649Ssam 
6229649Ssam int	enpprobe(), enpattach(), enpintr();
6330298Ssam long	enpstd[] = { 0xfff41000, 0xfff61000, 0 };
6430230Ssam struct  vba_device *enpinfo[NENP];
6529649Ssam struct  vba_driver enpdriver =
6630230Ssam     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
6729649Ssam 
6835383Skarels int	enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart();
6929649Ssam struct  mbuf *enpget();
7029649Ssam 
7129649Ssam /*
7229649Ssam  * Ethernet software status per interface.
7329649Ssam  *
7429649Ssam  * Each interface is referenced by a network interface structure,
7529649Ssam  * es_if, which the routing code uses to locate the interface.
7629649Ssam  * This structure contains the output queue for the interface, its address, ...
7729649Ssam  */
7830230Ssam struct  enp_softc {
7930230Ssam 	struct  arpcom es_ac;           /* common ethernet structures */
8030230Ssam #define es_if		es_ac.ac_if
8130986Ssam #define es_addr	es_ac.ac_enaddr
8230230Ssam 	short	es_ivec;		/* interrupt vector */
8330230Ssam } enp_softc[NENP];
8430230Ssam extern	struct ifnet loif;
8529649Ssam 
enpprobe(reg,vi)8630230Ssam enpprobe(reg, vi)
8730230Ssam 	caddr_t reg;
8830230Ssam 	struct vba_device *vi;
8929649Ssam {
9030230Ssam 	register br, cvec;		/* must be r12, r11 */
9130230Ssam 	register struct enpdevice *addr = (struct enpdevice *)reg;
9230230Ssam 	struct enp_softc *es = &enp_softc[vi->ui_unit];
9329649Ssam 
9430230Ssam #ifdef lint
9530295Ssam 	br = 0; cvec = br; br = cvec;
9630230Ssam 	enpintr(0);
9730230Ssam #endif
9830295Ssam 	if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
9930230Ssam 		return (0);
10030230Ssam 	es->es_ivec = --vi->ui_hd->vh_lastiv;
10130230Ssam 	addr->enp_state = S_ENPRESET;		/* reset by VERSAbus reset */
10230230Ssam 	br = 0x14, cvec = es->es_ivec;		/* XXX */
10330230Ssam 	return (sizeof (struct enpdevice));
10429649Ssam }
10529649Ssam 
10629649Ssam /*
10729649Ssam  * Interface exists: make available by filling in network interface
10829649Ssam  * record.  System will initialize the interface when it is ready
10929649Ssam  * to accept packets.
11029649Ssam  */
enpattach(ui)11130230Ssam enpattach(ui)
11230230Ssam 	register struct vba_device *ui;
11329649Ssam {
11430230Ssam 	struct enp_softc *es = &enp_softc[ui->ui_unit];
11530230Ssam 	register struct ifnet *ifp = &es->es_if;
11629649Ssam 
11730230Ssam 	ifp->if_unit = ui->ui_unit;
11829649Ssam 	ifp->if_name = "enp";
11929649Ssam 	ifp->if_mtu = ETHERMTU;
12029649Ssam 	ifp->if_init = enpinit;
12129649Ssam 	ifp->if_ioctl = enpioctl;
12237474Ssklower 	ifp->if_output = ether_output;
12335411Skarels 	ifp->if_start = enpstart;
12429649Ssam 	ifp->if_reset = enpreset;
12535411Skarels 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
12629649Ssam 	if_attach(ifp);
12729649Ssam }
12829649Ssam 
12929649Ssam /*
13030230Ssam  * Reset of interface after "system" reset.
13129649Ssam  */
enpreset(unit,vban)13230230Ssam enpreset(unit, vban)
13330230Ssam 	int unit, vban;
13429649Ssam {
13530230Ssam 	register struct vba_device *ui;
13629649Ssam 
13730230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
13830230Ssam 	    ui->ui_vbanum != vban)
13930230Ssam 		return;
14030230Ssam 	printf(" enp%d", unit);
14129649Ssam 	enpinit(unit);
14229649Ssam }
14329649Ssam 
14429649Ssam /*
14530230Ssam  * Initialization of interface; clear recorded pending operations.
14629649Ssam  */
enpinit(unit)14730230Ssam enpinit(unit)
14830230Ssam 	int unit;
14929649Ssam {
15030230Ssam 	struct enp_softc *es = &enp_softc[unit];
15130230Ssam 	register struct vba_device *ui = enpinfo[unit];
15230230Ssam 	struct enpdevice *addr;
15330230Ssam 	register struct ifnet *ifp = &es->es_if;
15430230Ssam 	int s;
15529649Ssam 
15630230Ssam 	if (ifp->if_addrlist == (struct ifaddr *)0)
15730230Ssam 		return;
15830230Ssam 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
15930230Ssam 		addr = (struct enpdevice *)ui->ui_addr;
16030230Ssam 		s = splimp();
16130230Ssam 		RESET_ENP(addr);
16230230Ssam 		DELAY(200000);
16330230Ssam 		es->es_if.if_flags |= IFF_RUNNING;
16430230Ssam 		splx(s);
16529649Ssam 	}
16629649Ssam }
16729649Ssam 
16829649Ssam /*
16929649Ssam  * Ethernet interface interrupt.
17029649Ssam  */
enpintr(unit)17130230Ssam enpintr(unit)
17230230Ssam 	int unit;
17329649Ssam {
17430230Ssam 	register struct enpdevice *addr;
17530230Ssam 	register BCB *bcbp;
17629649Ssam 
17730230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
17830295Ssam #if ENP == 30
17930230Ssam 	if (!IS_ENP_INTR(addr))
18029649Ssam 		return;
18130230Ssam 	ACK_ENP_INTR(addr);
18230295Ssam #endif
18330295Ssam 	while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
18435383Skarels 		enpread(&enp_softc[unit], bcbp);
18530295Ssam 		(void) ringput((RING *)&addr->enp_enpfree, bcbp);
18629649Ssam 	}
18729649Ssam }
18829649Ssam 
18929649Ssam /*
19029649Ssam  * Read input packet, examine its packet type, and enqueue it.
19129649Ssam  */
19230295Ssam enpread(es, bcbp)
19330230Ssam 	struct enp_softc *es;
19430230Ssam 	register BCB *bcbp;
19529649Ssam {
19629649Ssam 	register struct ether_header *enp;
19729649Ssam 	struct mbuf *m;
19830295Ssam 	int s, len, off, resid;
19929649Ssam 
20029649Ssam 	es->es_if.if_ipackets++;
20129649Ssam 	/*
20229649Ssam 	 * Get input data length.
20329649Ssam 	 * Get pointer to ethernet header (in input buffer).
20429649Ssam 	 * Deal with trailer protocol: if type is PUP trailer
20529649Ssam 	 * get true type from first 16-bit word past data.
20629649Ssam 	 * Remember that type was trailer by setting off.
20729649Ssam 	 */
20830230Ssam 	len = bcbp->b_msglen - sizeof (struct ether_header);
20930986Ssam 	enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
21030230Ssam #define enpdataaddr(enp, off, type) \
21130230Ssam     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
21230230Ssam 	enp->ether_type = ntohs((u_short)enp->ether_type);
21330230Ssam 	if (enp->ether_type >= ETHERTYPE_TRAIL &&
21430230Ssam 	    enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
21530230Ssam 		off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
21630230Ssam 		if (off >= ETHERMTU)
21735383Skarels 			return;
21830230Ssam 		enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
21930230Ssam 		resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
22030230Ssam 		if (off + resid > len)
22135383Skarels 			return;
22229649Ssam 		len = off + resid;
22330230Ssam 	} else
22429649Ssam 		off = 0;
22530230Ssam 	if (len == 0)
22635383Skarels 		return;
22729649Ssam 
22829649Ssam 	/*
22929649Ssam 	 * Pull packet off interface.  Off is nonzero if packet
23029649Ssam 	 * has trailing header; enpget will then force this header
23135383Skarels 	 * information to be at the front.
23229649Ssam 	 */
23330986Ssam 	m = enpget((u_char *)enp, len, off, &es->es_if);
23430230Ssam 	if (m == 0)
23535383Skarels 		return;
23637474Ssklower 	ether_input(&es->es_if, enp, m);
23729649Ssam }
23829649Ssam 
23935383Skarels enpstart(ifp)
24030230Ssam 	struct ifnet *ifp;
24129649Ssam {
24229649Ssam 
24335383Skarels 	if (enpput(ifp))
24435411Skarels 		return (ENOBUFS);
24535411Skarels 	else
24635411Skarels 		return (0);
24729649Ssam }
24829649Ssam 
24929649Ssam /*
25030230Ssam  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
25129649Ssam  */
25235383Skarels enpput(ifp)
25335383Skarels struct ifnet *ifp;
25429649Ssam {
25529649Ssam 	register BCB *bcbp;
25630230Ssam 	register struct enpdevice *addr;
25729649Ssam 	register struct mbuf *mp;
25829649Ssam 	register u_char *bp;
25930230Ssam 	register u_int len;
26035411Skarels 	int unit = ifp->if_unit, ret = 1;
26135383Skarels 	struct mbuf *m;
26229649Ssam 
26330230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
26435383Skarels again:
26535411Skarels 	if (ringempty((RING *)&addr->enp_hostfree))  {
26635411Skarels 	/*	ifp->if_flags |= IFF_OACTIVE; */
26735411Skarels 		return (ret);
26835411Skarels 	}
26935383Skarels 	IF_DEQUEUE(&ifp->if_snd, m);
27035411Skarels 	if (m == 0) {
27135411Skarels 		ifp->if_flags &= ~IFF_OACTIVE;
27235411Skarels 		return (0);
27335411Skarels 	}
27430295Ssam 	bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
27529649Ssam 	bcbp->b_len = 0;
27630986Ssam 	bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
27730230Ssam 	for (mp = m; mp; mp = mp->m_next) {
27829649Ssam 		len = mp->m_len;
27930230Ssam 		if (len == 0)
28029649Ssam 			continue;
28135411Skarels 		enpcopy(mtod(mp, u_char *), bp, len);
28229649Ssam 		bp += len;
28329649Ssam 		bcbp->b_len += len;
28429649Ssam 	}
28535411Skarels 	bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
28629649Ssam 	bcbp->b_reserved = 0;
28730295Ssam 	if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
28830230Ssam 		INTR_ENP(addr);
28929649Ssam 	m_freem(m);
29035411Skarels 	ret = 0;
29135383Skarels 	goto again;
29229649Ssam }
29329649Ssam 
29429649Ssam /*
29530230Ssam  * Routine to copy from VERSAbus memory into mbufs.
29629649Ssam  *
29729649Ssam  * Warning: This makes the fairly safe assumption that
29829649Ssam  * mbufs have even lengths.
29929649Ssam  */
30029649Ssam struct mbuf *
enpget(rxbuf,totlen,off,ifp)30135383Skarels enpget(rxbuf, totlen, off, ifp)
30230230Ssam 	u_char *rxbuf;
30335383Skarels 	int totlen, off;
30430230Ssam 	struct ifnet *ifp;
30529649Ssam {
30635411Skarels 	register u_char *cp;
30729649Ssam 	register struct mbuf *m;
30830230Ssam 	struct mbuf *top = 0, **mp = &top;
30935383Skarels 	int len;
31035383Skarels 	u_char *packet_end;
31129649Ssam 
31235383Skarels 	rxbuf += sizeof (struct ether_header);
31335383Skarels 	cp = rxbuf;
31435383Skarels 	packet_end = cp + totlen;
31535383Skarels 	if (off) {
31635383Skarels 		off += 2 * sizeof(u_short);
31735383Skarels 		totlen -= 2 *sizeof(u_short);
31835383Skarels 		cp = rxbuf + off;
31935383Skarels 	}
32035383Skarels 
32135383Skarels 	MGETHDR(m, M_DONTWAIT, MT_DATA);
32235383Skarels 	if (m == 0)
32335383Skarels 		return (0);
32435383Skarels 	m->m_pkthdr.rcvif = ifp;
32535383Skarels 	m->m_pkthdr.len = totlen;
32635383Skarels 	m->m_len = MHLEN;
32735383Skarels 
32830230Ssam 	while (totlen > 0) {
32935383Skarels 		if (top) {
33035383Skarels 			MGET(m, M_DONTWAIT, MT_DATA);
33135383Skarels 			if (m == 0) {
33235383Skarels 				m_freem(top);
33335383Skarels 				return (0);
33435383Skarels 			}
33535383Skarels 			m->m_len = MLEN;
33635383Skarels 		}
33735383Skarels 		len = min(totlen, (packet_end - cp));
33835383Skarels 		if (len >= MINCLSIZE) {
33935383Skarels 			MCLGET(m, M_DONTWAIT);
34035383Skarels 			if (m->m_flags & M_EXT)
34135383Skarels 				m->m_len = len = min(len, MCLBYTES);
34230230Ssam 			else
34335383Skarels 				len = m->m_len;
34430230Ssam 		} else {
34530230Ssam 			/*
34635383Skarels 			 * Place initial small packet/header at end of mbuf.
34730230Ssam 			 */
34835383Skarels 			if (len < m->m_len) {
34935411Skarels 				if (top == 0 && len + max_linkhdr <= m->m_len)
35035383Skarels 					m->m_data += max_linkhdr;
35135383Skarels 				m->m_len = len;
35235383Skarels 			} else
35335383Skarels 				len = m->m_len;
35430230Ssam 		}
35535411Skarels 		enpcopy(cp, mtod(m, u_char *), (u_int)len);
35629649Ssam 		*mp = m;
35729649Ssam 		mp = &m->m_next;
35835383Skarels 		totlen -= len;
35935383Skarels 		cp += len;
36035383Skarels 		if (cp == packet_end)
36135383Skarels 			cp = rxbuf;
36229649Ssam 	}
36329649Ssam 	return (top);
36429649Ssam }
36529649Ssam 
enpcopy(from,to,cnt)36630230Ssam enpcopy(from, to, cnt)
36730295Ssam 	register u_char *from, *to;
36830295Ssam 	register u_int cnt;
36930230Ssam {
37030230Ssam 	register c;
37130230Ssam 	register short *f, *t;
37230230Ssam 
37330230Ssam 	if (((int)from&01) && ((int)to&01)) {
37430230Ssam 		/* source & dest at odd addresses */
37530230Ssam 		*to++ = *from++;
37630230Ssam 		--cnt;
37730230Ssam 	}
37830230Ssam 	if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
37930230Ssam 		t = (short *)to;
38030230Ssam 		f = (short *)from;
38130230Ssam 		for (c = cnt>>1; c; --c)	/* even address copy */
38230230Ssam 			*t++ = *f++;
38330230Ssam 		cnt &= 1;
38430230Ssam 		if (cnt) {			/* odd len */
38530295Ssam 			from = (u_char *)f;
38630295Ssam 			to = (u_char *)t;
38730230Ssam 			*to = *from;
38830230Ssam 		}
38930230Ssam 	}
39030295Ssam 	while ((int)cnt-- > 0)	/* one of the address(es) must be odd */
39130230Ssam 		*to++ = *from++;
39230230Ssam }
39330230Ssam 
39429649Ssam /*
39529649Ssam  * Process an ioctl request.
39629649Ssam  */
enpioctl(ifp,cmd,data)39729649Ssam enpioctl(ifp, cmd, data)
39830230Ssam 	register struct ifnet *ifp;
39930230Ssam 	int cmd;
40030230Ssam 	caddr_t data;
40129649Ssam {
40230230Ssam 	register struct ifaddr *ifa = (struct ifaddr *)data;
40330230Ssam 	struct enpdevice *addr;
40430230Ssam 	int s = splimp(), error = 0;
40529649Ssam 
40629649Ssam 	switch (cmd) {
40729649Ssam 
40829649Ssam 	case SIOCSIFADDR:
40930230Ssam 		ifp->if_flags |= IFF_UP;
41037474Ssklower 		switch (ifa->ifa_addr->sa_family) {
41130230Ssam #ifdef INET
41230230Ssam 		case AF_INET:
41330230Ssam 			enpinit(ifp->if_unit);
41430230Ssam 			((struct arpcom *)ifp)->ac_ipaddr =
41530230Ssam 			    IA_SIN(ifa)->sin_addr;
41630230Ssam 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
41729649Ssam 			break;
41830230Ssam #endif
41930230Ssam #ifdef NS
42030230Ssam 		case AF_NS: {
42130230Ssam 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
42230230Ssam 			struct enp_softc *es = &enp_softc[ifp->if_unit];
42330230Ssam 
42430230Ssam 			if (!ns_nullhost(*ina)) {
42530230Ssam 				ifp->if_flags &= ~IFF_RUNNING;
42630230Ssam 				addr = (struct enpdevice *)
42730230Ssam 				    enpinfo[ifp->if_unit]->ui_addr;
42830230Ssam 				enpsetaddr(ifp->if_unit, addr,
42930230Ssam 				    ina->x_host.c_host);
43030230Ssam 			} else
43130986Ssam 				ina->x_host = *(union ns_host *)es->es_addr;
43230230Ssam 			enpinit(ifp->if_unit);
43330230Ssam 			break;
43429649Ssam 		}
43530230Ssam #endif
43630230Ssam 		default:
43730230Ssam 			enpinit(ifp->if_unit);
43830230Ssam 			break;
43929649Ssam 		}
44029649Ssam 		break;
44129649Ssam 
44230230Ssam 	case SIOCSIFFLAGS:
44330230Ssam 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
44430230Ssam 			enpinit(ifp->if_unit);		/* reset board */
44530230Ssam 			ifp->if_flags &= ~IFF_RUNNING;
44630230Ssam 		} else if (ifp->if_flags&IFF_UP &&
44730230Ssam 		     (ifp->if_flags&IFF_RUNNING) == 0)
44830230Ssam 			enpinit(ifp->if_unit);
44929649Ssam 		break;
45029649Ssam 
45129649Ssam 	default:
45229649Ssam 		error = EINVAL;
45329649Ssam 	}
45430230Ssam 	splx(s);
45530230Ssam 	return (error);
45629649Ssam }
45729649Ssam 
enpsetaddr(unit,addr,enaddr)45830230Ssam enpsetaddr(unit, addr, enaddr)
45930230Ssam 	int unit;
46030230Ssam 	struct enpdevice *addr;
46130230Ssam 	u_char *enaddr;
46229649Ssam {
46329649Ssam 
46430986Ssam 	enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
46530986Ssam 	    sizeof (struct ether_addr));
46630230Ssam 	enpinit(unit);
46730986Ssam 	enpgetaddr(unit, addr);
46829649Ssam }
46929649Ssam 
enpgetaddr(unit,addr)47030986Ssam enpgetaddr(unit, addr)
47130986Ssam 	int unit;
47230986Ssam 	struct enpdevice *addr;
47330986Ssam {
47430986Ssam 	struct enp_softc *es = &enp_softc[unit];
47530986Ssam 
47630986Ssam 	enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
47730986Ssam 	    sizeof (struct ether_addr));
47830986Ssam 	printf("enp%d: hardware address %s\n",
47930986Ssam 	    unit, ether_sprintf(es->es_addr));
48030986Ssam }
48130986Ssam 
48229649Ssam /*
48330230Ssam  * Routines to synchronize enp and host.
48429649Ssam  */
48530295Ssam #ifdef notdef
48629649Ssam static
ringinit(rp,size)48730230Ssam ringinit(rp, size)
48830230Ssam 	register RING *rp;
48929649Ssam {
49029649Ssam 
49129649Ssam 	rp->r_rdidx = rp->r_wrtidx = 0;
49229649Ssam 	rp->r_size = size;
49329649Ssam }
49429649Ssam 
49529649Ssam static
ringfull(rp)49630295Ssam ringfull(rp)
49730230Ssam 	register RING *rp;
49829649Ssam {
49930295Ssam 	register short idx;
50030230Ssam 
50130295Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
50230295Ssam 	return (idx == rp->r_rdidx);
50329649Ssam }
50429649Ssam 
50529649Ssam static
fir(rp)50630295Ssam fir(rp)
50730230Ssam 	register RING *rp;
50829649Ssam {
50929649Ssam 
51030295Ssam 	return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
51129649Ssam }
51230295Ssam #endif
51329649Ssam 
51429649Ssam static
ringempty(rp)51530295Ssam ringempty(rp)
51630295Ssam 	register RING *rp;
51730295Ssam {
51830295Ssam 
51930295Ssam 	return (rp->r_rdidx == rp->r_wrtidx);
52030295Ssam }
52130295Ssam 
52230295Ssam static
ringput(rp,v)52330230Ssam ringput(rp, v)
52430230Ssam 	register RING *rp;
52530295Ssam 	BCB *v;
52629649Ssam {
52729649Ssam 	register int idx;
52829649Ssam 
52929649Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
53030230Ssam 	if (idx != rp->r_rdidx) {
53130986Ssam 		ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
53229649Ssam 		rp->r_wrtidx = idx;
53330230Ssam 		if ((idx -= rp->r_rdidx) < 0)
53429649Ssam 			idx += rp->r_size;
53530230Ssam 		return (idx);			/* num ring entries */
53629649Ssam 	}
53730230Ssam 	return (0);
53829649Ssam }
53929649Ssam 
54029649Ssam static
ringget(rp)54130230Ssam ringget(rp)
54230230Ssam 	register RING *rp;
54329649Ssam {
54429649Ssam 	register int i = 0;
54529649Ssam 
54630230Ssam 	if (rp->r_rdidx != rp->r_wrtidx) {
54730986Ssam 		i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
54829649Ssam 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
54929649Ssam 	}
55030230Ssam 	return (i);
55129649Ssam }
55229649Ssam 
55330230Ssam /*
55430230Ssam  * ENP Ram device.
55530230Ssam  */
enpr_open(dev)55630230Ssam enpr_open(dev)
55730230Ssam 	dev_t dev;
55829649Ssam {
55930230Ssam 	register int unit = ENPUNIT(dev);
56030230Ssam 	struct vba_device *ui;
56130230Ssam 	struct enpdevice *addr;
56229649Ssam 
56330230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
56430230Ssam 	    (addr = (struct enpdevice *)ui->ui_addr) == 0)
56530230Ssam 		return (ENODEV);
56630230Ssam 	if (addr->enp_state != S_ENPRESET)
56730230Ssam 		return (EACCES);  /* enp is not in reset state, don't open  */
56830230Ssam 	return (0);
56929649Ssam }
57029649Ssam 
57130295Ssam /*ARGSUSED*/
enpr_close(dev)57230230Ssam enpr_close(dev)
57330230Ssam 	dev_t dev;
57429649Ssam {
57529649Ssam 
57630230Ssam 	return (0);
57729649Ssam }
57829649Ssam 
enpr_read(dev,uio)57930230Ssam enpr_read(dev, uio)
58030230Ssam 	dev_t dev;
58130230Ssam 	register struct uio *uio;
58229649Ssam {
58330230Ssam 	register struct iovec *iov;
58430230Ssam 	struct enpdevice *addr;
58529649Ssam 
58630230Ssam 	if (uio->uio_offset > RAM_SIZE)
58730230Ssam 		return (ENODEV);
58830295Ssam 	iov = uio->uio_iov;
58930230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
59030230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
59130230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
59230986Ssam 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
59330986Ssam 		return (EFAULT);
59430295Ssam 	enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
59530295Ssam 	    (u_char *)iov->iov_base, (u_int)iov->iov_len);
59630230Ssam 	uio->uio_resid -= iov->iov_len;
59730230Ssam 	iov->iov_len = 0;
59830230Ssam 	return (0);
59929649Ssam }
60029649Ssam 
enpr_write(dev,uio)60130230Ssam enpr_write(dev, uio)
60230230Ssam 	dev_t dev;
60330230Ssam 	register struct uio *uio;
60429649Ssam {
60530230Ssam 	register struct enpdevice *addr;
60630230Ssam 	register struct iovec *iov;
60729649Ssam 
60830230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
60930230Ssam 	iov = uio->uio_iov;
61030230Ssam 	if (uio->uio_offset > RAM_SIZE)
61130230Ssam 		return (ENODEV);
61230230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
61330230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
61430986Ssam 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
61530986Ssam 		return (EFAULT);
61630295Ssam 	enpcopy((u_char *)iov->iov_base,
61730295Ssam 	    (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
61830230Ssam 	uio->uio_resid -= iov->iov_len;
61940659Skarels 	uio->uio_offset += iov->iov_len;
62030230Ssam 	iov->iov_len = 0;
62130230Ssam 	return (0);
62229649Ssam }
62329649Ssam 
62430295Ssam /*ARGSUSED*/
enpr_ioctl(dev,cmd,data)62530230Ssam enpr_ioctl(dev, cmd, data)
62630230Ssam 	dev_t dev;
62730230Ssam 	caddr_t data;
62829649Ssam {
62930230Ssam 	register unit = ENPUNIT(dev);
63030986Ssam 	struct enpdevice *addr;
63129649Ssam 
63230230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
63330230Ssam 	switch(cmd) {
63430230Ssam 
63530230Ssam 	case ENPIOGO:
63630986Ssam 		ENPSETLONG(&addr->enp_base, addr);
63730230Ssam 		addr->enp_intrvec = enp_softc[unit].es_ivec;
63830230Ssam 		ENP_GO(addr, ENPSTART);
63930230Ssam 		DELAY(200000);
64030230Ssam 		enpinit(unit);
64130986Ssam 		/*
64230986Ssam 		 * Fetch Ethernet address after link level
64330986Ssam 		 * is booted (firmware copies manufacturer's
64430986Ssam 		 * address from on-board ROM).
64530986Ssam 		 */
64630986Ssam 		enpgetaddr(unit, addr);
64730986Ssam 		addr->enp_state = S_ENPRUN;
64830230Ssam 		break;
64930230Ssam 
65030230Ssam 	case ENPIORESET:
65130230Ssam 		RESET_ENP(addr);
65230986Ssam 		addr->enp_state = S_ENPRESET;
65330230Ssam 		DELAY(100000);
65430230Ssam 		break;
65530986Ssam 	default:
65630986Ssam 		return (EINVAL);
65729649Ssam 	}
65830230Ssam 	return (0);
65929649Ssam }
66029649Ssam #endif
661