1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)if_enp.c 7.2 (Berkeley) 06/29/88 18 */ 19 20 #include "enp.h" 21 #if NENP > 0 22 /* 23 * CMC ENP-20 Ethernet Controller. 24 */ 25 #include "param.h" 26 #include "systm.h" 27 #include "mbuf.h" 28 #include "buf.h" 29 #include "protosw.h" 30 #include "socket.h" 31 #include "vmmac.h" 32 #include "ioctl.h" 33 #include "errno.h" 34 #include "vmparam.h" 35 #include "syslog.h" 36 #include "uio.h" 37 38 #include "../net/if.h" 39 #include "../net/netisr.h" 40 #include "../net/route.h" 41 #ifdef INET 42 #include "../netinet/in.h" 43 #include "../netinet/in_systm.h" 44 #include "../netinet/in_var.h" 45 #include "../netinet/ip.h" 46 #include "../netinet/ip_var.h" 47 #include "../netinet/if_ether.h" 48 #endif 49 #ifdef NS 50 #include "../netns/ns.h" 51 #include "../netns/ns_if.h" 52 #endif 53 54 #include "../tahoe/cpu.h" 55 #include "../tahoe/pte.h" 56 #include "../tahoe/mtpr.h" 57 58 #include "../tahoevba/vbavar.h" 59 #include "../tahoeif/if_enpreg.h" 60 61 #define ENPSTART 0xf02000 /* standard enp start addr */ 62 #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 63 /* macros for dealing with longs in i/o space */ 64 #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 65 #define ENPSETLONG(a,v) \ 66 { register u_short *wp = (u_short *)(a); \ 67 wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 68 69 int enpprobe(), enpattach(), enpintr(); 70 long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 71 struct vba_device *enpinfo[NENP]; 72 struct vba_driver enpdriver = 73 { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 74 75 int enpinit(), enpioctl(), enpreset(), enpoutput(); 76 struct mbuf *enpget(); 77 78 /* 79 * Ethernet software status per interface. 80 * 81 * Each interface is referenced by a network interface structure, 82 * es_if, which the routing code uses to locate the interface. 83 * This structure contains the output queue for the interface, its address, ... 84 */ 85 struct enp_softc { 86 struct arpcom es_ac; /* common ethernet structures */ 87 #define es_if es_ac.ac_if 88 #define es_addr es_ac.ac_enaddr 89 short es_ivec; /* interrupt vector */ 90 } enp_softc[NENP]; 91 extern struct ifnet loif; 92 93 enpprobe(reg, vi) 94 caddr_t reg; 95 struct vba_device *vi; 96 { 97 register br, cvec; /* must be r12, r11 */ 98 register struct enpdevice *addr = (struct enpdevice *)reg; 99 struct enp_softc *es = &enp_softc[vi->ui_unit]; 100 101 #ifdef lint 102 br = 0; cvec = br; br = cvec; 103 enpintr(0); 104 #endif 105 if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 106 return (0); 107 es->es_ivec = --vi->ui_hd->vh_lastiv; 108 addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 109 br = 0x14, cvec = es->es_ivec; /* XXX */ 110 return (sizeof (struct enpdevice)); 111 } 112 113 /* 114 * Interface exists: make available by filling in network interface 115 * record. System will initialize the interface when it is ready 116 * to accept packets. 117 */ 118 enpattach(ui) 119 register struct vba_device *ui; 120 { 121 struct enp_softc *es = &enp_softc[ui->ui_unit]; 122 register struct ifnet *ifp = &es->es_if; 123 124 ifp->if_unit = ui->ui_unit; 125 ifp->if_name = "enp"; 126 ifp->if_mtu = ETHERMTU; 127 ifp->if_init = enpinit; 128 ifp->if_ioctl = enpioctl; 129 ifp->if_output = enpoutput; 130 ifp->if_reset = enpreset; 131 ifp->if_flags = IFF_BROADCAST; 132 if_attach(ifp); 133 } 134 135 /* 136 * Reset of interface after "system" reset. 137 */ 138 enpreset(unit, vban) 139 int unit, vban; 140 { 141 register struct vba_device *ui; 142 143 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 144 ui->ui_vbanum != vban) 145 return; 146 printf(" enp%d", unit); 147 enpinit(unit); 148 } 149 150 /* 151 * Initialization of interface; clear recorded pending operations. 152 */ 153 enpinit(unit) 154 int unit; 155 { 156 struct enp_softc *es = &enp_softc[unit]; 157 register struct vba_device *ui = enpinfo[unit]; 158 struct enpdevice *addr; 159 register struct ifnet *ifp = &es->es_if; 160 int s; 161 162 if (ifp->if_addrlist == (struct ifaddr *)0) 163 return; 164 if ((ifp->if_flags & IFF_RUNNING) == 0) { 165 addr = (struct enpdevice *)ui->ui_addr; 166 s = splimp(); 167 RESET_ENP(addr); 168 DELAY(200000); 169 es->es_if.if_flags |= IFF_RUNNING; 170 splx(s); 171 } 172 } 173 174 /* 175 * Ethernet interface interrupt. 176 */ 177 enpintr(unit) 178 int unit; 179 { 180 register struct enpdevice *addr; 181 register BCB *bcbp; 182 183 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 184 #if ENP == 30 185 if (!IS_ENP_INTR(addr)) 186 return; 187 ACK_ENP_INTR(addr); 188 #endif 189 while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 190 (void) enpread(&enp_softc[unit], bcbp); 191 (void) ringput((RING *)&addr->enp_enpfree, bcbp); 192 } 193 } 194 195 /* 196 * Read input packet, examine its packet type, and enqueue it. 197 */ 198 enpread(es, bcbp) 199 struct enp_softc *es; 200 register BCB *bcbp; 201 { 202 register struct ether_header *enp; 203 struct mbuf *m; 204 int s, len, off, resid; 205 register struct ifqueue *inq; 206 207 es->es_if.if_ipackets++; 208 /* 209 * Get input data length. 210 * Get pointer to ethernet header (in input buffer). 211 * Deal with trailer protocol: if type is PUP trailer 212 * get true type from first 16-bit word past data. 213 * Remember that type was trailer by setting off. 214 */ 215 len = bcbp->b_msglen - sizeof (struct ether_header); 216 enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 217 #define enpdataaddr(enp, off, type) \ 218 ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 219 enp->ether_type = ntohs((u_short)enp->ether_type); 220 if (enp->ether_type >= ETHERTYPE_TRAIL && 221 enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 222 off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 223 if (off >= ETHERMTU) 224 goto setup; 225 enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 226 resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 227 if (off + resid > len) 228 goto setup; 229 len = off + resid; 230 } else 231 off = 0; 232 if (len == 0) 233 goto setup; 234 235 /* 236 * Pull packet off interface. Off is nonzero if packet 237 * has trailing header; enpget will then force this header 238 * information to be at the front, but we still have to drop 239 * the type and length which are at the front of any trailer data. 240 */ 241 m = enpget((u_char *)enp, len, off, &es->es_if); 242 if (m == 0) 243 goto setup; 244 if (off) { 245 struct ifnet *ifp; 246 247 ifp = *(mtod(m, struct ifnet **)); 248 m->m_off += 2 * sizeof (u_short); 249 m->m_len -= 2 * sizeof (u_short); 250 *(mtod(m, struct ifnet **)) = ifp; 251 } 252 switch (enp->ether_type) { 253 254 #ifdef INET 255 case ETHERTYPE_IP: 256 schednetisr(NETISR_IP); 257 inq = &ipintrq; 258 break; 259 #endif 260 case ETHERTYPE_ARP: 261 arpinput(&es->es_ac, m); 262 goto setup; 263 264 #ifdef NS 265 case ETHERTYPE_NS: 266 schednetisr(NETISR_NS); 267 inq = &nsintrq; 268 break; 269 #endif 270 default: 271 m_freem(m); 272 goto setup; 273 } 274 if (IF_QFULL(inq)) { 275 IF_DROP(inq); 276 m_freem(m); 277 goto setup; 278 } 279 s = splimp(); 280 IF_ENQUEUE(inq, m); 281 splx(s); 282 setup: 283 return (0); 284 } 285 286 /* 287 * Ethernet output routine. (called by user) 288 * Encapsulate a packet of type family for the local net. 289 * Use trailer local net encapsulation if enough data in first 290 * packet leaves a multiple of 512 bytes of data in remainder. 291 * If destination is this address or broadcast, send packet to 292 * loop device to kludge around the fact that 3com interfaces can't 293 * talk to themselves. 294 */ 295 enpoutput(ifp, m0, dst) 296 struct ifnet *ifp; 297 struct mbuf *m0; 298 struct sockaddr *dst; 299 { 300 register struct enp_softc *es = &enp_softc[ifp->if_unit]; 301 register struct mbuf *m = m0; 302 register struct ether_header *enp; 303 register int off; 304 struct mbuf *mcopy = (struct mbuf *)0; 305 int type, s, error, usetrailers; 306 u_char edst[6]; 307 struct in_addr idst; 308 309 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 310 error = ENETDOWN; 311 goto bad; 312 } 313 switch (dst->sa_family) { 314 #ifdef INET 315 case AF_INET: 316 idst = ((struct sockaddr_in *)dst)->sin_addr; 317 if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) 318 return (0); /* if not yet resolved */ 319 if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 320 sizeof (edst))) 321 mcopy = m_copy(m, 0, (int)M_COPYALL); 322 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 323 if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 324 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 325 type = ETHERTYPE_TRAIL + (off>>9); 326 m->m_off -= 2 * sizeof (u_short); 327 m->m_len += 2 * sizeof (u_short); 328 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 329 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 330 goto gottrailertype; 331 } 332 type = ETHERTYPE_IP; 333 off = 0; 334 goto gottype; 335 #endif 336 #ifdef NS 337 case AF_NS: 338 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 339 (caddr_t)edst, sizeof (edst)); 340 if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst))) 341 mcopy = m_copy(m, 0, (int)M_COPYALL); 342 else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 343 sizeof (edst))) 344 return (looutput(&loif, m, dst)); 345 type = ETHERTYPE_NS; 346 off = 0; 347 goto gottype; 348 #endif 349 case AF_UNSPEC: 350 enp = (struct ether_header *)dst->sa_data; 351 bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst)); 352 type = enp->ether_type; 353 goto gottype; 354 355 default: 356 log(LOG_ERR, "enp%d: can't handle af%d\n", 357 ifp->if_unit, dst->sa_family); 358 error = EAFNOSUPPORT; 359 goto bad; 360 } 361 362 gottrailertype: 363 /* 364 * Packet to be sent as trailer: move first packet 365 * (control information) to end of chain. 366 */ 367 while (m->m_next) 368 m = m->m_next; 369 m->m_next = m0; 370 m = m0->m_next; 371 m0->m_next = 0; 372 m0 = m; 373 374 gottype: 375 /* 376 * Add local net header. If no space in first mbuf, 377 * allocate another. 378 */ 379 if (m->m_off > MMAXOFF || 380 MMINOFF + sizeof (struct ether_header) > m->m_off) { 381 m = m_get(M_DONTWAIT, MT_HEADER); 382 if (m == 0) { 383 error = ENOBUFS; 384 goto bad; 385 } 386 m->m_next = m0; 387 m->m_off = MMINOFF; 388 m->m_len = sizeof (struct ether_header); 389 } else { 390 m->m_off -= sizeof (struct ether_header); 391 m->m_len += sizeof (struct ether_header); 392 } 393 enp = mtod(m, struct ether_header *); 394 bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst)); 395 bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost, 396 sizeof (es->es_addr)); 397 enp->ether_type = htons((u_short)type); 398 399 /* 400 * Queue message on interface if possible 401 */ 402 s = splimp(); 403 if (enpput(ifp->if_unit, m)) { 404 error = ENOBUFS; 405 goto qfull; 406 } 407 splx(s); 408 es->es_if.if_opackets++; 409 return (mcopy ? looutput(&loif, mcopy, dst) : 0); 410 qfull: 411 splx(s); 412 m0 = m; 413 bad: 414 m_freem(m0); 415 if (mcopy) 416 m_freem(mcopy); 417 return (error); 418 } 419 420 /* 421 * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 422 */ 423 enpput(unit, m) 424 int unit; 425 struct mbuf *m; 426 { 427 register BCB *bcbp; 428 register struct enpdevice *addr; 429 register struct mbuf *mp; 430 register u_char *bp; 431 register u_int len; 432 u_char *mcp; 433 434 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 435 if (ringempty((RING *)&addr->enp_hostfree)) 436 return (1); 437 bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 438 bcbp->b_len = 0; 439 bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 440 for (mp = m; mp; mp = mp->m_next) { 441 len = mp->m_len; 442 if (len == 0) 443 continue; 444 mcp = mtod(mp, u_char *); 445 enpcopy(mcp, bp, len); 446 bp += len; 447 bcbp->b_len += len; 448 } 449 bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 450 bcbp->b_reserved = 0; 451 if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 452 INTR_ENP(addr); 453 m_freem(m); 454 return (0); 455 } 456 457 /* 458 * Routine to copy from VERSAbus memory into mbufs. 459 * 460 * Warning: This makes the fairly safe assumption that 461 * mbufs have even lengths. 462 */ 463 struct mbuf * 464 enpget(rxbuf, totlen, off0, ifp) 465 u_char *rxbuf; 466 int totlen, off0; 467 struct ifnet *ifp; 468 { 469 register u_char *cp, *mcp; 470 register struct mbuf *m; 471 struct mbuf *top = 0, **mp = ⊤ 472 int len, off = off0; 473 474 cp = rxbuf + sizeof (struct ether_header); 475 while (totlen > 0) { 476 MGET(m, M_DONTWAIT, MT_DATA); 477 if (m == 0) 478 goto bad; 479 if (off) { 480 len = totlen - off; 481 cp = rxbuf + sizeof (struct ether_header) + off; 482 } else 483 len = totlen; 484 if (len >= NBPG) { 485 MCLGET(m); 486 if (m->m_len == CLBYTES) 487 m->m_len = len = MIN(len, CLBYTES); 488 else 489 m->m_len = len = MIN(MLEN, len); 490 } else { 491 m->m_len = len = MIN(MLEN, len); 492 m->m_off = MMINOFF; 493 } 494 mcp = mtod(m, u_char *); 495 if (ifp) { 496 /* 497 * Prepend interface pointer to first mbuf. 498 */ 499 *(mtod(m, struct ifnet **)) = ifp; 500 mcp += sizeof (ifp); 501 len -= sizeof (ifp); 502 ifp = (struct ifnet *)0; 503 } 504 enpcopy(cp, mcp, (u_int)len); 505 cp += len; 506 *mp = m; 507 mp = &m->m_next; 508 if (off == 0) { 509 totlen -= len; 510 continue; 511 } 512 off += len; 513 if (off == totlen) { 514 cp = rxbuf + sizeof (struct ether_header); 515 off = 0; 516 totlen = off0; 517 } 518 } 519 return (top); 520 bad: 521 m_freem(top); 522 return (0); 523 } 524 525 enpcopy(from, to, cnt) 526 register u_char *from, *to; 527 register u_int cnt; 528 { 529 register c; 530 register short *f, *t; 531 532 if (((int)from&01) && ((int)to&01)) { 533 /* source & dest at odd addresses */ 534 *to++ = *from++; 535 --cnt; 536 } 537 if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 538 t = (short *)to; 539 f = (short *)from; 540 for (c = cnt>>1; c; --c) /* even address copy */ 541 *t++ = *f++; 542 cnt &= 1; 543 if (cnt) { /* odd len */ 544 from = (u_char *)f; 545 to = (u_char *)t; 546 *to = *from; 547 } 548 } 549 while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 550 *to++ = *from++; 551 } 552 553 /* 554 * Process an ioctl request. 555 */ 556 enpioctl(ifp, cmd, data) 557 register struct ifnet *ifp; 558 int cmd; 559 caddr_t data; 560 { 561 register struct ifaddr *ifa = (struct ifaddr *)data; 562 struct enpdevice *addr; 563 int s = splimp(), error = 0; 564 565 switch (cmd) { 566 567 case SIOCSIFADDR: 568 ifp->if_flags |= IFF_UP; 569 switch (ifa->ifa_addr.sa_family) { 570 #ifdef INET 571 case AF_INET: 572 enpinit(ifp->if_unit); 573 ((struct arpcom *)ifp)->ac_ipaddr = 574 IA_SIN(ifa)->sin_addr; 575 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 576 break; 577 #endif 578 #ifdef NS 579 case AF_NS: { 580 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 581 struct enp_softc *es = &enp_softc[ifp->if_unit]; 582 583 if (!ns_nullhost(*ina)) { 584 ifp->if_flags &= ~IFF_RUNNING; 585 addr = (struct enpdevice *) 586 enpinfo[ifp->if_unit]->ui_addr; 587 enpsetaddr(ifp->if_unit, addr, 588 ina->x_host.c_host); 589 } else 590 ina->x_host = *(union ns_host *)es->es_addr; 591 enpinit(ifp->if_unit); 592 break; 593 } 594 #endif 595 default: 596 enpinit(ifp->if_unit); 597 break; 598 } 599 break; 600 601 case SIOCSIFFLAGS: 602 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 603 enpinit(ifp->if_unit); /* reset board */ 604 ifp->if_flags &= ~IFF_RUNNING; 605 } else if (ifp->if_flags&IFF_UP && 606 (ifp->if_flags&IFF_RUNNING) == 0) 607 enpinit(ifp->if_unit); 608 break; 609 610 default: 611 error = EINVAL; 612 } 613 splx(s); 614 return (error); 615 } 616 617 enpsetaddr(unit, addr, enaddr) 618 int unit; 619 struct enpdevice *addr; 620 u_char *enaddr; 621 { 622 623 enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 624 sizeof (struct ether_addr)); 625 enpinit(unit); 626 enpgetaddr(unit, addr); 627 } 628 629 enpgetaddr(unit, addr) 630 int unit; 631 struct enpdevice *addr; 632 { 633 struct enp_softc *es = &enp_softc[unit]; 634 635 enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 636 sizeof (struct ether_addr)); 637 printf("enp%d: hardware address %s\n", 638 unit, ether_sprintf(es->es_addr)); 639 } 640 641 /* 642 * Routines to synchronize enp and host. 643 */ 644 #ifdef notdef 645 static 646 ringinit(rp, size) 647 register RING *rp; 648 { 649 650 rp->r_rdidx = rp->r_wrtidx = 0; 651 rp->r_size = size; 652 } 653 654 static 655 ringfull(rp) 656 register RING *rp; 657 { 658 register short idx; 659 660 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 661 return (idx == rp->r_rdidx); 662 } 663 664 static 665 fir(rp) 666 register RING *rp; 667 { 668 669 return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 670 } 671 #endif 672 673 static 674 ringempty(rp) 675 register RING *rp; 676 { 677 678 return (rp->r_rdidx == rp->r_wrtidx); 679 } 680 681 static 682 ringput(rp, v) 683 register RING *rp; 684 BCB *v; 685 { 686 register int idx; 687 688 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 689 if (idx != rp->r_rdidx) { 690 ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 691 rp->r_wrtidx = idx; 692 if ((idx -= rp->r_rdidx) < 0) 693 idx += rp->r_size; 694 return (idx); /* num ring entries */ 695 } 696 return (0); 697 } 698 699 static 700 ringget(rp) 701 register RING *rp; 702 { 703 register int i = 0; 704 705 if (rp->r_rdidx != rp->r_wrtidx) { 706 i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 707 rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 708 } 709 return (i); 710 } 711 712 /* 713 * ENP Ram device. 714 */ 715 enpr_open(dev) 716 dev_t dev; 717 { 718 register int unit = ENPUNIT(dev); 719 struct vba_device *ui; 720 struct enpdevice *addr; 721 722 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 723 (addr = (struct enpdevice *)ui->ui_addr) == 0) 724 return (ENODEV); 725 if (addr->enp_state != S_ENPRESET) 726 return (EACCES); /* enp is not in reset state, don't open */ 727 return (0); 728 } 729 730 /*ARGSUSED*/ 731 enpr_close(dev) 732 dev_t dev; 733 { 734 735 return (0); 736 } 737 738 enpr_read(dev, uio) 739 dev_t dev; 740 register struct uio *uio; 741 { 742 register struct iovec *iov; 743 struct enpdevice *addr; 744 745 if (uio->uio_offset > RAM_SIZE) 746 return (ENODEV); 747 iov = uio->uio_iov; 748 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 749 iov->iov_len = RAM_SIZE - uio->uio_offset; 750 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 751 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 752 return (EFAULT); 753 enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 754 (u_char *)iov->iov_base, (u_int)iov->iov_len); 755 uio->uio_resid -= iov->iov_len; 756 iov->iov_len = 0; 757 return (0); 758 } 759 760 enpr_write(dev, uio) 761 dev_t dev; 762 register struct uio *uio; 763 { 764 register struct enpdevice *addr; 765 register struct iovec *iov; 766 767 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 768 iov = uio->uio_iov; 769 if (uio->uio_offset > RAM_SIZE) 770 return (ENODEV); 771 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 772 iov->iov_len = RAM_SIZE - uio->uio_offset; 773 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 774 return (EFAULT); 775 enpcopy((u_char *)iov->iov_base, 776 (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 777 uio->uio_resid -= iov->iov_len; 778 iov->iov_len = 0; 779 return (0); 780 } 781 782 /*ARGSUSED*/ 783 enpr_ioctl(dev, cmd, data) 784 dev_t dev; 785 caddr_t data; 786 { 787 register unit = ENPUNIT(dev); 788 struct enpdevice *addr; 789 790 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 791 switch(cmd) { 792 793 case ENPIOGO: 794 ENPSETLONG(&addr->enp_base, addr); 795 addr->enp_intrvec = enp_softc[unit].es_ivec; 796 ENP_GO(addr, ENPSTART); 797 DELAY(200000); 798 enpinit(unit); 799 /* 800 * Fetch Ethernet address after link level 801 * is booted (firmware copies manufacturer's 802 * address from on-board ROM). 803 */ 804 enpgetaddr(unit, addr); 805 addr->enp_state = S_ENPRUN; 806 break; 807 808 case ENPIORESET: 809 RESET_ENP(addr); 810 addr->enp_state = S_ENPRESET; 811 DELAY(100000); 812 break; 813 default: 814 return (EINVAL); 815 } 816 return (0); 817 } 818 #endif 819