|
|
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: ! 11: /* Centronix parallel (printer) port */ ! 12: ! 13: typedef struct Lptinfo Lptinfo; ! 14: ! 15: struct Lptinfo ! 16: { ! 17: int base; /* port number */ ! 18: int ivec; /* interrupt number */ ! 19: }; ! 20: ! 21: static Lptinfo lptinfo[] = { ! 22: 0x3bc, Parallelvec, /* lpt1 (safari) */ ! 23: 0x378, Parallelvec, /* lpt1 (`official') */ ! 24: 0x278, Int0vec+5, /* lpt2 (`official') */ ! 25: }; ! 26: #define NDEV (sizeof lptinfo/sizeof lptinfo[0]) ! 27: ! 28: extern int incondev; /* from config */ ! 29: ! 30: /* offsets, and bits in the registers */ ! 31: enum ! 32: { ! 33: /* data latch register */ ! 34: Qdlr= 0x0, ! 35: /* printer status register */ ! 36: Qpsr= 0x1, ! 37: Fbusy= 0x80, ! 38: Fintbar= 0x40, ! 39: /* printer control register */ ! 40: Qpcr= 0x2, ! 41: Fie= 0x10, ! 42: Fsi= 0x08, ! 43: Finitbar= 0x04, ! 44: Faf= 0x02, ! 45: Fstrobe= 0x01, ! 46: ! 47: /* other `registers' */ ! 48: Qstats= 0x03, ! 49: Qdebug= 0x04 ! 50: }; ! 51: ! 52: /* ! 53: * af si dlr<7:0> ! 54: * 0 x xxxxxxxx wr ctl/data char (si is dcto) ! 55: * 1 0 xxxxxxxx wr cmd ! 56: * 1 1 xxxxxx00 rd ctl/data char ! 57: * 1 1 xxxxxx01 rd status ! 58: * 1 1 xxxxxx11 nop (multiplexer to normal state) ! 59: * ! 60: * psr<7:3> multiplexed as follows: ! 61: * ! 62: * bc7 bc6 bc5 bc4 bc3 ! 63: * rd, st- low bsy d8 d7 d6 d5 ! 64: * rd, st- high d4 d3 d2 d1 d0 ! 65: * other bsy int- ! 66: */ ! 67: ! 68: typedef struct Incon Incon; ! 69: ! 70: #define NOW (MACHP(0)->ticks*MS2HZ) ! 71: ! 72: #define DPRINT if(incondebug)kprint ! 73: ! 74: static void inconintr(Ureg *ur, void *a); ! 75: ! 76: enum { ! 77: Minstation= 2, /* lowest station # to poll */ ! 78: Maxstation= 15, /* highest station # to poll */ ! 79: Nincon= 1, /* number of incons */ ! 80: Nin= 32, /* Blocks in the input ring */ ! 81: Bsize= 128, /* size of an input ring block */ ! 82: Mfifo= 0xff /* a mask, must be 2^n-1, must be > Nin */ ! 83: }; ! 84: ! 85: struct Incon { ! 86: QLock; ! 87: ! 88: QLock xmit; /* transmit lock */ ! 89: QLock reslock; /* reset lock */ ! 90: int dev; /* base address of port */ ! 91: int station; /* station number */ ! 92: int state; /* chip state */ ! 93: Rendez r; /* output process */ ! 94: Rendez kr; /* input kernel process */ ! 95: ushort chan; /* current input channel */ ! 96: Queue *rq; /* read queue */ ! 97: int kstarted; /* true if kernel process started */ ! 98: ! 99: /* input blocks */ ! 100: ! 101: Block *inb[Nin]; ! 102: ushort wi; ! 103: ushort ri; ! 104: ! 105: /* statistics */ ! 106: ! 107: ulong overflow; /* overflow errors */ ! 108: ulong pack0; /* channel 0 */ ! 109: ulong crc; /* crc errors */ ! 110: ulong in; /* bytes in */ ! 111: ulong out; /* bytes out */ ! 112: ulong wait; /* wait time in milliseconds */ ! 113: }; ! 114: ! 115: Incon incon[Nincon]; ! 116: ! 117: /* ! 118: * chip state ! 119: */ ! 120: enum { ! 121: Selecting, ! 122: Selected, ! 123: Notliving, ! 124: }; ! 125: ! 126: /* ! 127: * internal chip registers ! 128: */ ! 129: #define sel_polln 0 ! 130: #define sel_station 1 ! 131: #define sel_poll0 2 ! 132: #define sel_rcv_cnt 3 ! 133: #define sel_rcv_tim 4 ! 134: #define sel_tx_cnt 5 ! 135: ! 136: /* ! 137: * CSR bits ! 138: */ ! 139: #define INCON_RUN 0x80 ! 140: #define INCON_STOP 0x00 ! 141: #define ENABLE_IRQ 0x40 ! 142: #define ENABLE_TX_IRQ 0x20 ! 143: #define INCON_ALIVE 0x80 ! 144: #define TX_FULL 0x10 ! 145: #define TX_EMPTY 0x08 ! 146: #define RCV_EMPTY 0x04 ! 147: #define OVERFLOW 0x02 ! 148: #define CRC_ERROR 0x01 ! 149: ! 150: /* ! 151: * polling constants ! 152: */ ! 153: #define HT_GNOT 0x30 ! 154: #define HT_UNIX 0x31 ! 155: #define ST_UNIX 0x04 ! 156: #define NCHAN 64 ! 157: ! 158: static void inconkproc(void*); ! 159: ! 160: /* ! 161: * incon stream module definition ! 162: */ ! 163: static void inconoput(Queue*, Block*); ! 164: static void inconstopen(Queue*, Stream*); ! 165: static void inconstclose(Queue*); ! 166: Qinfo inconinfo = ! 167: { ! 168: nullput, ! 169: inconoput, ! 170: inconstopen, ! 171: inconstclose, ! 172: "incon" ! 173: }; ! 174: ! 175: int incondebug = 0; ! 176: ! 177: Dirtab incondir[]={ ! 178: "dlr", {Qdlr}, 1, 0666, ! 179: "psr", {Qpsr}, 5, 0444, ! 180: "pcr", {Qpcr}, 0, 0666, ! 181: "stats", {Qstats}, 0, 0444, ! 182: "debug", {Qdebug}, 0, 0666, ! 183: }; ! 184: #define NINCON (sizeof incondir/sizeof incondir[0]) ! 185: ! 186: static void ! 187: nop(void) ! 188: { ! 189: } ! 190: ! 191: static int ! 192: slowinb(int x) ! 193: { ! 194: nop(); ! 195: nop(); ! 196: return inb(x); ! 197: } ! 198: ! 199: static void ! 200: reset(int dev) /* hardware reset */ ! 201: { ! 202: outb(dev+Qpcr, Finitbar); ! 203: outb(dev+Qpcr, 0); ! 204: outb(dev+Qpcr, Finitbar); ! 205: } ! 206: ! 207: static void ! 208: wrctl(int dev, int data) /* write control character */ ! 209: { ! 210: outb(dev+Qpcr, Finitbar); /* no interrupts, please */ ! 211: outb(dev+Qdlr, data); ! 212: outb(dev+Qpcr, Finitbar|Fstrobe); ! 213: outb(dev+Qpcr, Finitbar|Fie); ! 214: } ! 215: ! 216: static void ! 217: wrdata(int dev, int data) /* write data character */ ! 218: { ! 219: outb(dev+Qpcr, Finitbar|Fsi); ! 220: outb(dev+Qdlr, data); ! 221: outb(dev+Qpcr, Finitbar|Fsi|Fstrobe); ! 222: outb(dev+Qpcr, Finitbar|Fsi|Fie); ! 223: } ! 224: ! 225: static void ! 226: wrcmd(int dev, int data) /* write command */ ! 227: { ! 228: outb(dev+Qpcr, Finitbar|Faf); ! 229: outb(dev+Qdlr, data); ! 230: outb(dev+Qpcr, Finitbar|Faf|Fstrobe); ! 231: outb(dev+Qpcr, Finitbar|Faf|Fie); ! 232: } ! 233: ! 234: static int ! 235: rdstatus(Incon *ip) /* read status */ ! 236: { ! 237: int dev, data; ! 238: ! 239: dev = ip->dev; ! 240: ! 241: outb(dev+Qpcr, Finitbar|Faf|Fsi); ! 242: outb(dev+Qdlr, 0x01); ! 243: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 244: data = (inb(dev+Qpsr)&0xf8)<<2; ! 245: outb(dev+Qpcr, Finitbar|Faf|Fsi); ! 246: data |= inb(dev+Qpsr)>>3; ! 247: if(data&(OVERFLOW|CRC_ERROR)){ ! 248: if(data&OVERFLOW) ! 249: ip->overflow++; ! 250: if(data&CRC_ERROR) ! 251: ip->crc++; ! 252: } ! 253: outb(dev+Qdlr, 0x03); ! 254: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 255: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie); ! 256: ! 257: return data; ! 258: } ! 259: ! 260: static void ! 261: iwrcmd(int dev, int data) /* write command at interrupt level */ ! 262: { ! 263: outb(dev+Qdlr, data); ! 264: outb(dev+Qpcr, Finitbar|Faf|Fstrobe); ! 265: outb(dev+Qpcr, Finitbar|Faf); ! 266: } ! 267: ! 268: static int ! 269: irdstatus(Incon *ip) /* read status at interrupt level */ ! 270: { ! 271: int dev, data; ! 272: ! 273: dev = ip->dev; ! 274: ! 275: outb(dev+Qdlr, 0x01); ! 276: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 277: data = (slowinb(dev+Qpsr)&0xf8)<<2; ! 278: outb(dev+Qpcr, Finitbar|Faf|Fsi); ! 279: data |= slowinb(dev+Qpsr)>>3; ! 280: if(data&(OVERFLOW|CRC_ERROR)){ ! 281: if(data&OVERFLOW) ! 282: ip->overflow++; ! 283: if(data&CRC_ERROR) ! 284: ip->crc++; ! 285: } ! 286: ! 287: return data; ! 288: } ! 289: ! 290: static int ! 291: irddata(int dev) /* read data at interrupt level */ ! 292: { ! 293: int data; ! 294: ! 295: outb(dev+Qdlr, 0x00); ! 296: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 297: data = (slowinb(dev+Qpsr)&0xf8)<<2; ! 298: outb(dev+Qpcr, Finitbar|Faf|Fsi); ! 299: data |= slowinb(dev+Qpsr)>>3; ! 300: ! 301: return data; ! 302: } ! 303: ! 304: static int ! 305: irdnext(int dev) /* read next data at interrupt level */ ! 306: { ! 307: int data; ! 308: ! 309: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 310: data = (inb(dev+Qpsr)&0xf8)<<2; ! 311: outb(dev+Qpcr, Finitbar|Faf|Fsi); ! 312: data |= inb(dev+Qpsr)>>3; ! 313: ! 314: return data; ! 315: } ! 316: ! 317: static void ! 318: irdnop(int dev, int pcr) /* read nop (mux reset) */ ! 319: { ! 320: outb(dev+Qdlr, 0x03); ! 321: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); ! 322: outb(dev+Qpcr, pcr); ! 323: } ! 324: ! 325: int Irdnext(int); ! 326: #define irdnext Irdnext ! 327: /**/ ! 328: ! 329: /* ! 330: * set the incon parameters ! 331: */ ! 332: void ! 333: inconset(Incon *ip, int cnt, int del) ! 334: { ! 335: int dev; ! 336: ! 337: if (cnt<1 || cnt>14 || del<1 || del>15) ! 338: error(Ebadarg); ! 339: ! 340: dev = ip->dev; ! 341: wrcmd(dev, sel_rcv_cnt | INCON_RUN); ! 342: wrdata(dev, cnt); ! 343: wrcmd(dev, sel_rcv_tim | INCON_RUN); ! 344: wrdata(dev, del); ! 345: wrcmd(dev, INCON_RUN | ENABLE_IRQ); ! 346: } ! 347: ! 348: /* ! 349: * parse a set request ! 350: */ ! 351: void ! 352: inconsetctl(Incon *ip, Block *bp) ! 353: { ! 354: char *field[3]; ! 355: int n; ! 356: int del; ! 357: int cnt; ! 358: ! 359: del = 15; ! 360: n = getfields((char *)bp->rptr, field, 3, " "); ! 361: switch(n){ ! 362: default: ! 363: freeb(bp); ! 364: error(Ebadarg); ! 365: case 2: ! 366: del = strtol(field[1], 0, 0); ! 367: if(del<0 || del>15){ ! 368: freeb(bp); ! 369: error(Ebadarg); ! 370: } ! 371: /* fall through */ ! 372: case 1: ! 373: cnt = strtol(field[0], 0, 0); ! 374: if(cnt<0 || cnt>15){ ! 375: freeb(bp); ! 376: error(Ebadarg); ! 377: } ! 378: } ! 379: inconset(ip, cnt, del); ! 380: freeb(bp); ! 381: } ! 382: ! 383: /* ! 384: * poll for a station number ! 385: */ ! 386: void ! 387: inconpoll(Incon *ip, int station) ! 388: { ! 389: ulong timer; ! 390: int dev; ! 391: char *p; ! 392: ! 393: dev = ip->dev; ! 394: ! 395: /* ! 396: * get us to a known state ! 397: */ ! 398: ip->state = Notliving; ! 399: wrcmd(dev, INCON_STOP); ! 400: ! 401: /* ! 402: * try a station number ! 403: */ ! 404: wrcmd(dev, sel_station); ! 405: wrdata(dev, station); ! 406: wrcmd(dev, sel_poll0); ! 407: wrdata(dev, HT_GNOT); ! 408: wrcmd(dev, sel_rcv_cnt); ! 409: wrdata(dev, 3); ! 410: wrcmd(dev, sel_rcv_tim); ! 411: wrdata(dev, 15); ! 412: wrcmd(dev, sel_tx_cnt); ! 413: wrdata(dev, 1); ! 414: wrcmd(dev, sel_polln); ! 415: wrdata(dev, 0x00); ! 416: wrdata(dev, ST_UNIX); ! 417: wrdata(dev, NCHAN); ! 418: for(p = "gnot"; *p; p++) ! 419: wrdata(dev, *p); ! 420: wrctl(dev, 0); ! 421: ! 422: /* ! 423: * poll and wait for ready (or 1/4 second) ! 424: */ ! 425: ip->state = Selecting; ! 426: wrcmd(dev, INCON_RUN | ENABLE_IRQ); ! 427: timer = NOW + 250; ! 428: while (NOW < timer) { ! 429: nop(); ! 430: if(rdstatus(ip) & INCON_ALIVE){ ! 431: ip->station = station; ! 432: ip->state = Selected; ! 433: break; ! 434: } ! 435: } ! 436: } ! 437: ! 438: /* ! 439: * reset the chip and find a new station number ! 440: */ ! 441: void ! 442: inconrestart(Incon *ip) ! 443: { ! 444: int i; ! 445: ! 446: if(!canqlock(&ip->reslock)) ! 447: return; ! 448: ! 449: /* ! 450: * poll for incon station numbers ! 451: */ ! 452: DPRINT("inconrestart\n"); ! 453: for(i = Minstation; i <= Maxstation; i++){ ! 454: inconpoll(ip, i); ! 455: if(ip->state == Selected) ! 456: break; ! 457: } ! 458: switch(ip->state) { ! 459: case Selecting: ! 460: DPRINT("incon[%d] not polled\n", ip-incon); ! 461: print("incon[%d] not polled\n", ip-incon); ! 462: break; ! 463: case Selected: ! 464: DPRINT("incon[%d] station %d\n", ip-incon, ip->station); ! 465: print("incon[%d] station %d\n", ip-incon, ip->station); ! 466: inconset(ip, 3, 15); ! 467: break; ! 468: default: ! 469: DPRINT("incon[%d] bollixed\n", ip-incon); ! 470: print("incon[%d] bollixed\n", ip-incon); ! 471: break; ! 472: } ! 473: qunlock(&ip->reslock); ! 474: } ! 475: ! 476: /* ! 477: * reset all incon chips. ! 478: */ ! 479: ! 480: void ! 481: inconreset(void) ! 482: { ! 483: int i; ! 484: char *p; ! 485: ! 486: /* ! 487: * get incondev from p9rc ! 488: */ ! 489: p = getconf("incondev"); ! 490: if(p) ! 491: incondev = atoi(p); ! 492: ! 493: /* ! 494: * state is Selected if we used incon as the boot device ! 495: * i.e. we've already got a station number. ! 496: * state is Selecting if this is a first-time open. ! 497: */ ! 498: /* inconset(&incon[0], 3, 15); /**/ ! 499: for(i=0; i<Nincon; i++){ ! 500: incon[i].dev = lptinfo[incondev].base; ! 501: incon[i].state = Notliving; ! 502: reset(incon[i].dev); ! 503: incon[i].ri = incon[i].wi = 0; ! 504: } ! 505: incon[0].state = Selecting; ! 506: wrcmd(incon[0].dev, INCON_STOP); ! 507: } ! 508: ! 509: void ! 510: inconinit(void) ! 511: { ! 512: wrcmd(incon[0].dev, INCON_STOP); ! 513: } ! 514: ! 515: /* ! 516: * enable the device for interrupts, spec is the device number ! 517: */ ! 518: Chan* ! 519: inconattach(char *spec) ! 520: { ! 521: Incon *ip; ! 522: int i; ! 523: Chan *c; ! 524: ! 525: setvec(lptinfo[incondev].ivec, inconintr, 0); ! 526: i = strtoul(spec, 0, 0); ! 527: if(i >= Nincon) ! 528: error(Ebadarg); ! 529: ip = &incon[i]; ! 530: rdstatus(ip); ! 531: if(ip->state != Selected) ! 532: inconrestart(ip); ! 533: ! 534: c = devattach('i', spec); ! 535: c->dev = i; ! 536: c->qid.path = CHDIR; ! 537: c->qid.vers = 0; ! 538: return c; ! 539: } ! 540: ! 541: Chan* ! 542: inconclone(Chan *c, Chan *nc) ! 543: { ! 544: return devclone(c, nc); ! 545: } ! 546: ! 547: int ! 548: inconwalk(Chan *c, char *name) ! 549: { ! 550: return devwalk(c, name, incondir, NINCON, streamgen); ! 551: } ! 552: ! 553: void ! 554: inconstat(Chan *c, char *dp) ! 555: { ! 556: devstat(c, dp, incondir, NINCON, streamgen); ! 557: } ! 558: ! 559: Chan* ! 560: inconopen(Chan *c, int omode) ! 561: { ! 562: if(c->qid.path != CHDIR && c->qid.path >= Slowqid) ! 563: streamopen(c, &inconinfo); ! 564: c->mode = openmode(omode); ! 565: c->flag |= COPEN; ! 566: c->offset = 0; ! 567: return c; ! 568: } ! 569: ! 570: void ! 571: inconcreate(Chan *c, char *name, int omode, ulong perm) ! 572: { ! 573: USED(c, name, omode, perm); ! 574: error(Eperm); ! 575: } ! 576: ! 577: void ! 578: inconclose(Chan *c) ! 579: { ! 580: if(c->qid.path != CHDIR && c->qid.path >= Slowqid) ! 581: streamclose(c); ! 582: } ! 583: ! 584: long ! 585: inconread(Chan *c, void *buf, long n, ulong offset) ! 586: { ! 587: char b[256]; ! 588: Incon *ip; ! 589: ! 590: if(c->qid.path == CHDIR) ! 591: return devdirread(c, buf, n, incondir, NINCON, streamgen); ! 592: ip = &incon[c->dev]; ! 593: switch(c->qid.path){ ! 594: default: ! 595: return streamread(c, buf, n); ! 596: case Qdlr: ! 597: case Qpsr: ! 598: case Qpcr: ! 599: sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path)); ! 600: break; ! 601: case Qstats: ! 602: sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", ! 603: ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait); ! 604: break; ! 605: case Qdebug: ! 606: sprint(b, "%d\n", incondebug); ! 607: break; ! 608: } ! 609: return readstr(offset, buf, n, b); ! 610: } ! 611: ! 612: long ! 613: inconwrite(Chan *c, void *buf, long n, ulong offset) ! 614: { ! 615: char b[8]; ! 616: Incon *ip; ! 617: int data; ! 618: ! 619: USED(offset); ! 620: switch(c->qid.path){ ! 621: default: ! 622: return streamwrite(c, buf, n, 0); ! 623: case Qdlr: ! 624: case Qpcr: ! 625: case Qdebug: ! 626: break; ! 627: } ! 628: if(n > sizeof b-1) ! 629: n = sizeof b-1; ! 630: memmove(b, buf, n); ! 631: b[n] = 0; ! 632: data = strtoul(b, 0, 0); ! 633: switch(c->qid.path){ ! 634: default: ! 635: ip = &incon[c->dev]; ! 636: outb(ip->dev + c->qid.path, data); ! 637: break; ! 638: case Qdebug: ! 639: incondebug = data; ! 640: break; ! 641: } ! 642: return n; ! 643: } ! 644: ! 645: void ! 646: inconremove(Chan *c) ! 647: { ! 648: USED(c); ! 649: error(Eperm); ! 650: } ! 651: ! 652: void ! 653: inconwstat(Chan *c, char *dp) ! 654: { ! 655: USED(c, dp); ! 656: error(Eperm); ! 657: } ! 658: ! 659: /* ! 660: * the stream routines ! 661: */ ! 662: ! 663: /* ! 664: * kill off the kernel process ! 665: */ ! 666: static int ! 667: kNotliving(void *arg) ! 668: { ! 669: Incon *ip; ! 670: ! 671: ip = (Incon *)arg; ! 672: return ip->kstarted == 0; ! 673: } ! 674: ! 675: static void ! 676: inconstclose(Queue * q) ! 677: { ! 678: Incon *ip; ! 679: ! 680: ip = (Incon *)q->ptr; ! 681: qlock(ip); ! 682: ip->rq = 0; ! 683: qunlock(ip); ! 684: wakeup(&ip->kr); ! 685: sleep(&ip->r, kNotliving, ip); ! 686: } ! 687: ! 688: /* ! 689: * create the kernel process for input ! 690: * first wait for any old ones to die ! 691: */ ! 692: static void ! 693: inconstopen(Queue *q, Stream *s) ! 694: { ! 695: Incon *ip; ! 696: char name[32]; ! 697: ! 698: ip = &incon[s->dev]; ! 699: sprint(name, "incon%d", s->dev); ! 700: q->ptr = q->other->ptr = ip; ! 701: wakeup(&ip->kr); ! 702: sleep(&ip->r, kNotliving, ip); ! 703: ip->rq = q; ! 704: kproc(name, inconkproc, ip); ! 705: } ! 706: ! 707: /* ! 708: * free all blocks of a message in `q', `bp' is the first block ! 709: * of the message ! 710: */ ! 711: static void ! 712: freemsg(Queue *q, Block *bp) ! 713: { ! 714: for(; bp; bp = getq(q)){ ! 715: if(bp->flags & S_DELIM){ ! 716: freeb(bp); ! 717: return; ! 718: } ! 719: freeb(bp); ! 720: } ! 721: } ! 722: ! 723: static void ! 724: showpkt(char *str, int chan, int ctl, Block *bp, int i) ! 725: { ! 726: int n; ! 727: ! 728: n = bp->wptr - bp->rptr; ! 729: kprint("%s(%d)%uo %d", str, chan, ctl, n); ! 730: if(n > 8) ! 731: n = 8; ! 732: for(; i<n; i++) ! 733: kprint(" %2.2ux", bp->rptr[i]); ! 734: kprint("\n"); ! 735: } ! 736: ! 737: /* ! 738: * output a block ! 739: * ! 740: * the first 2 bytes of every message are the channel number, ! 741: * low order byte first. the third is a possible trailing control ! 742: * character. ! 743: */ ! 744: void ! 745: inconoput(Queue *q, Block *bp) ! 746: { ! 747: int dev; ! 748: Incon *ip; ! 749: ulong end; ! 750: int status, chan, ctl; ! 751: int n, size; ! 752: ! 753: ip = (Incon *)q->ptr; ! 754: ! 755: if(bp->type != M_DATA){ ! 756: if(streamparse("inconset", bp)) ! 757: inconsetctl(ip, bp); ! 758: else ! 759: freeb(bp); ! 760: return; ! 761: } ! 762: if(BLEN(bp) < 3){ ! 763: bp = pullup(bp, 3); ! 764: if(bp == 0){ ! 765: print("inconoput pullup failed\n"); ! 766: return; ! 767: } ! 768: } ! 769: ! 770: /* ! 771: * get a whole message before handing bytes to the device ! 772: */ ! 773: if(!putq(q, bp)) ! 774: return; ! 775: ! 776: /* ! 777: * one transmitter at a time ! 778: */ ! 779: qlock(&ip->xmit); ! 780: dev = ip->dev; ! 781: ! 782: /* ! 783: * parse message ! 784: */ ! 785: bp = getq(q); ! 786: chan = bp->rptr[0] | (bp->rptr[1]<<8); ! 787: ctl = bp->rptr[2]; ! 788: bp->rptr += 3; ! 789: if(chan<=0) ! 790: print("bad channel %d\n", chan); ! 791: ! 792: if(incondebug){ ! 793: kprint("0x%.2ux ", rdstatus(ip)); ! 794: showpkt("->", chan, ctl, bp, 0); ! 795: } ! 796: ! 797: /* ! 798: * make sure there's an incon out there ! 799: */ ! 800: if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){ ! 801: DPRINT("inconoput: not ready"); ! 802: inconrestart(ip); ! 803: freemsg(q, bp); ! 804: qunlock(&ip->xmit); ! 805: return; ! 806: } ! 807: ! 808: /* ! 809: * send the 8 bit data ! 810: */ ! 811: for(;;){ ! 812: /* ! 813: * spin till there is room ! 814: */ ! 815: for(n=0, end = NOW+1000; (status=rdstatus(ip)) & TX_FULL; n++){ ! 816: nop(); /* make sure we don't optimize too much */ ! 817: if(NOW > end){ ! 818: print("incon output stuck 0 %.2ux\n", status); ! 819: freemsg(q, bp); ! 820: qunlock(&ip->xmit); ! 821: return; ! 822: } ! 823: } ! 824: ip->wait = (n + ip->wait)>>1; ! 825: ! 826: /* ! 827: * put in next packet ! 828: */ ! 829: n = bp->wptr - bp->rptr; ! 830: if(n > 16) ! 831: n = 16; ! 832: size = n; ! 833: wrctl(dev, chan); ! 834: ip->out += n; ! 835: while(n--){ ! 836: wrdata(dev, *bp->rptr++); ! 837: } ! 838: ! 839: /* ! 840: * get next block ! 841: */ ! 842: if(bp->rptr >= bp->wptr){ ! 843: if(bp->flags & S_DELIM){ ! 844: freeb(bp); ! 845: break; ! 846: } ! 847: freeb(bp); ! 848: bp = getq(q); ! 849: if(bp==0) ! 850: break; ! 851: } ! 852: ! 853: /* ! 854: * end packet ! 855: */ ! 856: wrctl(dev, 0); ! 857: } ! 858: ! 859: /* ! 860: * send the control byte if there is one ! 861: */ ! 862: if(ctl){ ! 863: if(size >= 16){ ! 864: wrctl(dev, 0); ! 865: for(end = NOW+1000; rdstatus(ip) & TX_FULL;){ ! 866: nop(); /* make sure we don't optimize too much */ ! 867: if(NOW > end){ ! 868: print("incon output stuck 1\n"); ! 869: freemsg(q, bp); ! 870: qunlock(&ip->xmit); ! 871: return; ! 872: } ! 873: } ! 874: wrctl(dev, chan); ! 875: } ! 876: if(rdstatus(ip) & TX_FULL) ! 877: print("inconfull\n"); ! 878: ip->out += 1; ! 879: wrctl(dev, ctl); ! 880: } ! 881: wrctl(dev, 0); ! 882: ! 883: qunlock(&ip->xmit); ! 884: return; ! 885: } ! 886: ! 887: /* ! 888: * return true if the raw fifo is non-empty ! 889: */ ! 890: static int ! 891: notempty(void *arg) ! 892: { ! 893: Incon *ip; ! 894: ! 895: ip = (Incon *)arg; ! 896: return ip->ri!=ip->wi; ! 897: } ! 898: ! 899: /* ! 900: * Read bytes from the raw input circular buffer. ! 901: */ ! 902: static void ! 903: inconkproc(void *arg) ! 904: { ! 905: Incon *ip; ! 906: Block *bp; ! 907: int i; ! 908: int locked; ! 909: ! 910: ip = (Incon *)arg; ! 911: ip->kstarted = 1; ! 912: ! 913: /* ! 914: * create a number of blocks for input ! 915: */ ! 916: for(i = 0; i < Nin; i++){ ! 917: bp = ip->inb[i] = allocb(Bsize); ! 918: bp->wptr += 3; ! 919: } ! 920: ! 921: locked = 0; ! 922: if(waserror()){ ! 923: if(locked) ! 924: qunlock(ip); ! 925: ip->kstarted = 0; ! 926: wakeup(&ip->r); ! 927: return; ! 928: } ! 929: ! 930: for(;;){ ! 931: /* ! 932: * sleep if input fifo empty ! 933: */ ! 934: sleep(&ip->kr, notempty, ip); ! 935: ! 936: /* ! 937: * die if the device is closed ! 938: */ ! 939: USED(locked); ! 940: qlock(ip); ! 941: locked = 1; ! 942: if(ip->rq == 0){ ! 943: qunlock(ip); ! 944: ip->kstarted = 0; ! 945: wakeup(&ip->r); ! 946: poperror(); ! 947: return; ! 948: } ! 949: ! 950: /* ! 951: * send blocks upstream and stage new blocks. ! 952: */ ! 953: while(ip->ri != ip->wi){ ! 954: bp = ip->inb[ip->ri]; ! 955: bp->flags |= S_DELIM; ! 956: ip->in += BLEN(bp); ! 957: PUTNEXT(ip->rq, bp); ! 958: bp = ip->inb[ip->ri] = allocb(Bsize); ! 959: bp->wptr += 3; ! 960: ip->ri = (ip->ri+1)%Nin; ! 961: } ! 962: USED(locked); ! 963: qunlock(ip); ! 964: locked = 0; ! 965: } ! 966: } ! 967: ! 968: /* ! 969: * drop a single packet ! 970: */ ! 971: static void ! 972: droppacket(int dev) ! 973: { ! 974: if(irddata(dev) == 0) ! 975: return; ! 976: while(irdnext(dev)) ! 977: ; ! 978: } ! 979: ! 980: /* ! 981: * flush the input fifo ! 982: */ ! 983: static void ! 984: flushfifo(Incon *ip) ! 985: { ! 986: while(!(irdstatus(ip) & RCV_EMPTY)) ! 987: droppacket(ip->dev); ! 988: } ! 989: ! 990: /* ! 991: * advance the queue. if we've run out of staged input blocks, ! 992: * drop the packet and return 0. otherwise return the next input ! 993: * block to fill. ! 994: */ ! 995: static Block * ! 996: nextin(Incon *ip, unsigned int c) ! 997: { ! 998: Block *bp; ! 999: int next; ! 1000: ! 1001: bp = ip->inb[ip->wi]; ! 1002: bp->rptr[0] = ip->chan; ! 1003: bp->rptr[1] = ip->chan>>8; ! 1004: bp->rptr[2] = c; ! 1005: if(incondebug) ! 1006: showpkt("<-", ip->chan, c, bp, 3); ! 1007: ! 1008: next = (ip->wi+1)%Nin; ! 1009: if(next == ip->ri){ ! 1010: bp->wptr = bp->rptr+3; ! 1011: return bp; ! 1012: } ! 1013: ip->wi = next; ! 1014: ! 1015: return ip->inb[ip->wi]; ! 1016: } ! 1017: ! 1018: /* ! 1019: * read the packets from the device into the staged input blocks. ! 1020: * we have to do this at interrupt tevel to turn off the interrupts. ! 1021: */ ! 1022: static void ! 1023: rdpackets(Incon *ip) ! 1024: { ! 1025: Block *bp; ! 1026: unsigned int c; ! 1027: int dev; ! 1028: uchar *p; ! 1029: int first = ip->wi; ! 1030: ! 1031: dev = ip->dev; ! 1032: bp = ip->inb[ip->wi]; ! 1033: if(bp==0){ ! 1034: flushfifo(ip); ! 1035: return; ! 1036: } ! 1037: p = bp->wptr; ! 1038: while(!(irdstatus(ip) & RCV_EMPTY)){ ! 1039: /* ! 1040: * get channel number ! 1041: */ ! 1042: c = irddata(dev); ! 1043: if(c == 0){ ! 1044: droppacket(dev); ! 1045: continue; ! 1046: } ! 1047: if(ip->chan != c){ ! 1048: if(p - bp->rptr > 3){ ! 1049: bp->wptr = p; ! 1050: bp = nextin(ip, 0); ! 1051: p = bp->wptr; ! 1052: } ! 1053: ip->chan = c; ! 1054: } ! 1055: ! 1056: /* ! 1057: * null byte marks end of packet ! 1058: */ ! 1059: while(c = irdnext(dev)){ /* assign = */ ! 1060: if((c & 0x100) == 0){ ! 1061: /* ! 1062: * control byte ends block ! 1063: */ ! 1064: bp->wptr = p; ! 1065: bp = nextin(ip, c); ! 1066: p = bp->wptr; ! 1067: }else{ ! 1068: /* ! 1069: * data byte, put in local buffer ! 1070: */ ! 1071: *p++ = c; ! 1072: } ! 1073: } ! 1074: ! 1075: /* ! 1076: * pass a block on if it doesn't have room for one more ! 1077: * packet. this way we don't have to check per byte. ! 1078: */ ! 1079: if(p + 16 > bp->lim){ ! 1080: bp->wptr = p; ! 1081: bp = nextin(ip, 0); ! 1082: p = bp->wptr; ! 1083: } ! 1084: } ! 1085: bp->wptr = p; ! 1086: if(bp->wptr != bp->rptr+3) ! 1087: nextin(ip, 0); ! 1088: ! 1089: if(first != ip->wi)/**/ ! 1090: wakeup(&ip->kr); ! 1091: } ! 1092: ! 1093: /* ! 1094: * Receive an incon interrupt. One entry point ! 1095: * for all types of interrupt. Until we figure out ! 1096: * how to use more than one incon, this routine only ! 1097: * is for incon[0]. ! 1098: */ ! 1099: static void ! 1100: inconintr(Ureg *ur, void *a) ! 1101: { ! 1102: uchar status; ! 1103: int pcr; ! 1104: Incon *ip; ! 1105: ! 1106: USED(ur, a); ! 1107: ip = &incon[0]; ! 1108: pcr = inb(ip->dev+Qpcr); ! 1109: if(!(pcr & Fie)) ! 1110: return; ! 1111: status = irdstatus(ip); ! 1112: if(incondebug){ ! 1113: kprint("pcr=%2.2x status=%2.2x\n", pcr, status); ! 1114: if(pcr & Fstrobe) ! 1115: kprint("YIKES!!\n"); ! 1116: } ! 1117: if(!(status & RCV_EMPTY)) ! 1118: rdpackets(ip); ! 1119: ! 1120: /* see if it died underneath us */ ! 1121: if(!(status&INCON_ALIVE)){ ! 1122: switch(ip->state){ ! 1123: case Selected: ! 1124: iwrcmd(ip->dev, INCON_STOP); ! 1125: DPRINT("Incon died\n"); ! 1126: print("Incon died\n"); ! 1127: break; ! 1128: case Selecting: ! 1129: DPRINT("rejected\n"); ! 1130: print("rejected\n"); ! 1131: break; ! 1132: default: ! 1133: iwrcmd(ip->dev, INCON_STOP); ! 1134: DPRINT("state was %d\n", ip->state); ! 1135: break; ! 1136: } ! 1137: ip->state = Notliving; ! 1138: } ! 1139: irdnop(ip->dev, pcr); ! 1140: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.