|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "../port/error.h" ! 7: #include "devtab.h" ! 8: ! 9: #include "io.h" ! 10: #include "ureg.h" ! 11: ! 12: typedef struct Incon Incon; ! 13: typedef struct Device Device; ! 14: ! 15: #define NOW (MACHP(0)->ticks*MS2HZ) ! 16: ! 17: #define MICROSECOND USED(NOW) ! 18: ! 19: #define DPRINT if(0) ! 20: ! 21: enum { ! 22: Minstation= 2, /* lowest station # to poll */ ! 23: Maxstation= 15, /* highest station # to poll */ ! 24: Nincon= 1, /* number of incons */ ! 25: Nin= 32, /* Blocks in the input ring */ ! 26: Bsize= 128, /* size of an input ring block */ ! 27: Mfifo= 0xff, /* a mask, must be 2^n-1, must be > Nin */ ! 28: ! 29: Qstats= 1, /* qid of the statistics file */ ! 30: }; ! 31: ! 32: /* ! 33: * incon datakit board ! 34: */ ! 35: struct Device { ! 36: uchar cdata; ! 37: #define cpolln cdata ! 38: uchar u0; ! 39: uchar cstatus; ! 40: uchar u1; ! 41: uchar creset; ! 42: uchar u2; ! 43: uchar csend; ! 44: uchar u3; ! 45: ushort data_cntl; /* data is high byte, cntl is low byte */ ! 46: uchar status; ! 47: #define cmd status ! 48: uchar u5; ! 49: uchar reset; ! 50: uchar u6; ! 51: uchar send; ! 52: uchar u7; ! 53: }; ! 54: #define INCON ((Device *)0x40700000) ! 55: ! 56: struct Incon { ! 57: QLock; ! 58: ! 59: QLock xmit; /* transmit lock */ ! 60: QLock reslock; /* reset lock */ ! 61: Device *dev; ! 62: int station; /* station number */ ! 63: int state; /* chip state */ ! 64: Rendez r; /* output process */ ! 65: Rendez kr; /* input kernel process */ ! 66: ushort chan; /* current input channel */ ! 67: Queue *rq; /* read queue */ ! 68: int kstarted; /* true if kernel process started */ ! 69: ! 70: /* input blocks */ ! 71: ! 72: Block *inb[Nin]; ! 73: ushort wi; ! 74: ushort ri; ! 75: ! 76: /* statistics */ ! 77: ! 78: ulong overflow; /* overflow errors */ ! 79: ulong pack0; /* channel 0 */ ! 80: ulong crc; /* crc errors */ ! 81: ulong in; /* bytes in */ ! 82: ulong out; /* bytes out */ ! 83: ulong wait; /* wait time in milliseconds */ ! 84: }; ! 85: ! 86: Incon incon[Nincon]; ! 87: ! 88: /* ! 89: * chip state ! 90: */ ! 91: enum { ! 92: Selecting, ! 93: Selected, ! 94: Notliving, ! 95: }; ! 96: ! 97: /* ! 98: * internal chip registers ! 99: */ ! 100: #define sel_polln 0 ! 101: #define sel_station 1 ! 102: #define sel_poll0 2 ! 103: #define sel_rcv_cnt 3 ! 104: #define sel_rcv_tim 4 ! 105: #define sel_tx_cnt 5 ! 106: ! 107: /* ! 108: * CSR bits ! 109: */ ! 110: #define INCON_RUN 0x80 ! 111: #define INCON_STOP 0x00 ! 112: #define ENABLE_IRQ 0x40 ! 113: #define ENABLE_TX_IRQ 0x20 ! 114: #define INCON_ALIVE 0x80 ! 115: #define TX_FULL 0x10 ! 116: #define TX_EMPTY 0x08 ! 117: #define RCV_EMPTY 0x04 ! 118: #define OVERFLOW 0x02 ! 119: #define CRC_ERROR 0x01 ! 120: ! 121: /* ! 122: * polling constants ! 123: */ ! 124: #define HT_GNOT 0x30 ! 125: #define ST_UNIX 0x04 ! 126: #define NCHAN 16 ! 127: ! 128: static void inconkproc(void*); ! 129: ! 130: /* ! 131: * incon stream module definition ! 132: */ ! 133: static void inconoput(Queue*, Block*); ! 134: static void inconstopen(Queue*, Stream*); ! 135: static void inconstclose(Queue*); ! 136: Qinfo inconinfo = ! 137: { ! 138: nullput, ! 139: inconoput, ! 140: inconstopen, ! 141: inconstclose, ! 142: "incon" ! 143: }; ! 144: ! 145: int incondebug; ! 146: ! 147: Dirtab incondir[]={ ! 148: "stats", {Qstats}, 0, 0444, ! 149: }; ! 150: ! 151: /* ! 152: * set the incon parameters ! 153: */ ! 154: void ! 155: inconset(Incon *ip, int cnt, int del) ! 156: { ! 157: Device *dev; ! 158: ! 159: if (cnt<1 || cnt>14 || del<1 || del>15) ! 160: error(Ebadarg); ! 161: ! 162: dev = ip->dev; ! 163: dev->cmd = sel_rcv_cnt | INCON_RUN; ! 164: MICROSECOND; ! 165: *(uchar *)&dev->data_cntl = cnt; ! 166: MICROSECOND; ! 167: dev->cmd = sel_rcv_tim | INCON_RUN; ! 168: MICROSECOND; ! 169: *(uchar *)&dev->data_cntl = del; ! 170: MICROSECOND; ! 171: dev->cmd = INCON_RUN | ENABLE_IRQ; ! 172: } ! 173: ! 174: /* ! 175: * parse a set request ! 176: */ ! 177: void ! 178: inconsetctl(Incon *ip, Block *bp) ! 179: { ! 180: char *field[3]; ! 181: int n; ! 182: int del; ! 183: int cnt; ! 184: ! 185: del = 15; ! 186: n = getfields((char *)bp->rptr, field, 3, " "); ! 187: switch(n){ ! 188: default: ! 189: freeb(bp); ! 190: error(Ebadarg); ! 191: case 2: ! 192: del = strtol(field[1], 0, 0); ! 193: if(del<0 || del>15){ ! 194: freeb(bp); ! 195: error(Ebadarg); ! 196: } ! 197: /* fall through */ ! 198: case 1: ! 199: cnt = strtol(field[0], 0, 0); ! 200: if(cnt<0 || cnt>15){ ! 201: freeb(bp); ! 202: error(Ebadarg); ! 203: } ! 204: } ! 205: inconset(ip, cnt, del); ! 206: freeb(bp); ! 207: } ! 208: ! 209: static void ! 210: nop(void) ! 211: { ! 212: } ! 213: ! 214: /* ! 215: * poll for a station number ! 216: */ ! 217: void ! 218: inconpoll(Incon *ip, int station) ! 219: { ! 220: ulong timer; ! 221: Device *dev; ! 222: ! 223: dev = ip->dev; ! 224: ! 225: /* ! 226: * get us to a known state ! 227: */ ! 228: ip->state = Notliving; ! 229: dev->cmd = INCON_STOP; ! 230: ! 231: /* ! 232: * try a station number ! 233: */ ! 234: dev->cmd = sel_station; ! 235: *(uchar *)&dev->data_cntl = station; ! 236: dev->cmd = sel_poll0; ! 237: *(uchar *)&dev->data_cntl = HT_GNOT; ! 238: dev->cmd = sel_rcv_cnt; ! 239: *(uchar *)&dev->data_cntl = 3; ! 240: dev->cmd = sel_rcv_tim; ! 241: *(uchar *)&dev->data_cntl = 15; ! 242: dev->cmd = sel_tx_cnt; ! 243: *(uchar *)&dev->data_cntl = 1; ! 244: dev->cmd = sel_polln; ! 245: *(uchar *)&dev->data_cntl = 0x00; ! 246: *(uchar *)&dev->data_cntl = ST_UNIX; ! 247: *(uchar *)&dev->data_cntl = NCHAN; ! 248: *(uchar *)&dev->data_cntl = 'g'; ! 249: *(uchar *)&dev->data_cntl = 'n'; ! 250: *(uchar *)&dev->data_cntl = 'o'; ! 251: *(uchar *)&dev->data_cntl = 't'; ! 252: dev->cpolln = 0; ! 253: ! 254: /* ! 255: * poll and wait for ready (or 1/4 second) ! 256: */ ! 257: ip->state = Selecting; ! 258: dev->cmd = INCON_RUN | ENABLE_IRQ; ! 259: timer = NOW + 250; ! 260: while (NOW < timer) { ! 261: nop(); ! 262: if(dev->status & INCON_ALIVE){ ! 263: ip->station = station; ! 264: ip->state = Selected; ! 265: break; ! 266: } ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * reset the chip and find a new staion number ! 272: */ ! 273: void ! 274: inconrestart(Incon *ip) ! 275: { ! 276: int i; ! 277: ! 278: if(!canqlock(&ip->reslock)) ! 279: return; ! 280: ! 281: /* ! 282: * poll for incon station numbers ! 283: */ ! 284: for(i = Minstation; i <= Maxstation; i++){ ! 285: inconpoll(ip, i); ! 286: if(ip->state == Selected) ! 287: break; ! 288: } ! 289: switch(ip->state) { ! 290: case Selecting: ! 291: print("incon[%d] not polled\n", ip-incon); ! 292: break; ! 293: case Selected: ! 294: print("incon[%d] station %d\n", ip-incon, ip->station); ! 295: inconset(ip, 3, 15); ! 296: break; ! 297: default: ! 298: print("incon[%d] bollixed\n", ip-incon); ! 299: break; ! 300: } ! 301: qunlock(&ip->reslock); ! 302: } ! 303: ! 304: /* ! 305: * reset all incon chips. ! 306: */ ! 307: void ! 308: inconreset(void) ! 309: { ! 310: int i; ! 311: ! 312: incon[0].dev = INCON; ! 313: incon[0].state = Selected; ! 314: incon[0].ri = incon[0].wi = 0; ! 315: /* inconset(&incon[0], 3, 15); /**/ ! 316: for(i=1; i<Nincon; i++){ ! 317: incon[i].dev = INCON+i; ! 318: incon[i].state = Notliving; ! 319: incon[i].dev->cmd = INCON_STOP; ! 320: incon[i].ri = incon[i].wi = 0; ! 321: } ! 322: } ! 323: ! 324: void ! 325: inconinit(void) ! 326: { ! 327: } ! 328: ! 329: /* ! 330: * enable the device for interrupts, spec is the device number ! 331: */ ! 332: Chan* ! 333: inconattach(char *spec) ! 334: { ! 335: Incon *ip; ! 336: int i; ! 337: Chan *c; ! 338: ! 339: i = strtoul(spec, 0, 0); ! 340: if(i >= Nincon) ! 341: error(Ebadarg); ! 342: ip = &incon[i]; ! 343: if(ip->state != Selected) ! 344: inconrestart(ip); ! 345: ! 346: c = devattach('i', spec); ! 347: c->dev = i; ! 348: c->qid.path = CHDIR; ! 349: c->qid.vers = 0; ! 350: return c; ! 351: } ! 352: ! 353: Chan* ! 354: inconclone(Chan *c, Chan *nc) ! 355: { ! 356: return devclone(c, nc); ! 357: } ! 358: ! 359: int ! 360: inconwalk(Chan *c, char *name) ! 361: { ! 362: return devwalk(c, name, incondir, 1, streamgen); ! 363: } ! 364: ! 365: void ! 366: inconstat(Chan *c, char *dp) ! 367: { ! 368: devstat(c, dp, incondir, 1, streamgen); ! 369: } ! 370: ! 371: Chan* ! 372: inconopen(Chan *c, int omode) ! 373: { ! 374: if(c->qid.path == CHDIR || c->qid.path == Qstats){ ! 375: if(omode != OREAD) ! 376: error(Eperm); ! 377: }else ! 378: streamopen(c, &inconinfo); ! 379: c->mode = openmode(omode); ! 380: c->flag |= COPEN; ! 381: c->offset = 0; ! 382: return c; ! 383: } ! 384: ! 385: void ! 386: inconcreate(Chan *c, char *name, int omode, ulong perm) ! 387: { ! 388: USED(c, name, omode, perm); ! 389: error(Eperm); ! 390: } ! 391: ! 392: void ! 393: inconclose(Chan *c) ! 394: { ! 395: if(c->qid.path != CHDIR) ! 396: streamclose(c); ! 397: } ! 398: ! 399: long ! 400: inconread(Chan *c, void *buf, long n, ulong offset) ! 401: { ! 402: char b[256]; ! 403: Incon *i; ! 404: ! 405: if(c->qid.path == CHDIR) ! 406: return devdirread(c, buf, n, incondir, 1, streamgen); ! 407: else if(c->qid.path == Qstats){ ! 408: i = &incon[c->dev]; ! 409: sprint(b, "in: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", i->in, ! 410: i->out, i->overflow, i->crc, i->wait); ! 411: return readstr(offset, buf, n, b); ! 412: } else ! 413: return streamread(c, buf, n); ! 414: } ! 415: ! 416: long ! 417: inconwrite(Chan *c, void *buf, long n, ulong offset) ! 418: { ! 419: USED(offset); ! 420: return streamwrite(c, buf, n, 0); ! 421: } ! 422: ! 423: void ! 424: inconremove(Chan *c) ! 425: { ! 426: USED(c); ! 427: error(Eperm); ! 428: } ! 429: ! 430: void ! 431: inconwstat(Chan *c, char *dp) ! 432: { ! 433: USED(c, dp); ! 434: error(Eperm); ! 435: } ! 436: ! 437: /* ! 438: * the stream routines ! 439: */ ! 440: ! 441: /* ! 442: * for sleeping while kproc dies ! 443: */ ! 444: static int ! 445: kNotliving(void *arg) ! 446: { ! 447: Incon *ip; ! 448: ! 449: ip = (Incon *)arg; ! 450: return ip->kstarted == 0; ! 451: } ! 452: ! 453: /* ! 454: * create the kernel process for input ! 455: * first wait for any old ones to die ! 456: */ ! 457: static void ! 458: inconstopen(Queue *q, Stream *s) ! 459: { ! 460: Incon *ip; ! 461: char name[32]; ! 462: ! 463: ip = &incon[s->dev]; ! 464: sprint(name, "incon%d", s->dev); ! 465: q->ptr = q->other->ptr = ip; ! 466: wakeup(&ip->kr); ! 467: sleep(&ip->r, kNotliving, ip); ! 468: ip->rq = q; ! 469: kproc(name, inconkproc, ip); ! 470: } ! 471: ! 472: /* ! 473: * kill off the kernel process ! 474: */ ! 475: static void ! 476: inconstclose(Queue * q) ! 477: { ! 478: Incon *ip; ! 479: ! 480: ip = (Incon *)q->ptr; ! 481: qlock(ip); ! 482: ip->rq = 0; ! 483: qunlock(ip); ! 484: wakeup(&ip->kr); ! 485: sleep(&ip->r, kNotliving, ip); ! 486: } ! 487: ! 488: /* ! 489: * free all blocks of a message in `q', `bp' is the first block ! 490: * of the message ! 491: */ ! 492: static void ! 493: freemsg(Queue *q, Block *bp) ! 494: { ! 495: for(; bp; bp = getq(q)){ ! 496: if(bp->flags & S_DELIM){ ! 497: freeb(bp); ! 498: return; ! 499: } ! 500: freeb(bp); ! 501: } ! 502: } ! 503: ! 504: /* ! 505: * output a block ! 506: * ! 507: * the first 2 bytes of every message are the channel number, ! 508: * low order byte first. the third is a possible trailing control ! 509: * character. ! 510: */ ! 511: void ! 512: inconoput(Queue *q, Block *bp) ! 513: { ! 514: Device *dev; ! 515: Incon *ip; ! 516: ulong start, end; ! 517: int chan; ! 518: int ctl; ! 519: int n, size; ! 520: ! 521: ip = (Incon *)q->ptr; ! 522: ! 523: if(bp->type != M_DATA){ ! 524: if(streamparse("inconset", bp)) ! 525: inconsetctl(ip, bp); ! 526: else ! 527: freeb(bp); ! 528: return; ! 529: } ! 530: if(BLEN(bp) < 3){ ! 531: bp = pullup(bp, 3); ! 532: if(bp == 0){ ! 533: print("inconoput pullup failed\n"); ! 534: return; ! 535: } ! 536: } ! 537: ! 538: /* ! 539: * get a whole message before handing bytes to the device ! 540: */ ! 541: if(!putq(q, bp)) ! 542: return; ! 543: ! 544: /* ! 545: * one transmitter at a time ! 546: */ ! 547: qlock(&ip->xmit); ! 548: dev = ip->dev; ! 549: ! 550: /* ! 551: * parse message ! 552: */ ! 553: bp = getq(q); ! 554: chan = bp->rptr[0] | (bp->rptr[1]<<8); ! 555: ctl = bp->rptr[2]; ! 556: bp->rptr += 3; ! 557: if(chan<=0) ! 558: print("bad channel %d\n", chan); ! 559: ! 560: if(incondebug) ! 561: print("->(%d)%uo %d\n", chan, ctl, bp->wptr - bp->rptr); ! 562: ! 563: /* ! 564: * make sure there's an incon out there ! 565: */ ! 566: if(!(dev->status&INCON_ALIVE) || ip->state==Notliving){ ! 567: inconrestart(ip); ! 568: freemsg(q, bp); ! 569: qunlock(&ip->xmit); ! 570: return; ! 571: } ! 572: ! 573: /* ! 574: * send the 8 bit data ! 575: */ ! 576: for(;;){ ! 577: /* ! 578: * spin till there is room ! 579: */ ! 580: start = NOW; ! 581: for(n = 0, end = start+1000; dev->status & TX_FULL; n++){ ! 582: nop(); /* make sure we don't optimize too much */ ! 583: if(NOW > end){ ! 584: print("incon output stuck\n"); ! 585: freemsg(q, bp); ! 586: qunlock(&ip->xmit); ! 587: return; ! 588: } ! 589: } ! 590: ip->wait = (n + ip->wait)>>1; ! 591: ! 592: /* ! 593: * put in next packet ! 594: */ ! 595: n = bp->wptr - bp->rptr; ! 596: if(n > 16) ! 597: n = 16; ! 598: size = n; ! 599: dev->cdata = chan; ! 600: ip->out += n; ! 601: while(n--){ ! 602: *(uchar *)&dev->data_cntl = *bp->rptr++; ! 603: } ! 604: ! 605: /* ! 606: * get next block ! 607: */ ! 608: if(bp->rptr >= bp->wptr){ ! 609: if(bp->flags & S_DELIM){ ! 610: freeb(bp); ! 611: break; ! 612: } ! 613: freeb(bp); ! 614: bp = getq(q); ! 615: if(bp==0) ! 616: break; ! 617: } ! 618: ! 619: /* ! 620: * end packet ! 621: */ ! 622: dev->cdata = 0; ! 623: } ! 624: ! 625: /* ! 626: * send the control byte if there is one ! 627: */ ! 628: if(ctl){ ! 629: if(size >= 16){ ! 630: dev->cdata = 0; ! 631: MICROSECOND; ! 632: for(end = NOW+1000; dev->status & TX_FULL;){ ! 633: nop(); /* make sure we don't optimize too much */ ! 634: if(NOW > end){ ! 635: print("incon output stuck\n"); ! 636: freemsg(q, bp); ! 637: qunlock(&ip->xmit); ! 638: return; ! 639: } ! 640: } ! 641: dev->cdata = chan; ! 642: MICROSECOND; ! 643: } ! 644: if(dev->status & TX_FULL) ! 645: print("inconfull\n"); ! 646: dev->cdata = ctl; ! 647: } ! 648: MICROSECOND; ! 649: dev->cdata = 0; ! 650: ! 651: qunlock(&ip->xmit); ! 652: return; ! 653: } ! 654: ! 655: /* ! 656: * return true if the raw fifo is non-empty ! 657: */ ! 658: static int ! 659: notempty(void *arg) ! 660: { ! 661: Incon *ip; ! 662: ! 663: ip = (Incon *)arg; ! 664: return ip->ri!=ip->wi; ! 665: } ! 666: ! 667: /* ! 668: * Read bytes from the raw input circular buffer. ! 669: */ ! 670: static void ! 671: inconkproc(void *arg) ! 672: { ! 673: Incon *ip; ! 674: Block *bp; ! 675: int i; ! 676: int locked; ! 677: ! 678: ip = (Incon *)arg; ! 679: ip->kstarted = 1; ! 680: ! 681: /* ! 682: * create a number of blocks for input ! 683: */ ! 684: for(i = 0; i < Nin; i++){ ! 685: bp = ip->inb[i] = allocb(Bsize); ! 686: bp->wptr += 3; ! 687: } ! 688: ! 689: locked = 0; ! 690: if(waserror()){ ! 691: if(locked) ! 692: qunlock(ip); ! 693: ip->kstarted = 0; ! 694: wakeup(&ip->r); ! 695: return; ! 696: } ! 697: ! 698: for(;;){ ! 699: /* ! 700: * sleep if input fifo empty ! 701: */ ! 702: sleep(&ip->kr, notempty, ip); ! 703: ! 704: /* ! 705: * die if the device is closed ! 706: */ ! 707: USED(locked); ! 708: qlock(ip); ! 709: locked = 1; ! 710: if(ip->rq == 0){ ! 711: qunlock(ip); ! 712: ip->kstarted = 0; ! 713: wakeup(&ip->r); ! 714: poperror(); ! 715: return; ! 716: } ! 717: ! 718: /* ! 719: * send blocks upstream and stage new blocks. if the block is small ! 720: * (< 64 bytes) copy into a smaller buffer. ! 721: */ ! 722: while(ip->ri != ip->wi){ ! 723: bp = ip->inb[ip->ri]; ! 724: ip->in += BLEN(bp); ! 725: PUTNEXT(ip->rq, bp); ! 726: bp = ip->inb[ip->ri] = allocb(Bsize); ! 727: bp->wptr += 3; ! 728: ip->ri = (ip->ri+1)%Nin; ! 729: } ! 730: USED(locked); ! 731: qunlock(ip); ! 732: locked = 0; ! 733: } ! 734: } ! 735: ! 736: /* ! 737: * drop a single packet ! 738: */ ! 739: static void ! 740: droppacket(Device *dev) ! 741: { ! 742: int i; ! 743: int c; ! 744: ! 745: for(i = 0; i < 17; i++){ ! 746: c = dev->data_cntl; ! 747: if(c==0) ! 748: break; ! 749: } ! 750: } ! 751: ! 752: /* ! 753: * flush the input fifo ! 754: */ ! 755: static void ! 756: flushfifo(Device *dev) ! 757: { ! 758: while(!(dev->status & RCV_EMPTY)) ! 759: droppacket(dev); ! 760: } ! 761: ! 762: /* ! 763: * advance the queue. if we've run out of staged input blocks, ! 764: * drop the packet and return 0. otherwise return the next input ! 765: * block to fill. ! 766: */ ! 767: static Block * ! 768: nextin(Incon *ip, unsigned int c) ! 769: { ! 770: Block *bp; ! 771: int next; ! 772: ! 773: bp = ip->inb[ip->wi]; ! 774: bp->rptr[0] = ip->chan; ! 775: bp->rptr[1] = ip->chan>>8; ! 776: bp->rptr[2] = c; ! 777: if(incondebug) ! 778: print("<-(%d)%uo %d\n", ip->chan, c, bp->wptr-bp->rptr); ! 779: ! 780: next = (ip->wi+1)%Nin; ! 781: if(next == ip->ri){ ! 782: bp->wptr = bp->rptr+3; ! 783: return bp; ! 784: } ! 785: ip->wi = next; ! 786: ! 787: return ip->inb[ip->wi]; ! 788: } ! 789: ! 790: /* ! 791: * read the packets from the device into the staged input blocks. ! 792: * we have to do this at interrupt tevel to turn off the interrupts. ! 793: */ ! 794: static void ! 795: rdpackets(Incon *ip) ! 796: { ! 797: Block *bp; ! 798: unsigned int c; ! 799: Device *dev; ! 800: uchar *p; ! 801: int first = ip->wi; ! 802: ! 803: dev = ip->dev; ! 804: bp = ip->inb[ip->wi]; ! 805: if(bp==0){ ! 806: flushfifo(ip->dev); ! 807: return; ! 808: } ! 809: p = bp->wptr; ! 810: while(!(dev->status & RCV_EMPTY)){ ! 811: /* ! 812: * get channel number ! 813: */ ! 814: c = (dev->data_cntl)>>8; ! 815: if(c == 0){ ! 816: droppacket(dev); ! 817: continue; ! 818: } ! 819: if(ip->chan != c){ ! 820: if(p - bp->rptr > 3){ ! 821: bp->wptr = p; ! 822: bp = nextin(ip, 0); ! 823: if(bp==0){ ! 824: flushfifo(ip->dev); ! 825: return; ! 826: } ! 827: p = bp->wptr; ! 828: } ! 829: ip->chan = c; ! 830: } ! 831: ! 832: /* ! 833: * null byte marks end of packet ! 834: */ ! 835: for(;;){ ! 836: if((c=dev->data_cntl)&1) { ! 837: /* ! 838: * data byte, put in local buffer ! 839: */ ! 840: *p++ = c>>8; ! 841: } else if (c>>=8) { ! 842: /* ! 843: * control byte ends block ! 844: */ ! 845: bp->wptr = p; ! 846: bp = nextin(ip, c); ! 847: if(bp==0){ ! 848: flushfifo(ip->dev); ! 849: return; ! 850: } ! 851: p = bp->wptr; ! 852: } else { ! 853: /* end of packet */ ! 854: break; ! 855: } ! 856: } ! 857: ! 858: /* ! 859: * pass a block on if it doesn't have room for one more ! 860: * packet. this way we don't have to check per byte. ! 861: */ ! 862: if(p + 16 > bp->lim){ ! 863: bp->wptr = p; ! 864: bp = nextin(ip, 0); ! 865: p = bp->wptr; ! 866: } ! 867: } ! 868: bp->wptr = p; ! 869: if(bp->wptr != bp->rptr+3) ! 870: nextin(ip, 0); ! 871: ! 872: if(first != ip->wi)/**/ ! 873: wakeup(&ip->kr); ! 874: } ! 875: ! 876: /* ! 877: * Receive an incon interrupt. One entry point ! 878: * for all types of interrupt. Until we figure out ! 879: * how to use more than one incon, this routine only ! 880: * is for incon[0]. ! 881: */ ! 882: void ! 883: inconintr(Ureg *ur) ! 884: { ! 885: uchar status; ! 886: Incon *ip; ! 887: ! 888: USED(ur); ! 889: ip = &incon[0]; ! 890: ! 891: status = ip->dev->status; ! 892: if(!(status & RCV_EMPTY)) ! 893: rdpackets(ip); ! 894: ! 895: /* check for exceptional conditions */ ! 896: if(status&(OVERFLOW|CRC_ERROR)){ ! 897: if(status&OVERFLOW) ! 898: ip->overflow++; ! 899: if(status&CRC_ERROR) ! 900: ip->crc++; ! 901: } ! 902: ! 903: /* see if it died underneath us */ ! 904: if(!(status&INCON_ALIVE)){ ! 905: switch(ip->state){ ! 906: case Selected: ! 907: ip->dev->cmd = INCON_STOP; ! 908: print("Incon died\n"); ! 909: break; ! 910: case Selecting: ! 911: print("rejected\n"); ! 912: break; ! 913: default: ! 914: ip->dev->cmd = INCON_STOP; ! 915: break; ! 916: } ! 917: ip->state = Notliving; ! 918: } ! 919: } ! 920: ! 921: void ! 922: incontoggle(void) ! 923: { ! 924: incondebug ^= 1; ! 925: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.