|
|
1.1 ! root 1: #include "ec.h" ! 2: #if NEC > 0 ! 3: ! 4: ! 5: #include "../h/param.h" ! 6: #include "../h/systm.h" ! 7: #include "../h/pte.h" ! 8: #include "../h/map.h" ! 9: #include "../h/buf.h" ! 10: #include "../h/ubareg.h" ! 11: #include "../h/ubavar.h" ! 12: #include "../h/conf.h" ! 13: #include "../h/ioctl.h" ! 14: #include "../h/ttyld.h" ! 15: #include "../h/stream.h" ! 16: #include "../h/ethernet.h" ! 17: #include "sparam.h" ! 18: ! 19: extern char ECmem[]; /* .set in locore.s */ ! 20: #define ECADDR ((caddr_t)(ECmem)) /* Virt addr of EC buffer mem */ ! 21: ! 22: /* NOTE: The ECRHBF/ECRLBF/ECTBF definitions must match the address ! 23: and size of EC memory as defined in locore.s in the kernel. ! 24: If locore maps in full 32K, then use all buffers, otherwise, ! 25: change accordingly. ! 26: */ ! 27: ! 28: #define ENETDOWN ENODEV ! 29: #define ECRHBF 11 ! 30: #define ECRLBF 1 ! 31: #define ECTBF 0 ! 32: ! 33: /* Following ethernet address only has meaning if UE prom is missing */ ! 34: ! 35: #define ECPRI (PZERO+8) ! 36: #define ECBFSZ 2048 /* Size of each EC buffer */ ! 37: ! 38: struct ecdevice { ! 39: short ecrcr; /* Transmit Control Register */ ! 40: short ecxcr; /* Receive Control Register */ ! 41: }; ! 42: ! 43: /* Bits in ecxcr: */ ! 44: #define EC_WBN 0x0010 /* Write Buffer Number */ ! 45: #define EC_CLRDN 0x0020 /* Clear Done */ ! 46: #define EC_IE 0x0040 /* Interrupt Enable */ ! 47: #define EC_DONE 0x0080 /* Xmt/Rcv complete */ ! 48: #define EC_CLR 0x0100 /* Clear EC */ ! 49: #define EC_CLRJAM 0x2000 /* Clear Jam */ ! 50: #define EC_JIE 0x4000 /* Jam Interrupt Enable */ ! 51: #define EC_JAM 0x8000 /* Jam */ ! 52: ! 53: /* Bits WBN, CLRDN, IE, and DONE are also used for ecrcr */ ! 54: #define EC_BITS "\20\20JAM\17JIE\16CLRJAM\11CLR\10DONE\7IE\6CLRDN\5WBN" ! 55: ! 56: /* Bits in ecrcr: */ ! 57: #define EC_RANDATA 0xA00 /* Alternating 1/0 in 4 data bits */ ! 58: #define EC_ADATAMSK 0xF00 /* Mask for 4 data bits */ ! 59: #define EC_OWN_BDCST 0x600 /* Recog addrs for me + broadcast*/ ! 60: #define EC_ARALL 0 /* Pass all addresses */ ! 61: #define EC_AWCLK 0x1000 /* Clock data into address recog ram */ ! 62: #define EC_AROM 0x2000 /* Select rom vs default ram */ ! 63: #define EC_ASTEP 0x4000 /* Step rom/ram address one bit */ ! 64: ! 65: ! 66: /* ! 67: * Useful combinations ! 68: */ ! 69: #define EC_READ (EC_OWN_BDCST|EC_IE|EC_WBN) ! 70: #define EC_WRITE (EC_JIE|EC_IE|EC_WBN) ! 71: #define EC_CLEAR (EC_JIE|EC_IE|EC_CLRJAM) ! 72: ! 73: #define ECXBUSY 010 ! 74: #define ECDEBUG 0200 ! 75: ! 76: /* corresponds to minor device numbers (# of servers) */ ! 77: #define CHANS_PER_UNIT 8 ! 78: ! 79: struct ec { /* per controller */ ! 80: char myethadr[6]; /* My Ethernet address */ ! 81: char attached; /* Non zero when ec has been attached */ ! 82: char active; ! 83: short collisions; /* Jam counter */ ! 84: int state; /* Device state */ ! 85: int bits; ! 86: int ierrors, oerrors; ! 87: int ipackets, opackets; ! 88: } ec[NEC] = { {0x02, 0x60, 0x8c, 0x00, 0x4, 0x62}, }; ! 89: ! 90: #define NECCHAN (CHANS_PER_UNIT * NEC) ! 91: struct ecchan { ! 92: int unit; ! 93: int packets; ! 94: struct queue *ecq; ! 95: int type; ! 96: } ecchan[NECCHAN]; ! 97: ! 98: int nodev(), ecopen(), ecclose(), ecput(), ecsrv(); ! 99: static struct qinit ecrinit = { nodev, NULL, ecopen, ecclose, 0, 0 }; ! 100: static struct qinit ecwinit = { ecput, NULL, ecopen, ecclose, 1514, 0 }; ! 101: /* 1514 bytes is minimum highwater mark to send 1514 byte packets */ ! 102: struct streamtab ecsinfo = { &ecrinit, &ecwinit }; ! 103: ! 104: /* JUNK FOR AUTOCONFIGURE */ ! 105: struct uba_device *ecinfo[1]; ! 106: int ecprobe(), ecattach(); ! 107: u_short ecstd[] = { 0 }; ! 108: struct uba_driver ecdriver = ! 109: { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo }; ! 110: extern bsize[]; ! 111: ! 112: ecprobe(reg) ! 113: caddr_t reg; ! 114: { ! 115: register int br, cvec; /* value-result */ ! 116: br = 0x16; /* BR Level 16 = UNIBUS 6 */ ! 117: cvec = 0440; /* Int vector */ ! 118: return 1; ! 119: } ! 120: ! 121: /* ARGSUSED */ ! 122: ecattach(ui) ! 123: struct uba_device *ui; ! 124: { ! 125: register struct ecdevice *ecaddr = (struct ecdevice *)ui->ui_addr; ! 126: register struct ec *ecu = &ec[ui->ui_unit]; ! 127: unsigned short s0, s1; ! 128: register i, j; ! 129: register char *cp; ! 130: char bdethadr[6]; /* copy of bd rom; -1=>chip missing */ ! 131: ! 132: ! 133: if(ecu->attached) /* Do this only once */ ! 134: return; ! 135: ecaddr->ecxcr = EC_CLR; /* Reset the EC */ ! 136: ! 137: /* Fetch out the ROM ethernet address into tmp ethadr */ ! 138: ! 139: ecaddr->ecrcr = EC_AROM; /* Select the ROM */ ! 140: cp = bdethadr; ! 141: for(i = 0; i < 6; i++) { ! 142: *cp = 0; ! 143: for(j = 0; j <= 4; j += 4) { ! 144: s1 = ecaddr->ecrcr; ! 145: *cp |= ((s1 >> 8) & 017) << j; ! 146: for(s1 = 0; s1 < 4; s1++) { ! 147: ecaddr->ecrcr = EC_ASTEP+EC_AROM; ! 148: ecaddr->ecrcr = EC_AROM; ! 149: } ! 150: } ! 151: cp++; ! 152: } ! 153: for(i = 0, cp = bdethadr; i < 6; i++) ! 154: if(*cp++ != -1) { /* Rom is good if not -1 */ ! 155: for(i = 0; i < 6; i++) ! 156: ecu->myethadr[i] = bdethadr[i]; ! 157: } ! 158: /* use the RAM for addr recog */ ! 159: laddrec(ui); ! 160: ! 161: for(i = ECRHBF; i >= ECRLBF; i--) ! 162: ecaddr->ecrcr = EC_READ + i; ! 163: ecsrand((long)ecu->myethadr[5]); ! 164: ecu->attached = 1; ! 165: ecu->bits = EC_READ; ! 166: } ! 167: ! 168: laddrec(ui) ! 169: struct uba_device *ui; ! 170: { ! 171: register struct ecdevice *ecaddr = (struct ecdevice *)ui->ui_addr; ! 172: register struct ec *ecu = &ec[ui->ui_unit]; ! 173: register i, j, s0, s1; ! 174: register char *cp; ! 175: ! 176: /* Have to load myethadr into hardware ram! */ ! 177: ecaddr->ecxcr = EC_CLR; /* Reset bit ptr */ ! 178: for(i = 0, cp = ecu->myethadr; i < 6; i++, cp++) ! 179: for(j = 0; j <= 4; j += 4) { ! 180: s1 = ((*cp >> j) & 017) << 8; ! 181: ecaddr->ecrcr = s1; ! 182: ecaddr->ecrcr = s1 | EC_AWCLK; ! 183: ecaddr->ecrcr = s1; ! 184: for(s0 = 0; s0 < 4; s0++) { ! 185: ecaddr->ecrcr = EC_ASTEP; ! 186: ecaddr->ecrcr = 0; ! 187: } ! 188: } ! 189: } ! 190: ! 191: ! 192: /* ARGSUSED */ ! 193: ecopen(q, dev) ! 194: register struct queue *q; ! 195: register dev_t dev; ! 196: { ! 197: register struct ecchan *ecd; ! 198: register struct ec *ecu; ! 199: register unit; ! 200: ! 201: dev = minor(dev); ! 202: unit = dev / CHANS_PER_UNIT; ! 203: ! 204: if (dev >= NECCHAN) ! 205: return(0); ! 206: if (unit >= NEC) ! 207: return(0); ! 208: ! 209: ecu = &ec[unit]; ! 210: if(!ecu->attached) ! 211: return(0); ! 212: ecd = &ecchan[dev]; ! 213: if (ecd->ecq) ! 214: return(0); ! 215: ! 216: ecd->unit = unit; ! 217: ecd->ecq = q; ! 218: q->ptr = (caddr_t)ecd; ! 219: q->flag |= QBIGB | QDELIM; ! 220: WR(q)->ptr = (caddr_t)ecd; ! 221: WR(q)->flag |= QBIGB|QDELIM; ! 222: ! 223: if (ecu->state & ECDEBUG) ! 224: printf("ECo%d, ", minor(dev)); ! 225: return(1); ! 226: } ! 227: ecclose(q) ! 228: register struct queue *q; ! 229: { ! 230: register struct ecchan *ecd; ! 231: register struct ec *ecu; ! 232: register unit; ! 233: ! 234: ecd = (struct ecchan *)q->ptr; ! 235: ecu = &ec[ecd->unit]; ! 236: if (ecu->state & ECDEBUG) ! 237: printf("ECc\n"); ! 238: flushq(WR(q), 1); ! 239: ecd->ecq = NULL; ! 240: } ! 241: ! 242: ecput(q, bp) ! 243: register struct queue *q; ! 244: register struct block *bp; ! 245: { ! 246: register struct ecchan *ecd; ! 247: register struct ec *ecu; ! 248: register unit, type, count, ps; ! 249: ! 250: ecd = (struct ecchan *)q->ptr; ! 251: unit = ecd->unit; ! 252: ecu = &ec[unit]; ! 253: ! 254: switch(bp->type) { ! 255: ! 256: case M_IOCTL: ! 257: ecioctl(q, bp); ! 258: return; ! 259: ! 260: case M_DATA: ! 261: putq(q, bp); ! 262: return; ! 263: ! 264: case M_DELIM: ! 265: break; ! 266: ! 267: default: ! 268: freeb(bp); ! 269: return; ! 270: } ! 271: ! 272: putq(q, bp); ! 273: ps = spl6(); ! 274: ecd->packets++; ! 275: if (ecu->active == 0) ! 276: ecstart(unit); ! 277: splx(ps); ! 278: } ! 279: ecstart(unit) ! 280: { ! 281: register u_char *tsp, *fsp; ! 282: register struct ec *ecu; ! 283: register struct ecchan *ecd; ! 284: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 285: register struct queue *q, *bq; ! 286: register struct block *bp, *head, *nbp, **bnext; ! 287: register len, count = 0, i; ! 288: ! 289: ecu = &ec[unit]; ! 290: if (ecu->active) { ! 291: printf(" start but active %d\n", unit); ! 292: ecu->active = 0; ! 293: } ! 294: ecd = &ecchan[unit * CHANS_PER_UNIT]; ! 295: for(i = 0; i < CHANS_PER_UNIT; i++, ecd++) ! 296: if (ecd->ecq && ecd->packets > 0) ! 297: break; ! 298: if (i >= CHANS_PER_UNIT) ! 299: return; ! 300: ! 301: ecd->packets--; ! 302: q = WR(ecd->ecq); ! 303: ! 304: /* The packet must be justified to the end of the buffer. ! 305: * Therefore, we have to count the bytes before copying. ! 306: */ ! 307: bnext = &head; ! 308: while (*bnext = bp = getq(q)) { ! 309: if (bp->type == M_DELIM) { ! 310: bp->next = 0; ! 311: break; ! 312: } ! 313: count += bp->wptr - bp->rptr; ! 314: bnext = &bp->next; ! 315: } ! 316: bp = head; ! 317: ! 318: /* if there is no ethernet header in packet, throw it out */ ! 319: if (count < sizeof(struct ether_out)) { ! 320: while(bp) { ! 321: nbp = bp->next; ! 322: freeb(bp); ! 323: bp = nbp; ! 324: } ! 325: return; ! 326: } ! 327: ecu->active = 1; ! 328: ! 329: /* test for small packets */ ! 330: if (count < 46 + sizeof(struct ether_out)) ! 331: count = 46 + sizeof(struct ether_out); ! 332: ! 333: /* test for too large packets */ ! 334: else if (count > 1500 + sizeof(struct ether_out)) ! 335: count = 1500 + sizeof(struct ether_out); ! 336: ! 337: /* Fill buffer - packet is justified to end of buffer. */ ! 338: tsp = (u_char *)(ECmem+(ECBFSZ*ECTBF)); ! 339: *(short *)tsp = (ECBFSZ) - count; /* Stuff offset into buffer */ ! 340: tsp += ((ECBFSZ) - count); /* Adjust ptr into buffer */ ! 341: ! 342: while (count > 0 && bp != 0) { ! 343: len = bp->wptr - bp->rptr; ! 344: fsp = bp->rptr; ! 345: count -= len; ! 346: while (len-- > 0) /* Could this use scopy()? */ ! 347: *tsp++ = *fsp++; ! 348: nbp = bp->next; ! 349: freeb(bp); ! 350: bp = nbp; ! 351: } ! 352: ! 353: /* if no buffers left but count > 0, (i.e. padded packet), zero fill */ ! 354: while (count-- > 0) ! 355: *tsp++ = 0; ! 356: ! 357: /* flush remaining buffers, if any (too large packet: count > 1500) */ ! 358: while (bp) { ! 359: nbp = bp->next; ! 360: freeb(bp); ! 361: bp = nbp; ! 362: } ! 363: ! 364: if (ecu->state & ECDEBUG) { ! 365: register i; ! 366: printf("\ncount=%d, packet = ", count); ! 367: tsp = (u_char *)(ECmem+(ECBFSZ*ECTBF)) + (ECBFSZ - count); ! 368: for(i = 0; i < count; i++) ! 369: printf("%02x ", (unsigned int)*tsp++); ! 370: printf("\n"); ! 371: } ! 372: ecu->state |= ECXBUSY; ! 373: ecu->collisions = 0; ! 374: ecaddr->ecxcr = EC_WRITE + ECTBF; ! 375: } ! 376: ! 377: ecioctl(q, bp) ! 378: register struct queue *q; ! 379: register struct block *bp; ! 380: { ! 381: #ifndef EIOCSETP ! 382: #define EIOCSETP (('e'<<8)|3) /* set ec_state (state of driver) */ ! 383: #define EIOCGETP (('e'<<8)|4) /* get ec_state (driver state) */ ! 384: #define EIOCAREC (('e'<<8)|5) /* set address recognition */ ! 385: #endif ! 386: register struct ecdevice *ecaddr; ! 387: register struct ecchan *ecd; ! 388: register struct ec *ecu; ! 389: register u_char *msg; ! 390: register unit, i, ps, cmd; ! 391: ! 392: ecd = (struct ecchan *)q->ptr; ! 393: unit = ecd->unit; ! 394: ecu = &ec[unit]; ! 395: ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 396: cmd = ((union stmsg *)(bp->rptr))->ioc1.com; ! 397: msg = (u_char *)&((union stmsg *)(bp->rptr))->ioc1.sb; ! 398: ! 399: bp->type = M_IOCACK; ! 400: if (ecu->state & ECDEBUG) ! 401: printf("ecioctl: cmd = %x\n"); ! 402: switch(cmd) { ! 403: case ENIOADDR: /* get my Ethernet address */ ! 404: bcopy(ecu->myethadr, (int *)msg, 6); ! 405: break; ! 406: ! 407: /* ! 408: * SETP, SETD, SSIG, AREC should be super user ioctl calls. ! 409: * Since it is impossible to know who the initiator of an ioctl call is, ! 410: * it would be desirable to have a special minor device number for super user ! 411: * privileges ! 412: */ ! 413: case EIOCSETP: ! 414: case EIOCGETP: ! 415: if (cmd == EIOCGETP) { ! 416: *(int *)msg = ecu->state; ! 417: } else { ! 418: ecu->state = *(int *)msg; ! 419: } ! 420: if (ecu->state & ECDEBUG) ! 421: printf("state = %o\n", ecu->state); ! 422: break; ! 423: ! 424: case ENIOTYPE: ! 425: ecd->type = *(int *)msg; ! 426: break; ! 427: ! 428: case EIOCAREC: ! 429: ecu->bits = *(int *)msg; ! 430: ecu->bits |= EC_IE|EC_WBN; ! 431: if (ecu->state & ECDEBUG) ! 432: printf("set addr rec, bits = %b\n", ecu->bits, EC_BITS); ! 433: ps = spl6(); ! 434: ecaddr->ecxcr = EC_CLR; /* Reset the UE */ ! 435: for(i = ECRHBF; i >= ECRLBF; i--) ! 436: ecaddr->ecrcr = ecu->bits + i; ! 437: splx(ps); ! 438: break; ! 439: ! 440: default: ! 441: bp->type = M_IOCNAK; ! 442: break; ! 443: } ! 444: qreply(q, bp); ! 445: } ! 446: ! 447: ! 448: /* Come here only after hardware has decided packet is for us-- ! 449: either exactly, or multi-cast */ ! 450: ecrint(unit) ! 451: { ! 452: register struct ecchan *ecd; ! 453: register struct ec *ecu = &ec[unit]; ! 454: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 455: register struct queue *q; ! 456: register struct block *bp; ! 457: register short buf; /* Extract done rcv buffer */ ! 458: register short type; ! 459: register short *fsp; ! 460: register len, min, i; ! 461: register u_char *p; ! 462: ! 463: while (ecaddr->ecrcr & EC_DONE) { ! 464: buf = ecaddr->ecrcr & 0xF; /* Extract buffer # */ ! 465: if (buf < ECRLBF || buf > ECRHBF) ! 466: panic("ec%d: rcvr interrupt (bad buf=%d)\n", unit, buf); ! 467: ! 468: /* fsp points to the buffer in VAX virt memory */ ! 469: ! 470: fsp = (short *)(ECmem+(ECBFSZ*buf)); ! 471: if (*fsp < 0) { /* negative offset => FCS err */ ! 472: ecu->ierrors++; ! 473: goto out; ! 474: } ! 475: if (((*fsp) & 0x3fff) == 0) { /* 0 offset => TOO LONG pkt */ ! 476: ecu->ierrors++; ! 477: goto out; ! 478: } ! 479: /* *fsp contains offset to end of packet - ie (length + beginning offset); ! 480: packet starts at offset 528 into the buffer */ ! 481: ! 482: if (*fsp < 592 || *fsp > 2046) { /* illegal count */ ! 483: ecu->ierrors++; ! 484: goto out; ! 485: } ! 486: len = *fsp - (528+4); /* +4 is the FCS */ ! 487: fsp = fsp + (528/2); /* Offset of beg of packet */ ! 488: type = *(fsp + 6); ! 489: p = (u_char *)fsp; ! 490: ! 491: ecd = &ecchan[unit * CHANS_PER_UNIT]; ! 492: for (i = 0; i < CHANS_PER_UNIT; i++, ecd++) ! 493: if (ecd->ecq && ecd->type == type) ! 494: break; ! 495: if (i >= CHANS_PER_UNIT) ! 496: goto out; ! 497: q = ecd->ecq; ! 498: if (q->next->flag & QFULL) { ! 499: if(ecu->state & ECDEBUG) ! 500: printf(" q full\n"); ! 501: ecu->ierrors++; ! 502: goto out; ! 503: } ! 504: while (len > 0) { ! 505: bp = allocb(len); ! 506: if (bp == 0) { ! 507: printf("ecrint no buffers\n"); ! 508: goto out; ! 509: } ! 510: min = MIN((bp->lim - bp->base), len); ! 511: len -= min; ! 512: while (min-- > 0) ! 513: *bp->wptr++ = *p++; ! 514: (*q->next->qinfo->putp)(q->next, bp); ! 515: } ! 516: if (putctl(q->next, M_DELIM)) ! 517: ecu->ipackets++; ! 518: else ! 519: printf("ecrint no DELIM bp\n"); ! 520: out: ! 521: ecaddr->ecrcr = ecu->bits | EC_CLRDN | buf; ! 522: } ! 523: } ! 524: ! 525: ecjint(unit) ! 526: { ! 527: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 528: register struct ec *ecu = &ec[unit]; ! 529: register i; ! 530: ! 531: if(++ecu->collisions > 8) { ! 532: printf("ec gak\n"); ! 533: ecu->oerrors++; ! 534: /* Hmmm, can't xmit in 8 tries */ ! 535: ecaddr->ecxcr = EC_CLR; /* Reset the UE */ ! 536: /* And re-read all rcv buffers */ ! 537: for(i = ECRHBF; i >= ECRLBF; i--) ! 538: ecaddr->ecrcr = ecu->bits + i; ! 539: ecu->state &= ~ECXBUSY; ! 540: } else { ! 541: ecu->collisions++; ! 542: backoff(ecu->collisions); ! 543: ecaddr->ecxcr = EC_CLEAR; /* RESET */ ! 544: } ! 545: } ! 546: ! 547: ! 548: /* backoff: this routine implements an approximation of the binary ! 549: * exponential backoff algorithm. When called with an argument n, ! 550: * the retry number, this routine will delay (in a busy loop) ! 551: * a random amount of time between 0 and 2**n slot times. A slot ! 552: * time is defined as 51.2 microseconds. This routine assumes it ! 553: * takes about 300 microseconds to be called after the jam actually ! 554: * occurs, and that the random number generator takes about 50 ! 555: * microseconds. ! 556: */ ! 557: backoff(n) ! 558: register int n; ! 559: { ! 560: long ecrand(); ! 561: register int time; ! 562: ! 563: if (n < 4) ! 564: return; ! 565: if (n > 10) ! 566: n = 10; ! 567: ! 568: /* compute number of slot times to delay */ ! 569: time = ((int)ecrand() & ((1 << n) - 1)) - 7; ! 570: if (time <= 0) ! 571: return; ! 572: ! 573: while(time--) ! 574: ecidle(); ! 575: } ! 576: ! 577: static long randx = 1; ! 578: ! 579: ecsrand(x) ! 580: unsigned x; ! 581: { ! 582: randx = x; ! 583: } ! 584: ! 585: ecrand() ! 586: { ! 587: return(((randx = randx*1103515245 + 12345)>>16) & 077777); ! 588: } ! 589: ! 590: ! 591: ecidle() ! 592: { ! 593: register i = 40; ! 594: ! 595: while(--i) ; ! 596: } ! 597: ! 598: /* ! 599: * ecxint gets called when a transmit completes normally. ! 600: */ ! 601: ecxint(unit) ! 602: { ! 603: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 604: register struct ec *ecu; ! 605: register struct ecchan *ecd; ! 606: register struct block *bp; ! 607: register buf = ecaddr->ecxcr & 0xF; ! 608: ! 609: if((ecaddr->ecxcr & EC_DONE) == 0 || buf != ECTBF) ! 610: printf("ec%d: xmit interrupt-bad bufno, xcsr=%b\n", unit, ecaddr->ecxcr, EC_BITS); ! 611: ! 612: ecu = &ec[unit]; ! 613: if(ecu->active == 0) { ! 614: printf("ec%d: stray xmit interrupt, xcsr=%b\n", unit, ecaddr->ecxcr, EC_BITS); ! 615: return; ! 616: } ! 617: ! 618: ecaddr->ecxcr = EC_CLRDN; ! 619: ecu->state &= ~ECXBUSY; ! 620: ecu->active = 0; ! 621: ecu->opackets++; ! 622: ecstart(unit); ! 623: } ! 624: scopy(f, t, c) ! 625: register u_char *f, *t; ! 626: register c; ! 627: { ! 628: while(c-- > 0) ! 629: *t++ = *f++; ! 630: } ! 631: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.