home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / tahoe / if / if_enp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  15.8 KB  |  687 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Computer Consoles Inc.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  *    @(#)if_enp.c    7.8 (Berkeley) 12/16/90
  37.  */
  38.  
  39. #include "enp.h"
  40. #if NENP > 0
  41. /*
  42.  * CMC ENP-20 Ethernet Controller.
  43.  */
  44. #include "sys/param.h"
  45. #include "sys/systm.h"
  46. #include "sys/mbuf.h"
  47. #include "sys/buf.h"
  48. #include "sys/protosw.h"
  49. #include "sys/socket.h"
  50. #include "sys/vmmac.h"
  51. #include "sys/ioctl.h"
  52. #include "sys/errno.h"
  53. #include "sys/vmparam.h"
  54. #include "sys/syslog.h"
  55. #include "sys/uio.h"
  56.  
  57. #include "net/if.h"
  58. #include "net/netisr.h"
  59. #include "net/route.h"
  60. #ifdef INET
  61. #include "netinet/in.h"
  62. #include "netinet/in_systm.h"
  63. #include "netinet/in_var.h"
  64. #include "netinet/ip.h"
  65. #include "netinet/ip_var.h"
  66. #include "netinet/if_ether.h"
  67. #endif
  68. #ifdef NS
  69. #include "netns/ns.h"
  70. #include "netns/ns_if.h"
  71. #endif
  72.  
  73. #include "../include/cpu.h"
  74. #include "../include/pte.h"
  75. #include "../include/mtpr.h"
  76.  
  77. #include "../vba/vbavar.h"
  78. #include "../if/if_enpreg.h"
  79.  
  80. #define ENPSTART    0xf02000    /* standard enp start addr */
  81. #define    ENPUNIT(dev)    (minor(dev))    /* for enp ram devices */
  82. /* macros for dealing with longs in i/o space */
  83. #define    ENPGETLONG(a)    ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
  84. #define    ENPSETLONG(a,v) \
  85.    { register u_short *wp = (u_short *)(a); \
  86.      wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
  87.  
  88. int    enpprobe(), enpattach(), enpintr();
  89. long    enpstd[] = { 0xfff41000, 0xfff61000, 0 };
  90. struct  vba_device *enpinfo[NENP];
  91. struct  vba_driver enpdriver = 
  92.     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
  93.  
  94. int    enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart();
  95. struct  mbuf *enpget();
  96.  
  97. /*
  98.  * Ethernet software status per interface.
  99.  *
  100.  * Each interface is referenced by a network interface structure,
  101.  * es_if, which the routing code uses to locate the interface.
  102.  * This structure contains the output queue for the interface, its address, ...
  103.  */
  104. struct  enp_softc {
  105.     struct  arpcom es_ac;           /* common ethernet structures */
  106. #define es_if        es_ac.ac_if
  107. #define es_addr    es_ac.ac_enaddr
  108.     short    es_ivec;        /* interrupt vector */
  109. } enp_softc[NENP]; 
  110. extern    struct ifnet loif;
  111.  
  112. enpprobe(reg, vi)
  113.     caddr_t reg;
  114.     struct vba_device *vi;
  115. {
  116.     register br, cvec;        /* must be r12, r11 */
  117.     register struct enpdevice *addr = (struct enpdevice *)reg;
  118.     struct enp_softc *es = &enp_softc[vi->ui_unit];
  119.  
  120. #ifdef lint
  121.     br = 0; cvec = br; br = cvec;
  122.     enpintr(0);
  123. #endif
  124.     if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
  125.         return (0);
  126.     es->es_ivec = --vi->ui_hd->vh_lastiv;
  127.     addr->enp_state = S_ENPRESET;        /* reset by VERSAbus reset */
  128.     br = 0x14, cvec = es->es_ivec;        /* XXX */
  129.     return (sizeof (struct enpdevice));
  130. }
  131.  
  132. /*
  133.  * Interface exists: make available by filling in network interface
  134.  * record.  System will initialize the interface when it is ready
  135.  * to accept packets. 
  136.  */
  137. enpattach(ui)
  138.     register struct vba_device *ui;
  139. {
  140.     struct enp_softc *es = &enp_softc[ui->ui_unit];
  141.     register struct ifnet *ifp = &es->es_if;
  142.  
  143.     ifp->if_unit = ui->ui_unit;
  144.     ifp->if_name = "enp";
  145.     ifp->if_mtu = ETHERMTU;
  146.     ifp->if_init = enpinit;
  147.     ifp->if_ioctl = enpioctl;
  148.     ifp->if_output = ether_output;
  149.     ifp->if_start = enpstart;
  150.     ifp->if_reset = enpreset;
  151.     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  152.     if_attach(ifp);
  153. }
  154.  
  155. /*
  156.  * Reset of interface after "system" reset.
  157.  */
  158. enpreset(unit, vban)
  159.     int unit, vban;
  160. {
  161.     register struct vba_device *ui;
  162.  
  163.     if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
  164.         ui->ui_vbanum != vban)
  165.         return;
  166.     printf(" enp%d", unit);
  167.     enpinit(unit);
  168. }
  169.  
  170. /*
  171.  * Initialization of interface; clear recorded pending operations.
  172.  */
  173. enpinit(unit)
  174.     int unit;
  175. {
  176.     struct enp_softc *es = &enp_softc[unit];
  177.     register struct vba_device *ui = enpinfo[unit];
  178.     struct enpdevice *addr;
  179.     register struct ifnet *ifp = &es->es_if;
  180.     int s;
  181.  
  182.     if (ifp->if_addrlist == (struct ifaddr *)0)
  183.         return;
  184.     if ((ifp->if_flags & IFF_RUNNING) == 0) {
  185.         addr = (struct enpdevice *)ui->ui_addr;
  186.         s = splimp();
  187.         RESET_ENP(addr);
  188.         DELAY(200000);
  189.         es->es_if.if_flags |= IFF_RUNNING;
  190.         splx(s);
  191.     }
  192. }
  193.  
  194. /*
  195.  * Ethernet interface interrupt.
  196.  */
  197. enpintr(unit)
  198.     int unit;
  199. {
  200.     register struct enpdevice *addr;
  201.     register BCB *bcbp;
  202.  
  203.     addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
  204. #if ENP == 30
  205.     if (!IS_ENP_INTR(addr))
  206.         return;
  207.     ACK_ENP_INTR(addr);
  208. #endif
  209.     while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
  210.         enpread(&enp_softc[unit], bcbp);
  211.         (void) ringput((RING *)&addr->enp_enpfree, bcbp); 
  212.     }
  213. }
  214.  
  215. /*
  216.  * Read input packet, examine its packet type, and enqueue it.
  217.  */
  218. enpread(es, bcbp)
  219.     struct enp_softc *es;
  220.     register BCB *bcbp;
  221. {
  222.     register struct ether_header *enp;
  223.     struct mbuf *m;
  224.     int s, len, off, resid;
  225.  
  226.     es->es_if.if_ipackets++; 
  227.     /*
  228.      * Get input data length.
  229.      * Get pointer to ethernet header (in input buffer).
  230.      * Deal with trailer protocol: if type is PUP trailer
  231.      * get true type from first 16-bit word past data.
  232.      * Remember that type was trailer by setting off.
  233.      */
  234.     len = bcbp->b_msglen - sizeof (struct ether_header);
  235.     enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
  236. #define enpdataaddr(enp, off, type) \
  237.     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
  238.     enp->ether_type = ntohs((u_short)enp->ether_type);
  239.     if (enp->ether_type >= ETHERTYPE_TRAIL &&
  240.         enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
  241.         off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
  242.         if (off >= ETHERMTU)
  243.             return;
  244.         enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
  245.         resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
  246.         if (off + resid > len)
  247.             return;
  248.         len = off + resid;
  249.     } else
  250.         off = 0;
  251.     if (len == 0)
  252.         return;
  253.  
  254.     /*
  255.      * Pull packet off interface.  Off is nonzero if packet
  256.      * has trailing header; enpget will then force this header
  257.      * information to be at the front.
  258.      */
  259.     m = enpget((u_char *)enp, len, off, &es->es_if);
  260.     if (m == 0)
  261.         return;
  262.     ether_input(&es->es_if, enp, m);
  263. }
  264.  
  265. enpstart(ifp)
  266.     struct ifnet *ifp;
  267. {
  268.  
  269.     if (enpput(ifp))
  270.         return (ENOBUFS);
  271.     else
  272.         return (0);
  273. }
  274.  
  275. /*
  276.  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
  277.  */
  278. enpput(ifp)
  279. struct ifnet *ifp;
  280. {
  281.     register BCB *bcbp;
  282.     register struct enpdevice *addr;
  283.     register struct mbuf *mp;
  284.     register u_char *bp;
  285.     register u_int len;
  286.     int unit = ifp->if_unit, ret = 1;
  287.     struct mbuf *m;
  288.  
  289.     addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
  290. again:
  291.     if (ringempty((RING *)&addr->enp_hostfree))  {
  292.     /*    ifp->if_flags |= IFF_OACTIVE; */
  293.         return (ret);
  294.     }
  295.     IF_DEQUEUE(&ifp->if_snd, m);
  296.     if (m == 0) {
  297.         ifp->if_flags &= ~IFF_OACTIVE;
  298.         return (0);
  299.     }
  300.     bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
  301.     bcbp->b_len = 0;
  302.     bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
  303.     for (mp = m; mp; mp = mp->m_next) {
  304.         len = mp->m_len;
  305.         if (len == 0)
  306.             continue;
  307.         enpcopy(mtod(mp, u_char *), bp, len);
  308.         bp += len;
  309.         bcbp->b_len += len;
  310.     }
  311.     bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
  312.     bcbp->b_reserved = 0;
  313.     if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
  314.         INTR_ENP(addr);
  315.     m_freem(m);
  316.     ret = 0;
  317.     goto again;
  318. }
  319.  
  320. /*
  321.  * Routine to copy from VERSAbus memory into mbufs.
  322.  *
  323.  * Warning: This makes the fairly safe assumption that
  324.  * mbufs have even lengths.
  325.  */
  326. struct mbuf *
  327. enpget(rxbuf, totlen, off, ifp)
  328.     u_char *rxbuf;
  329.     int totlen, off;
  330.     struct ifnet *ifp;
  331. {
  332.     register u_char *cp;
  333.     register struct mbuf *m;
  334.     struct mbuf *top = 0, **mp = ⊤
  335.     int len;
  336.     u_char *packet_end;
  337.  
  338.     rxbuf += sizeof (struct ether_header);
  339.     cp = rxbuf;
  340.     packet_end = cp + totlen;
  341.     if (off) {
  342.         off += 2 * sizeof(u_short);
  343.         totlen -= 2 *sizeof(u_short);
  344.         cp = rxbuf + off;
  345.     }
  346.  
  347.     MGETHDR(m, M_DONTWAIT, MT_DATA);
  348.     if (m == 0)
  349.         return (0);
  350.     m->m_pkthdr.rcvif = ifp;
  351.     m->m_pkthdr.len = totlen;
  352.     m->m_len = MHLEN;
  353.  
  354.     while (totlen > 0) {
  355.         if (top) {
  356.             MGET(m, M_DONTWAIT, MT_DATA);
  357.             if (m == 0) {
  358.                 m_freem(top);
  359.                 return (0);
  360.             }
  361.             m->m_len = MLEN;
  362.         }
  363.         len = min(totlen, (packet_end - cp));
  364.         if (len >= MINCLSIZE) {
  365.             MCLGET(m, M_DONTWAIT);
  366.             if (m->m_flags & M_EXT)
  367.                 m->m_len = len = min(len, MCLBYTES);
  368.             else
  369.                 len = m->m_len;
  370.         } else {
  371.             /*
  372.              * Place initial small packet/header at end of mbuf.
  373.              */
  374.             if (len < m->m_len) {
  375.                 if (top == 0 && len + max_linkhdr <= m->m_len)
  376.                     m->m_data += max_linkhdr;
  377.                 m->m_len = len;
  378.             } else
  379.                 len = m->m_len;
  380.         }
  381.         enpcopy(cp, mtod(m, u_char *), (u_int)len);
  382.         *mp = m;
  383.         mp = &m->m_next;
  384.         totlen -= len;
  385.         cp += len;
  386.         if (cp == packet_end)
  387.             cp = rxbuf;
  388.     }
  389.     return (top);
  390. }
  391.  
  392. enpcopy(from, to, cnt)
  393.     register u_char *from, *to;
  394.     register u_int cnt;
  395. {
  396.     register c;
  397.     register short *f, *t;
  398.  
  399.     if (((int)from&01) && ((int)to&01)) {
  400.         /* source & dest at odd addresses */
  401.         *to++ = *from++;
  402.         --cnt;
  403.     }
  404.     if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
  405.         t = (short *)to;
  406.         f = (short *)from;
  407.         for (c = cnt>>1; c; --c)    /* even address copy */
  408.             *t++ = *f++;
  409.         cnt &= 1;
  410.         if (cnt) {            /* odd len */
  411.             from = (u_char *)f;
  412.             to = (u_char *)t;
  413.             *to = *from;
  414.         }
  415.     }
  416.     while ((int)cnt-- > 0)    /* one of the address(es) must be odd */
  417.         *to++ = *from++;
  418. }
  419.  
  420. /*
  421.  * Process an ioctl request.
  422.  */
  423. enpioctl(ifp, cmd, data)
  424.     register struct ifnet *ifp;
  425.     int cmd;
  426.     caddr_t data;
  427. {
  428.     register struct ifaddr *ifa = (struct ifaddr *)data;
  429.     struct enpdevice *addr;
  430.     int s = splimp(), error = 0;
  431.  
  432.     switch (cmd) {
  433.  
  434.     case SIOCSIFADDR:
  435.         ifp->if_flags |= IFF_UP;
  436.         switch (ifa->ifa_addr->sa_family) {
  437. #ifdef INET
  438.         case AF_INET:
  439.             enpinit(ifp->if_unit);
  440.             ((struct arpcom *)ifp)->ac_ipaddr =
  441.                 IA_SIN(ifa)->sin_addr;
  442.             arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
  443.             break;
  444. #endif
  445. #ifdef NS
  446.         case AF_NS: {
  447.             struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
  448.             struct enp_softc *es = &enp_softc[ifp->if_unit];
  449.  
  450.             if (!ns_nullhost(*ina)) {
  451.                 ifp->if_flags &= ~IFF_RUNNING;
  452.                 addr = (struct enpdevice *)
  453.                     enpinfo[ifp->if_unit]->ui_addr;
  454.                 enpsetaddr(ifp->if_unit, addr,
  455.                     ina->x_host.c_host);
  456.             } else
  457.                 ina->x_host = *(union ns_host *)es->es_addr;
  458.             enpinit(ifp->if_unit);
  459.             break;
  460.         }
  461. #endif
  462.         default:
  463.             enpinit(ifp->if_unit);
  464.             break;
  465.         }
  466.         break;
  467.  
  468.     case SIOCSIFFLAGS:
  469.         if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
  470.             enpinit(ifp->if_unit);        /* reset board */
  471.             ifp->if_flags &= ~IFF_RUNNING;
  472.         } else if (ifp->if_flags&IFF_UP &&
  473.              (ifp->if_flags&IFF_RUNNING) == 0)
  474.             enpinit(ifp->if_unit);
  475.         break;
  476.  
  477.     default:
  478.         error = EINVAL;
  479.     }
  480.     splx(s);
  481.     return (error);
  482. }
  483.  
  484. enpsetaddr(unit, addr, enaddr)
  485.     int unit;
  486.     struct enpdevice *addr;
  487.     u_char *enaddr;
  488. {
  489.  
  490.     enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
  491.         sizeof (struct ether_addr));
  492.     enpinit(unit);
  493.     enpgetaddr(unit, addr);
  494. }
  495.  
  496. enpgetaddr(unit, addr)
  497.     int unit;
  498.     struct enpdevice *addr;
  499. {
  500.     struct enp_softc *es = &enp_softc[unit];
  501.  
  502.     enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
  503.         sizeof (struct ether_addr));
  504.     printf("enp%d: hardware address %s\n",
  505.         unit, ether_sprintf(es->es_addr));
  506. }
  507.  
  508. /* 
  509.  * Routines to synchronize enp and host.
  510.  */
  511. #ifdef notdef
  512. static
  513. ringinit(rp, size)
  514.     register RING *rp;
  515. {
  516.  
  517.     rp->r_rdidx = rp->r_wrtidx = 0;
  518.     rp->r_size = size;
  519. }
  520.  
  521. static
  522. ringfull(rp)
  523.     register RING *rp;
  524. {
  525.     register short idx;
  526.  
  527.     idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
  528.     return (idx == rp->r_rdidx);
  529. }
  530.  
  531. static
  532. fir(rp)
  533.     register RING *rp;
  534. {
  535.  
  536.     return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
  537. }
  538. #endif
  539.  
  540. static
  541. ringempty(rp)
  542.     register RING *rp;
  543. {
  544.  
  545.     return (rp->r_rdidx == rp->r_wrtidx);
  546. }
  547.  
  548. static
  549. ringput(rp, v)
  550.     register RING *rp;
  551.     BCB *v;
  552. {
  553.     register int idx;
  554.  
  555.     idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
  556.     if (idx != rp->r_rdidx) {
  557.         ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
  558.         rp->r_wrtidx = idx;
  559.         if ((idx -= rp->r_rdidx) < 0)
  560.             idx += rp->r_size;
  561.         return (idx);            /* num ring entries */
  562.     }
  563.     return (0);
  564. }
  565.  
  566. static
  567. ringget(rp)
  568.     register RING *rp;
  569. {
  570.     register int i = 0;
  571.  
  572.     if (rp->r_rdidx != rp->r_wrtidx) {
  573.         i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
  574.         rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
  575.     }
  576.     return (i);
  577. }
  578.  
  579. /*
  580.  * ENP Ram device.
  581.  */
  582. enpr_open(dev)
  583.     dev_t dev;
  584. {
  585.     register int unit = ENPUNIT(dev);
  586.     struct vba_device *ui;
  587.     struct enpdevice *addr;
  588.  
  589.     if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
  590.         (addr = (struct enpdevice *)ui->ui_addr) == 0)
  591.         return (ENODEV);
  592.     if (addr->enp_state != S_ENPRESET)
  593.         return (EACCES);  /* enp is not in reset state, don't open  */
  594.     return (0);
  595. }
  596.  
  597. /*ARGSUSED*/
  598. enpr_close(dev)
  599.     dev_t dev;
  600. {
  601.  
  602.     return (0);
  603. }
  604.  
  605. enpr_read(dev, uio)
  606.     dev_t dev;
  607.     register struct uio *uio;
  608. {
  609.     register struct iovec *iov;
  610.     struct enpdevice *addr;
  611.  
  612.     if (uio->uio_offset > RAM_SIZE)
  613.         return (ENODEV);
  614.     iov = uio->uio_iov;
  615.     if (uio->uio_offset + iov->iov_len > RAM_SIZE)
  616.         iov->iov_len = RAM_SIZE - uio->uio_offset;
  617.     addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
  618.     if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
  619.         return (EFAULT);
  620.     enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
  621.         (u_char *)iov->iov_base, (u_int)iov->iov_len);
  622.     uio->uio_resid -= iov->iov_len;
  623.     iov->iov_len = 0;
  624.     return (0);
  625. }
  626.  
  627. enpr_write(dev, uio)
  628.     dev_t dev;
  629.     register struct uio *uio;
  630. {
  631.     register struct enpdevice *addr;
  632.     register struct iovec *iov;
  633.  
  634.     addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
  635.     iov = uio->uio_iov;
  636.     if (uio->uio_offset > RAM_SIZE)
  637.         return (ENODEV);
  638.     if (uio->uio_offset + iov->iov_len > RAM_SIZE)
  639.         iov->iov_len = RAM_SIZE - uio->uio_offset;
  640.     if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
  641.         return (EFAULT);
  642.     enpcopy((u_char *)iov->iov_base,
  643.         (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
  644.     uio->uio_resid -= iov->iov_len;
  645.     uio->uio_offset += iov->iov_len;
  646.     iov->iov_len = 0;
  647.     return (0);
  648. }
  649.  
  650. /*ARGSUSED*/
  651. enpr_ioctl(dev, cmd, data)
  652.     dev_t dev;
  653.     caddr_t data;
  654. {
  655.     register unit = ENPUNIT(dev);
  656.     struct enpdevice *addr;
  657.  
  658.     addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
  659.     switch(cmd) {
  660.  
  661.     case ENPIOGO:
  662.         ENPSETLONG(&addr->enp_base, addr);
  663.         addr->enp_intrvec = enp_softc[unit].es_ivec;
  664.         ENP_GO(addr, ENPSTART);
  665.         DELAY(200000);
  666.         enpinit(unit);
  667.         /*
  668.          * Fetch Ethernet address after link level
  669.          * is booted (firmware copies manufacturer's
  670.          * address from on-board ROM).
  671.          */
  672.         enpgetaddr(unit, addr);
  673.         addr->enp_state = S_ENPRUN;
  674.         break;
  675.  
  676.     case ENPIORESET:
  677.         RESET_ENP(addr);
  678.         addr->enp_state = S_ENPRESET;
  679.         DELAY(100000);
  680.         break;
  681.     default:
  682.         return (EINVAL);
  683.     }
  684.     return (0);
  685. }
  686. #endif
  687.