checkpointed by sklower, after hacking a start routine and enpget.
[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 *
979ea28d 20 * @(#)if_enp.c 7.3 (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;
6013a59e 133 ifp->if_reset = enpreset;
979ea28d 134 ifp->if_start = enpstart;
bc2cef1e 135 ifp->if_flags = IFF_BROADCAST;
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{
979ea28d
MK
252 int error = 0;
253 int s = splimp();
6013a59e 254
979ea28d 255 if (enpput(ifp))
6013a59e 256 error = ENOBUFS;
bc2cef1e 257 splx(s);
bc2cef1e 258 return (error);
6013a59e
SL
259}
260
261/*
bc2cef1e 262 * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
6013a59e 263 */
979ea28d
MK
264enpput(ifp)
265struct ifnet *ifp;
6013a59e
SL
266{
267 register BCB *bcbp;
bc2cef1e 268 register struct enpdevice *addr;
6013a59e
SL
269 register struct mbuf *mp;
270 register u_char *bp;
bc2cef1e 271 register u_int len;
979ea28d 272 int unit = ifp->if_unit;
bc2cef1e 273 u_char *mcp;
979ea28d 274 struct mbuf *m;
6013a59e 275
bc2cef1e 276 addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
979ea28d 277again:
9d61b7ff 278 if (ringempty((RING *)&addr->enp_hostfree))
bc2cef1e 279 return (1);
979ea28d
MK
280 IF_DEQUEUE(&ifp->if_snd, m);
281 if (m == 0) return (0);
9d61b7ff 282 bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
6013a59e 283 bcbp->b_len = 0;
7779e59b 284 bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
bc2cef1e 285 for (mp = m; mp; mp = mp->m_next) {
6013a59e 286 len = mp->m_len;
bc2cef1e 287 if (len == 0)
6013a59e 288 continue;
bc2cef1e
SL
289 mcp = mtod(mp, u_char *);
290 enpcopy(mcp, bp, len);
6013a59e
SL
291 bp += len;
292 bcbp->b_len += len;
293 }
7779e59b 294 bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
6013a59e 295 bcbp->b_reserved = 0;
9d61b7ff 296 if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
bc2cef1e 297 INTR_ENP(addr);
6013a59e 298 m_freem(m);
979ea28d 299 goto again;
6013a59e
SL
300}
301
302/*
bc2cef1e 303 * Routine to copy from VERSAbus memory into mbufs.
6013a59e
SL
304 *
305 * Warning: This makes the fairly safe assumption that
306 * mbufs have even lengths.
307 */
308struct mbuf *
979ea28d 309enpget(rxbuf, totlen, off, ifp)
bc2cef1e 310 u_char *rxbuf;
979ea28d 311 int totlen, off;
bc2cef1e 312 struct ifnet *ifp;
6013a59e 313{
bc2cef1e 314 register u_char *cp, *mcp;
6013a59e 315 register struct mbuf *m;
bc2cef1e 316 struct mbuf *top = 0, **mp = &top;
979ea28d
MK
317 int len;
318 u_char *packet_end;
319
320 rxbuf += sizeof (struct ether_header);
321 cp = rxbuf;
322 packet_end = cp + totlen;
323 if (off) {
324 off += 2 * sizeof(u_short);
325 totlen -= 2 *sizeof(u_short);
326 cp = rxbuf + off;
327 }
328
329 MGETHDR(m, M_DONTWAIT, MT_DATA);
330 if (m == 0)
331 return (0);
332 m->m_pkthdr.rcvif = ifp;
333 m->m_pkthdr.len = totlen;
334 m->m_len = MHLEN;
6013a59e 335
bc2cef1e 336 while (totlen > 0) {
979ea28d
MK
337 if (top) {
338 MGET(m, M_DONTWAIT, MT_DATA);
339 if (m == 0) {
340 m_freem(top);
341 return (0);
342 }
343 m->m_len = MLEN;
344 }
345 len = min(totlen, (packet_end - cp));
346 if (len >= MINCLSIZE) {
347 MCLGET(m, M_DONTWAIT);
348 if (m->m_flags & M_EXT)
349 m->m_len = len = min(len, MCLBYTES);
bc2cef1e 350 else
979ea28d 351 len = m->m_len;
bc2cef1e 352 } else {
bc2cef1e 353 /*
979ea28d 354 * Place initial small packet/header at end of mbuf.
bc2cef1e 355 */
979ea28d
MK
356 if (len < m->m_len) {
357 if (top == 0 && len < max_linkhdr + m->m_len)
358 m->m_data += max_linkhdr;
359 m->m_len = len;
360 } else
361 len = m->m_len;
bc2cef1e 362 }
979ea28d 363 mcp = mtod(m, u_char *);
9d61b7ff 364 enpcopy(cp, mcp, (u_int)len);
6013a59e
SL
365 *mp = m;
366 mp = &m->m_next;
979ea28d
MK
367 totlen -= len;
368 cp += len;
369 if (cp == packet_end)
370 cp = rxbuf;
6013a59e
SL
371 }
372 return (top);
6013a59e
SL
373}
374
bc2cef1e 375enpcopy(from, to, cnt)
9d61b7ff
SL
376 register u_char *from, *to;
377 register u_int cnt;
bc2cef1e
SL
378{
379 register c;
380 register short *f, *t;
381
382 if (((int)from&01) && ((int)to&01)) {
383 /* source & dest at odd addresses */
384 *to++ = *from++;
385 --cnt;
386 }
387 if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
388 t = (short *)to;
389 f = (short *)from;
390 for (c = cnt>>1; c; --c) /* even address copy */
391 *t++ = *f++;
392 cnt &= 1;
393 if (cnt) { /* odd len */
9d61b7ff
SL
394 from = (u_char *)f;
395 to = (u_char *)t;
bc2cef1e
SL
396 *to = *from;
397 }
398 }
9d61b7ff 399 while ((int)cnt-- > 0) /* one of the address(es) must be odd */
bc2cef1e
SL
400 *to++ = *from++;
401}
402
6013a59e
SL
403/*
404 * Process an ioctl request.
6013a59e 405 */
6013a59e 406enpioctl(ifp, cmd, data)
bc2cef1e
SL
407 register struct ifnet *ifp;
408 int cmd;
409 caddr_t data;
6013a59e 410{
bc2cef1e
SL
411 register struct ifaddr *ifa = (struct ifaddr *)data;
412 struct enpdevice *addr;
413 int s = splimp(), error = 0;
6013a59e
SL
414
415 switch (cmd) {
416
417 case SIOCSIFADDR:
bc2cef1e
SL
418 ifp->if_flags |= IFF_UP;
419 switch (ifa->ifa_addr.sa_family) {
420#ifdef INET
421 case AF_INET:
422 enpinit(ifp->if_unit);
423 ((struct arpcom *)ifp)->ac_ipaddr =
424 IA_SIN(ifa)->sin_addr;
425 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
426 break;
427#endif
428#ifdef NS
429 case AF_NS: {
430 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
431 struct enp_softc *es = &enp_softc[ifp->if_unit];
432
433 if (!ns_nullhost(*ina)) {
434 ifp->if_flags &= ~IFF_RUNNING;
435 addr = (struct enpdevice *)
436 enpinfo[ifp->if_unit]->ui_addr;
437 enpsetaddr(ifp->if_unit, addr,
438 ina->x_host.c_host);
439 } else
7779e59b 440 ina->x_host = *(union ns_host *)es->es_addr;
bc2cef1e 441 enpinit(ifp->if_unit);
6013a59e
SL
442 break;
443 }
bc2cef1e
SL
444#endif
445 default:
446 enpinit(ifp->if_unit);
447 break;
6013a59e 448 }
6013a59e
SL
449 break;
450
bc2cef1e
SL
451 case SIOCSIFFLAGS:
452 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
453 enpinit(ifp->if_unit); /* reset board */
454 ifp->if_flags &= ~IFF_RUNNING;
455 } else if (ifp->if_flags&IFF_UP &&
456 (ifp->if_flags&IFF_RUNNING) == 0)
457 enpinit(ifp->if_unit);
6013a59e
SL
458 break;
459
460 default:
461 error = EINVAL;
462 }
bc2cef1e
SL
463 splx(s);
464 return (error);
6013a59e
SL
465}
466
bc2cef1e
SL
467enpsetaddr(unit, addr, enaddr)
468 int unit;
469 struct enpdevice *addr;
470 u_char *enaddr;
6013a59e 471{
7779e59b
SL
472
473 enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
474 sizeof (struct ether_addr));
bc2cef1e 475 enpinit(unit);
7779e59b
SL
476 enpgetaddr(unit, addr);
477}
478
479enpgetaddr(unit, addr)
480 int unit;
481 struct enpdevice *addr;
482{
483 struct enp_softc *es = &enp_softc[unit];
484
485 enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
486 sizeof (struct ether_addr));
487 printf("enp%d: hardware address %s\n",
488 unit, ether_sprintf(es->es_addr));
6013a59e
SL
489}
490
491/*
bc2cef1e 492 * Routines to synchronize enp and host.
6013a59e 493 */
9d61b7ff 494#ifdef notdef
6013a59e 495static
bc2cef1e
SL
496ringinit(rp, size)
497 register RING *rp;
6013a59e 498{
6013a59e
SL
499
500 rp->r_rdidx = rp->r_wrtidx = 0;
501 rp->r_size = size;
502}
503
504static
9d61b7ff 505ringfull(rp)
bc2cef1e 506 register RING *rp;
6013a59e 507{
9d61b7ff 508 register short idx;
bc2cef1e 509
9d61b7ff
SL
510 idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
511 return (idx == rp->r_rdidx);
6013a59e
SL
512}
513
514static
9d61b7ff 515fir(rp)
bc2cef1e 516 register RING *rp;
6013a59e 517{
6013a59e 518
9d61b7ff
SL
519 return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
520}
521#endif
522
523static
524ringempty(rp)
525 register RING *rp;
526{
527
528 return (rp->r_rdidx == rp->r_wrtidx);
6013a59e
SL
529}
530
531static
bc2cef1e
SL
532ringput(rp, v)
533 register RING *rp;
9d61b7ff 534 BCB *v;
6013a59e
SL
535{
536 register int idx;
6013a59e
SL
537
538 idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
bc2cef1e 539 if (idx != rp->r_rdidx) {
7779e59b 540 ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
6013a59e 541 rp->r_wrtidx = idx;
bc2cef1e 542 if ((idx -= rp->r_rdidx) < 0)
6013a59e 543 idx += rp->r_size;
bc2cef1e 544 return (idx); /* num ring entries */
6013a59e 545 }
bc2cef1e 546 return (0);
6013a59e
SL
547}
548
549static
bc2cef1e
SL
550ringget(rp)
551 register RING *rp;
6013a59e
SL
552{
553 register int i = 0;
bc2cef1e
SL
554
555 if (rp->r_rdidx != rp->r_wrtidx) {
7779e59b 556 i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
6013a59e
SL
557 rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
558 }
bc2cef1e 559 return (i);
6013a59e
SL
560}
561
bc2cef1e
SL
562/*
563 * ENP Ram device.
564 */
565enpr_open(dev)
566 dev_t dev;
6013a59e 567{
bc2cef1e
SL
568 register int unit = ENPUNIT(dev);
569 struct vba_device *ui;
570 struct enpdevice *addr;
6013a59e 571
bc2cef1e
SL
572 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
573 (addr = (struct enpdevice *)ui->ui_addr) == 0)
574 return (ENODEV);
575 if (addr->enp_state != S_ENPRESET)
576 return (EACCES); /* enp is not in reset state, don't open */
577 return (0);
6013a59e
SL
578}
579
9d61b7ff 580/*ARGSUSED*/
bc2cef1e
SL
581enpr_close(dev)
582 dev_t dev;
6013a59e 583{
6013a59e 584
bc2cef1e 585 return (0);
6013a59e
SL
586}
587
bc2cef1e
SL
588enpr_read(dev, uio)
589 dev_t dev;
590 register struct uio *uio;
6013a59e 591{
bc2cef1e
SL
592 register struct iovec *iov;
593 struct enpdevice *addr;
6013a59e 594
bc2cef1e
SL
595 if (uio->uio_offset > RAM_SIZE)
596 return (ENODEV);
9d61b7ff 597 iov = uio->uio_iov;
bc2cef1e
SL
598 if (uio->uio_offset + iov->iov_len > RAM_SIZE)
599 iov->iov_len = RAM_SIZE - uio->uio_offset;
600 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
7779e59b
SL
601 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
602 return (EFAULT);
9d61b7ff
SL
603 enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
604 (u_char *)iov->iov_base, (u_int)iov->iov_len);
bc2cef1e
SL
605 uio->uio_resid -= iov->iov_len;
606 iov->iov_len = 0;
607 return (0);
6013a59e
SL
608}
609
bc2cef1e
SL
610enpr_write(dev, uio)
611 dev_t dev;
612 register struct uio *uio;
613{
614 register struct enpdevice *addr;
615 register struct iovec *iov;
6013a59e 616
bc2cef1e
SL
617 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
618 iov = uio->uio_iov;
619 if (uio->uio_offset > RAM_SIZE)
620 return (ENODEV);
621 if (uio->uio_offset + iov->iov_len > RAM_SIZE)
622 iov->iov_len = RAM_SIZE - uio->uio_offset;
7779e59b
SL
623 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
624 return (EFAULT);
9d61b7ff
SL
625 enpcopy((u_char *)iov->iov_base,
626 (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
bc2cef1e
SL
627 uio->uio_resid -= iov->iov_len;
628 iov->iov_len = 0;
629 return (0);
630}
631
9d61b7ff 632/*ARGSUSED*/
bc2cef1e
SL
633enpr_ioctl(dev, cmd, data)
634 dev_t dev;
635 caddr_t data;
6013a59e 636{
bc2cef1e 637 register unit = ENPUNIT(dev);
7779e59b 638 struct enpdevice *addr;
6013a59e 639
bc2cef1e
SL
640 addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
641 switch(cmd) {
642
643 case ENPIOGO:
7779e59b 644 ENPSETLONG(&addr->enp_base, addr);
bc2cef1e
SL
645 addr->enp_intrvec = enp_softc[unit].es_ivec;
646 ENP_GO(addr, ENPSTART);
647 DELAY(200000);
648 enpinit(unit);
7779e59b
SL
649 /*
650 * Fetch Ethernet address after link level
651 * is booted (firmware copies manufacturer's
652 * address from on-board ROM).
653 */
654 enpgetaddr(unit, addr);
655 addr->enp_state = S_ENPRUN;
bc2cef1e
SL
656 break;
657
658 case ENPIORESET:
659 RESET_ENP(addr);
7779e59b 660 addr->enp_state = S_ENPRESET;
bc2cef1e
SL
661 DELAY(100000);
662 break;
7779e59b
SL
663 default:
664 return (EINVAL);
6013a59e 665 }
bc2cef1e 666 return (0);
6013a59e
SL
667}
668#endif