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 = ⊤
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