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