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