|
|
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 "io.h" ! 7: #include "../port/error.h" ! 8: ! 9: #include "devtab.h" ! 10: ! 11: /* ! 12: * Driver for the Z8530. ! 13: */ ! 14: enum ! 15: { ! 16: /* wr 0 */ ! 17: ResExtPend= 2<<3, ! 18: ResTxPend= 5<<3, ! 19: ResErr= 6<<3, ! 20: ! 21: /* wr 1 */ ! 22: ExtIntEna= 1<<0, ! 23: TxIntEna= 1<<1, ! 24: RxIntDis= 0<<3, ! 25: RxIntFirstEna= 1<<3, ! 26: RxIntAllEna= 2<<3, ! 27: ! 28: /* wr 3 */ ! 29: RxEna= 1, ! 30: Rx5bits= 0<<6, ! 31: Rx7bits= 1<<6, ! 32: Rx6bits= 2<<6, ! 33: Rx8bits= 3<<6, ! 34: Rxbitmask= 3<<6, ! 35: ! 36: /* wr 4 */ ! 37: ParEven= 3<<0, ! 38: ParOdd= 1<<0, ! 39: ParOff= 0<<0, ! 40: ParMask= 3<<0, ! 41: SyncMode= 0<<2, ! 42: Rx1stop= 1<<2, ! 43: Rx1hstop= 2<<2, ! 44: Rx2stop= 3<<2, ! 45: X16= 1<<6, ! 46: ! 47: /* wr 5 */ ! 48: TxRTS= 1<<1, ! 49: TxEna= 1<<3, ! 50: TxBreak= 1<<4, ! 51: TxDTR= 1<<7, ! 52: Tx5bits= 0<<5, ! 53: Tx7bits= 1<<5, ! 54: Tx6bits= 2<<5, ! 55: Tx8bits= 3<<5, ! 56: Txbitmask= 3<<5, ! 57: ! 58: /* wr 9 */ ! 59: IntEna= 1<<3, ! 60: ResetB= 1<<6, ! 61: ResetA= 2<<6, ! 62: HardReset= 3<<6, ! 63: ! 64: /* wr 11 */ ! 65: TRxCOutBR= 2, ! 66: TxClockTRxC= 1<<3, ! 67: TxClockBR= 2<<3, ! 68: RxClockTRxC= 1<<5, ! 69: RxClockBR= 2<<5, ! 70: TRxCOI= 1<<2, ! 71: ! 72: /* wr 14 */ ! 73: BREna= 1, ! 74: BRSource= 2, ! 75: ! 76: /* rr 0 */ ! 77: RxReady= 1, ! 78: TxReady= 1<<2, ! 79: RxDCD= 1<<3, ! 80: RxCTS= 1<<5, ! 81: RxBreak= 1<<7, ! 82: ! 83: /* rr 3 */ ! 84: ExtPendB= 1, ! 85: TxPendB= 1<<1, ! 86: RxPendB= 1<<2, ! 87: ExtPendA= 1<<3, ! 88: TxPendA= 1<<4, ! 89: RxPendA= 1<<5, ! 90: }; ! 91: ! 92: typedef struct SCC SCC; ! 93: struct SCC ! 94: { ! 95: QLock; ! 96: ushort sticky[16]; /* sticky write register values */ ! 97: uchar* ptr; /* command/pointer register in Z8530 */ ! 98: uchar* data; /* data register in Z8530 */ ! 99: int printing; /* true if printing */ ! 100: ulong freq; /* clock frequency */ ! 101: uchar mask; /* bits/char */ ! 102: ! 103: /* console interface */ ! 104: int special; /* can't use the stream interface */ ! 105: IOQ* iq; /* input character queue */ ! 106: IOQ* oq; /* output character queue */ ! 107: ! 108: /* stream interface */ ! 109: Queue* wq; /* write queue */ ! 110: Rendez r; /* kproc waiting for input */ ! 111: int kstarted; /* kproc started */ ! 112: ! 113: /* idiot flow control */ ! 114: int xonoff; /* true if we obey this tradition */ ! 115: int blocked; /* abstinence */ ! 116: }; ! 117: ! 118: int invrtsdtr; /* set to 1 on indigo's */ ! 119: int nscc; ! 120: SCC *scc[8]; /* up to 4 8530's */ ! 121: #define CTLS 023 ! 122: #define CTLQ 021 ! 123: ! 124: #ifdef Zduart ! 125: #define SCCTYPE 'z' ! 126: #define onepointseven() ! 127: #else ! 128: #define SCCTYPE 't' ! 129: void ! 130: onepointseven(void) ! 131: { ! 132: int i; ! 133: for(i = 0; i < 20; i++) ! 134: ; ! 135: } ! 136: #endif ! 137: ! 138: /* ! 139: * Access registers using the pointer in register 0. ! 140: * This is a bit stupid when accessing register 0. ! 141: */ ! 142: void ! 143: sccwrreg(SCC *sp, int addr, int value) ! 144: { ! 145: onepointseven(); ! 146: *sp->ptr = addr; ! 147: wbflush(); ! 148: onepointseven(); ! 149: *sp->ptr = sp->sticky[addr] | value; ! 150: wbflush(); ! 151: } ! 152: ushort ! 153: sccrdreg(SCC *sp, int addr) ! 154: { ! 155: onepointseven(); ! 156: *sp->ptr = addr; ! 157: wbflush(); ! 158: onepointseven(); ! 159: return *sp->ptr; ! 160: } ! 161: ! 162: /* ! 163: * set the baud rate by calculating and setting the baudrate ! 164: * generator constant. This will work with fairly non-standard ! 165: * baud rates. ! 166: */ ! 167: void ! 168: sccsetbaud(SCC *sp, int rate) ! 169: { ! 170: int brconst; ! 171: ! 172: if(rate == 0) ! 173: error(Ebadctl); ! 174: ! 175: brconst = (sp->freq+16*rate-1)/(2*16*rate) - 2; ! 176: ! 177: sccwrreg(sp, 12, brconst & 0xff); ! 178: sccwrreg(sp, 13, (brconst>>8) & 0xff); ! 179: } ! 180: ! 181: void ! 182: sccparity(SCC *sp, char type) ! 183: { ! 184: int val; ! 185: ! 186: switch(type){ ! 187: case 'e': ! 188: val = ParEven; ! 189: break; ! 190: case 'o': ! 191: val = ParOdd; ! 192: break; ! 193: default: ! 194: val = ParOff; ! 195: break; ! 196: } ! 197: sp->sticky[4] = (sp->sticky[4] & ~ParMask) | val; ! 198: sccwrreg(sp, 4, 0); ! 199: } ! 200: ! 201: /* ! 202: * set bits/character, default 8 ! 203: */ ! 204: void ! 205: sccbits(SCC *sp, int n) ! 206: { ! 207: int rbits, tbits; ! 208: ! 209: switch(n){ ! 210: case 5: ! 211: sp->mask = 0x1f; ! 212: rbits = Rx5bits; ! 213: tbits = Tx5bits; ! 214: break; ! 215: case 6: ! 216: sp->mask = 0x3f; ! 217: rbits = Rx6bits; ! 218: tbits = Tx6bits; ! 219: break; ! 220: case 7: ! 221: sp->mask = 0x7f; ! 222: rbits = Rx7bits; ! 223: tbits = Tx7bits; ! 224: break; ! 225: case 8: ! 226: default: ! 227: sp->mask = 0xff; ! 228: rbits = Rx8bits; ! 229: tbits = Tx8bits; ! 230: break; ! 231: } ! 232: sp->sticky[3] = (sp->sticky[3]&~Rxbitmask) | rbits; ! 233: sccwrreg(sp, 3, 0); ! 234: sp->sticky[5] = (sp->sticky[5]&~Txbitmask) | tbits; ! 235: sccwrreg(sp, 5, 0); ! 236: } ! 237: ! 238: /* ! 239: * set/clear external clock mode; the indigo uses the CTS pin, ! 240: * so we disable external interrupts. ! 241: */ ! 242: void ! 243: sccextclk(SCC *sp, int n) ! 244: { ! 245: if(n){ ! 246: sp->sticky[1] &= ~ExtIntEna; ! 247: sp->sticky[11] = TxClockTRxC | RxClockTRxC; ! 248: }else{ ! 249: sp->sticky[1] |= ExtIntEna; ! 250: sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR; ! 251: } ! 252: sccwrreg(sp, 1, 0); ! 253: sccwrreg(sp, 11, 0); ! 254: } ! 255: ! 256: /* ! 257: * toggle DTR ! 258: */ ! 259: void ! 260: sccdtr(SCC *sp, int n) ! 261: { ! 262: if((n!=0)^invrtsdtr) ! 263: sp->sticky[5] |= TxDTR; ! 264: else ! 265: sp->sticky[5] &=~TxDTR; ! 266: sccwrreg(sp, 5, 0); ! 267: } ! 268: ! 269: /* ! 270: * toggle RTS ! 271: */ ! 272: void ! 273: sccrts(SCC *sp, int n) ! 274: { ! 275: if((n!=0)^invrtsdtr) ! 276: sp->sticky[5] |= TxRTS; ! 277: else ! 278: sp->sticky[5] &=~TxRTS; ! 279: sccwrreg(sp, 5, 0); ! 280: } ! 281: ! 282: /* ! 283: * send break ! 284: */ ! 285: void ! 286: sccbreak(SCC *sp, int ms) ! 287: { ! 288: if(ms == 0) ! 289: ms = 100; ! 290: sp->sticky[1] &=~TxIntEna; ! 291: sccwrreg(sp, 1, 0); ! 292: sccwrreg(sp, 5, TxBreak|TxEna); ! 293: tsleep(&u->p->sleep, return0, 0, ms); ! 294: sccwrreg(sp, 5, 0); ! 295: if(sp->oq){ ! 296: sp->sticky[1] |= TxIntEna; ! 297: sccwrreg(sp, 1, 0); ! 298: } ! 299: } ! 300: ! 301: /* ! 302: * set number of stop bits ! 303: */ ! 304: void ! 305: sccnstop(SCC *sp, char code) ! 306: { ! 307: sp->sticky[4] &=~Rx2stop; ! 308: switch(code){ ! 309: default: ! 310: sp->sticky[4] |= Rx1stop; ! 311: break; ! 312: case 'h': ! 313: sp->sticky[4] |= Rx1hstop; ! 314: break; ! 315: case '2': ! 316: sp->sticky[4] |= Rx2stop; ! 317: break; ! 318: } ! 319: sccwrreg(sp, 4, 0); ! 320: } ! 321: ! 322: /* ! 323: * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts, ! 324: * transmit and receive enabled, interrupts disabled. ! 325: */ ! 326: static void ! 327: sccsetup0(SCC *sp, int brsource) ! 328: { ! 329: memset(sp->sticky, 0, sizeof(sp->sticky)); ! 330: ! 331: /* ! 332: * turn on baud rate generator and set rate to 9600 baud. ! 333: * use 1 stop bit. ! 334: */ ! 335: sp->sticky[14] = brsource ? BRSource : 0; ! 336: sccwrreg(sp, 14, 0); ! 337: sccsetbaud(sp, 9600); ! 338: sp->sticky[4] = Rx1stop | X16; ! 339: sccwrreg(sp, 4, 0); ! 340: sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR /*| TRxCOI*/; ! 341: sccwrreg(sp, 11, 0); ! 342: sp->sticky[14] = BREna; ! 343: if(brsource) ! 344: sp->sticky[14] |= BRSource; ! 345: sccwrreg(sp, 14, 0); ! 346: ! 347: /* ! 348: * enable I/O, 8 bits/character ! 349: */ ! 350: sp->sticky[3] = RxEna | Rx8bits; ! 351: sccwrreg(sp, 3, 0); ! 352: sp->sticky[5] = TxEna | Tx8bits; ! 353: sccwrreg(sp, 5, 0); ! 354: sp->mask = 0xff; ! 355: } ! 356: ! 357: void ! 358: sccsetup(void *addr, ulong freq, int brsource) ! 359: { ! 360: SCCdev *dev; ! 361: SCC *sp; ! 362: ! 363: dev = addr; ! 364: ! 365: /* ! 366: * allocate a structure, set port addresses, and setup the line ! 367: */ ! 368: sp = xalloc(sizeof(SCC)); ! 369: scc[nscc] = sp; ! 370: sp->ptr = &dev->ptra; ! 371: sp->data = &dev->dataa; ! 372: sp->freq = freq; ! 373: sccsetup0(sp, brsource); ! 374: sp = xalloc(sizeof(SCC)); ! 375: scc[nscc+1] = sp; ! 376: sp->ptr = &dev->ptrb; ! 377: sp->data = &dev->datab; ! 378: sp->freq = freq; ! 379: sccsetup0(sp, brsource); ! 380: nscc += 2; ! 381: } ! 382: ! 383: void ! 384: sccputc(int port, char ch) ! 385: { ! 386: SCC *sp; ! 387: ! 388: sp = scc[port]; ! 389: for(;;) { ! 390: onepointseven(); ! 391: if(*sp->ptr & TxReady) ! 392: break; ! 393: } ! 394: onepointseven(); ! 395: *sp->data = ch; ! 396: } ! 397: ! 398: int ! 399: iprint(char *fmt, ...) ! 400: { ! 401: int n, i; ! 402: char buf[512]; ! 403: ! 404: n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; ! 405: for(i = 0; i < n; i++) ! 406: sccputc(1, buf[i]); ! 407: return n; ! 408: } ! 409: ! 410: /* ! 411: * Queue n characters for output; if queue is full, we lose characters. ! 412: * Get the output going if it isn't already. ! 413: */ ! 414: void ! 415: sccputs(IOQ *cq, char *s, int n) ! 416: { ! 417: SCC *sp = cq->ptr; ! 418: int ch, x; ! 419: ! 420: x = splhi(); ! 421: lock(cq); ! 422: puts(cq, s, n); ! 423: if(sp->printing == 0 && sp->blocked==0){ ! 424: ch = getc(cq); ! 425: /*kprint("<start %2.2ux>", ch);*/ ! 426: if(ch >= 0){ ! 427: sp->printing = 1; ! 428: while((*sp->ptr&TxReady)==0) ! 429: ; ! 430: *sp->data = ch; ! 431: } ! 432: } ! 433: unlock(cq); ! 434: splx(x); ! 435: } ! 436: ! 437: /* ! 438: * an scc interrupt (a damn lot of work for one character) ! 439: */ ! 440: void ! 441: sccintr0(SCC *sp, uchar x) ! 442: { ! 443: int ch; ! 444: IOQ *cq; ! 445: ! 446: if(x & ExtPendB){ ! 447: sccwrreg(sp, 0, ResExtPend); ! 448: } ! 449: if(x & RxPendB){ ! 450: cq = sp->iq; ! 451: while(*sp->ptr&RxReady){ ! 452: onepointseven(); ! 453: ch = *sp->data & sp->mask; ! 454: if (ch == CTLS && sp->xonoff) ! 455: sp->blocked = 1; ! 456: else if (ch == CTLQ && sp->xonoff) { ! 457: sp->blocked = 0; ! 458: sccputs(sp->oq, "", 0); ! 459: } ! 460: if(cq->putc) ! 461: (*cq->putc)(cq, ch); ! 462: else ! 463: putc(cq, ch); ! 464: } ! 465: } ! 466: if(x & TxPendB){ ! 467: if (sp->blocked) { ! 468: sccwrreg(sp, 0, ResTxPend); ! 469: sp->printing = 0; ! 470: return; ! 471: } ! 472: cq = sp->oq; ! 473: lock(cq); ! 474: ch = getc(cq); ! 475: onepointseven(); ! 476: if(ch < 0){ ! 477: sccwrreg(sp, 0, ResTxPend); ! 478: sp->printing = 0; ! 479: wakeup(&cq->r); ! 480: }else ! 481: *sp->data = ch; ! 482: unlock(cq); ! 483: } ! 484: } ! 485: ! 486: int ! 487: sccintr(void) ! 488: { ! 489: uchar x; ! 490: int i, j; ! 491: ! 492: for(i = j = 0; i < nscc; i += 2){ ! 493: x = sccrdreg(scc[i], 3); ! 494: if(x & (ExtPendB|RxPendB|TxPendB)) ! 495: ++j, sccintr0(scc[i+1], x); ! 496: x = x >> 3; ! 497: if(x & (ExtPendB|RxPendB|TxPendB)) ! 498: ++j, sccintr0(scc[i], x); ! 499: } ! 500: return j; ! 501: } ! 502: ! 503: void ! 504: sccclock(void) ! 505: { ! 506: SCC *sp; ! 507: IOQ *cq; ! 508: int i; ! 509: ! 510: for(i = 0; i < nscc; i++){ ! 511: sp = scc[i]; ! 512: cq = sp->iq; ! 513: if(sp->wq && cangetc(cq)) ! 514: wakeup(&cq->r); ! 515: } ! 516: } ! 517: ! 518: /* ! 519: * turn on a port's interrupts. set DTR and RTS ! 520: */ ! 521: void ! 522: sccenable(SCC *sp) ! 523: { ! 524: /* ! 525: * set up i/o routines ! 526: */ ! 527: if(sp->oq){ ! 528: sp->oq->puts = sccputs; ! 529: sp->oq->ptr = sp; ! 530: sp->sticky[1] |= TxIntEna | ExtIntEna; ! 531: } ! 532: if(sp->iq){ ! 533: sp->iq->ptr = sp; ! 534: sp->sticky[1] |= RxIntAllEna | ExtIntEna; ! 535: } ! 536: ! 537: /* ! 538: * turn on interrupts ! 539: */ ! 540: sccwrreg(sp, 1, 0); ! 541: sp->sticky[9] |= IntEna; ! 542: sccwrreg(sp, 9, 0); ! 543: ! 544: /* ! 545: * turn on DTR and RTS ! 546: */ ! 547: sccdtr(sp, 1); ! 548: sccrts(sp, 1); ! 549: } ! 550: ! 551: /* ! 552: * set up an scc port as something other than a stream ! 553: */ ! 554: void ! 555: sccspecial(int port, IOQ *oq, IOQ *iq, int baud) ! 556: { ! 557: SCC *sp = scc[port]; ! 558: ! 559: /* let output drain */ ! 560: if(sp->oq){ ! 561: while(cangetc(sp->oq)) ! 562: sleep(&sp->oq->r, cangetc, sp->oq); ! 563: tsleep(&sp->oq->r, cangetc, sp->oq, 50); ! 564: } ! 565: ! 566: sp->special = 1; ! 567: sp->oq = oq; ! 568: sp->iq = iq; ! 569: sccenable(sp); ! 570: if(baud) ! 571: sccsetbaud(sp, baud); ! 572: ! 573: if(iq){ ! 574: /* ! 575: * Stupid HACK to undo a stupid hack ! 576: */ ! 577: if(iq == &kbdq) ! 578: kbdq.putc = kbdcr2nl; ! 579: } ! 580: } ! 581: ! 582: void ! 583: sccrawput(int port, int c) ! 584: { ! 585: SCC *sp = scc[port]; ! 586: ! 587: if(c == '\n') { ! 588: sccrawput(port, '\r'); ! 589: delay(100); ! 590: } ! 591: ! 592: while((*sp->ptr&TxReady)==0) ! 593: ; ! 594: *sp->data = c; ! 595: } ! 596: ! 597: static void sccstopen(Queue*, Stream*); ! 598: static void sccstclose(Queue*); ! 599: static void sccoput(Queue*, Block*); ! 600: static void scckproc(void *); ! 601: Qinfo sccinfo = ! 602: { ! 603: nullput, ! 604: sccoput, ! 605: sccstopen, ! 606: sccstclose, ! 607: "scc" ! 608: }; ! 609: ! 610: static void ! 611: sccstopen(Queue *q, Stream *s) ! 612: { ! 613: SCC *sp; ! 614: char name[NAMELEN]; ! 615: ! 616: kprint("sccstopen: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n", ! 617: q, s->inuse, s->type, s->dev, s->id); ! 618: sp = scc[s->id]; ! 619: qlock(sp); ! 620: sp->wq = WR(q); ! 621: WR(q)->ptr = sp; ! 622: RD(q)->ptr = sp; ! 623: qunlock(sp); ! 624: ! 625: if(sp->kstarted == 0){ ! 626: sp->kstarted = 1; ! 627: sprint(name, "scc%d", s->id); ! 628: kproc(name, scckproc, sp); ! 629: } ! 630: } ! 631: ! 632: static void ! 633: sccstclose(Queue *q) ! 634: { ! 635: SCC *sp = q->ptr; ! 636: ! 637: if(sp->special) ! 638: return; ! 639: ! 640: qlock(sp); ! 641: sp->wq = 0; ! 642: sp->iq->putc = 0; ! 643: WR(q)->ptr = 0; ! 644: RD(q)->ptr = 0; ! 645: qunlock(sp); ! 646: } ! 647: ! 648: static void ! 649: sccoput(Queue *q, Block *bp) ! 650: { ! 651: SCC *sp = q->ptr; ! 652: IOQ *cq; ! 653: int n, m; ! 654: ! 655: if(sp == 0){ ! 656: freeb(bp); ! 657: return; ! 658: } ! 659: cq = sp->oq; ! 660: if(waserror()){ ! 661: freeb(bp); ! 662: nexterror(); ! 663: } ! 664: if(bp->type == M_CTL){ ! 665: if(*bp->rptr == '!') /* do it now! */ ! 666: ++bp->rptr; ! 667: else while(cangetc(cq)) /* else let output drain */ ! 668: sleep(&cq->r, cangetc, cq); ! 669: n = strtoul((char *)(bp->rptr+1), 0, 0); ! 670: switch(*bp->rptr){ ! 671: case 'B': ! 672: case 'b': ! 673: if(BLEN(bp)>4 && strncmp((char*)(bp->rptr+1), "reak", 4) == 0) ! 674: sccbreak(sp, 0); ! 675: else ! 676: sccsetbaud(sp, n); ! 677: break; ! 678: case 'C': ! 679: case 'c': ! 680: sccextclk(sp, n); ! 681: break; ! 682: case 'D': ! 683: case 'd': ! 684: sccdtr(sp, n); ! 685: break; ! 686: case 'L': ! 687: case 'l': ! 688: sccbits(sp, n); ! 689: break; ! 690: ! 691: case 'P': ! 692: case 'p': ! 693: sccparity(sp, *(bp->rptr+1)); ! 694: break; ! 695: case 'K': ! 696: case 'k': ! 697: sccbreak(sp, n); ! 698: break; ! 699: case 'R': ! 700: case 'r': ! 701: sccrts(sp, n); ! 702: break; ! 703: case 'S': ! 704: case 's': ! 705: sccnstop(sp, *(bp->rptr+1)); ! 706: break; ! 707: case 'W': ! 708: case 'w': ! 709: /* obsolete */ ! 710: break; ! 711: case 'X': ! 712: case 'x': ! 713: sp->xonoff = n; ! 714: break; ! 715: } ! 716: }else while((m = BLEN(bp)) > 0){ ! 717: while ((n = canputc(cq)) == 0){ ! 718: kprint(" sccoput: sleeping\n"); ! 719: sleep(&cq->r, canputc, cq); ! 720: } ! 721: if(n > m) ! 722: n = m; ! 723: (*cq->puts)(cq, bp->rptr, n); ! 724: bp->rptr += n; ! 725: } ! 726: freeb(bp); ! 727: poperror(); ! 728: } ! 729: ! 730: /* ! 731: * process to send bytes upstream for a port ! 732: */ ! 733: static void ! 734: scckproc(void *a) ! 735: { ! 736: SCC *sp = a; ! 737: IOQ *cq = sp->iq; ! 738: Block *bp; ! 739: int n; ! 740: ! 741: loop: ! 742: while ((n = cangetc(cq)) == 0) ! 743: sleep(&cq->r, cangetc, cq); ! 744: /*kprint(" scckproc: %d\n", n);*/ ! 745: qlock(sp); ! 746: if(sp->wq == 0){ ! 747: cq->out = cq->in; ! 748: }else{ ! 749: bp = allocb(n); ! 750: bp->flags |= S_DELIM; ! 751: bp->wptr += gets(cq, bp->wptr, n); ! 752: PUTNEXT(RD(sp->wq), bp); ! 753: } ! 754: qunlock(sp); ! 755: goto loop; ! 756: } ! 757: ! 758: Dirtab *sccdir; ! 759: ! 760: /* ! 761: * create 2 directory entries for each 'sccsetup' ports. ! 762: * allocate the queues if no one else has. ! 763: */ ! 764: void ! 765: sccreset(void) ! 766: { ! 767: SCC *sp; ! 768: int i; ! 769: Dirtab *dp; ! 770: ! 771: sccdir = xalloc(2 * nscc * sizeof(Dirtab)); ! 772: dp = sccdir; ! 773: for(i = 0; i < nscc; i++){ ! 774: /* 2 directory entries per port */ ! 775: sprint(dp->name, "eia%d", i); ! 776: dp->qid.path = STREAMQID(i, Sdataqid); ! 777: dp->perm = 0666; ! 778: dp++; ! 779: sprint(dp->name, "eia%dctl", i); ! 780: dp->qid.path = STREAMQID(i, Sctlqid); ! 781: dp->perm = 0666; ! 782: dp++; ! 783: ! 784: /* set up queues if a stream port */ ! 785: sp = scc[i]; ! 786: if(sp->special) ! 787: continue; ! 788: sp->iq = xalloc(sizeof(IOQ)); ! 789: initq(sp->iq); ! 790: sp->oq = xalloc(sizeof(IOQ)); ! 791: initq(sp->oq); ! 792: sccenable(sp); ! 793: } ! 794: } ! 795: ! 796: void ! 797: sccinit(void) ! 798: { ! 799: } ! 800: ! 801: Chan* ! 802: sccattach(char *spec) ! 803: { ! 804: return devattach(SCCTYPE, spec); ! 805: } ! 806: ! 807: Chan* ! 808: sccclone(Chan *c, Chan *nc) ! 809: { ! 810: return devclone(c, nc); ! 811: } ! 812: ! 813: int ! 814: sccwalk(Chan *c, char *name) ! 815: { ! 816: return devwalk(c, name, sccdir, 2*nscc, devgen); ! 817: } ! 818: ! 819: void ! 820: sccstat(Chan *c, char *dp) ! 821: { ! 822: int i; ! 823: ! 824: i = STREAMID(c->qid.path); ! 825: switch(STREAMTYPE(c->qid.path)){ ! 826: case Sdataqid: ! 827: streamstat(c, dp, sccdir[2*i].name, sccdir[2*i].perm); ! 828: break; ! 829: default: ! 830: devstat(c, dp, sccdir, 2*nscc, devgen); ! 831: break; ! 832: } ! 833: } ! 834: ! 835: Chan* ! 836: sccopen(Chan *c, int omode) ! 837: { ! 838: SCC *sp; ! 839: ! 840: if(c->qid.path != CHDIR){ ! 841: sp = scc[STREAMID(c->qid.path)]; ! 842: if(sp->special) ! 843: error(Einuse); ! 844: streamopen(c, &sccinfo); ! 845: } ! 846: return devopen(c, omode, sccdir, 2*nscc, devgen); ! 847: } ! 848: ! 849: void ! 850: scccreate(Chan *c, char *name, int omode, ulong perm) ! 851: { ! 852: USED(c, name, omode, perm); ! 853: error(Eperm); ! 854: } ! 855: ! 856: void ! 857: sccclose(Chan *c) ! 858: { ! 859: if(c->stream) ! 860: streamclose(c); ! 861: } ! 862: ! 863: long ! 864: sccread(Chan *c, void *buf, long n, ulong offset) ! 865: { ! 866: char b[8]; ! 867: ! 868: if(c->qid.path == CHDIR) ! 869: return devdirread(c, buf, n, sccdir, 2*nscc, devgen); ! 870: ! 871: switch(STREAMTYPE(c->qid.path)){ ! 872: case Sdataqid: ! 873: return streamread(c, buf, n); ! 874: case Sctlqid: ! 875: sprint(b, "%d", STREAMID(c->qid.path)); ! 876: return readstr(offset, buf, n, b); ! 877: } ! 878: error(Egreg); ! 879: return 0; /* not reached */ ! 880: } ! 881: ! 882: long ! 883: sccwrite(Chan *c, void *va, long n, ulong offset) ! 884: { ! 885: USED(offset); ! 886: return streamwrite(c, va, n, 0); ! 887: } ! 888: ! 889: void ! 890: sccremove(Chan *c) ! 891: { ! 892: USED(c); ! 893: error(Eperm); ! 894: } ! 895: ! 896: void ! 897: sccwstat(Chan *c, char *dp) ! 898: { ! 899: USED(c, dp); ! 900: error(Eperm); ! 901: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.