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