1: /* 2: * SCCS id @(#)mx2.c 2.1 (Berkeley) 8/5/83 3: */ 4: 5: #include "param.h" 6: #include <sys/systm.h> 7: #include <sys/dir.h> 8: #include <sys/user.h> 9: #include <sys/proc.h> 10: #include <sys/tty.h> 11: #include <sys/inode.h> 12: #include <sys/mx.h> 13: #include <sys/file.h> 14: #include <sys/conf.h> 15: #include <sys/buf.h> 16: 17: /* 18: * multiplexor driver 19: */ 20: struct chan chans[NCHANS]; 21: struct group *groups[NGROUPS]; 22: int mpxline; 23: 24: short cmask[16] ={ 25: 01, 02, 04, 26: 010, 020, 040, 27: 0100, 0200, 0400, 28: 01000, 02000, 04000, 29: 010000, 020000, 040000, 0100000 30: }; 31: 32: #define IOMOVE iomove 33: struct chan *xcp(),*addch(),*nextcp(); 34: 35: #define HIQ 100 36: #define LOQ 20 37: #define FP ((struct file *)cp) 38: 39: char mcdebugs[NDEBUGS]; 40: 41: struct group * 42: getmpx(dev) 43: dev_t dev; 44: { 45: register d; 46: 47: d = minor(dev); 48: if (d >= NGROUPS) { 49: u.u_error = ENXIO; 50: return(NULL); 51: } 52: return(groups[d]); 53: } 54: 55: 56: /*ARGSUSED*/ 57: mxopen(dev, flag) 58: { 59: register struct group *gp; 60: register struct file *fp; 61: register struct chan *cp; 62: int msg; 63: 64: if ((gp=getmpx(dev)) == NULL) { 65: return; 66: } 67: if (!(gp->g_state&INUSE)) { 68: u.u_error = ENXIO; 69: return; 70: } 71: fp = u.u_ofile[u.u_r.r_val1]; 72: if (fp->f_inode != gp->g_inode) { 73: u.u_error = ENXIO; 74: return; 75: } 76: if ((cp=addch(gp->g_inode,0)) == NULL) { 77: u.u_error = ENXIO; 78: return; 79: } 80: 81: cp->c_flags = XGRP; 82: cp->c_ottyp = cp->c_ttyp = (struct tty *)cp; 83: cp->c_line = cp->c_oline = mpxline; 84: 85: fp->f_flag |= FMPY; 86: fp->f_flag |= FREAD+FWRITE; 87: fp->f_un.f_chan = cp; 88: 89: if (gp->g_inode == mpxip) { 90: plock(mpxip); 91: mpxname(cp); 92: msg = M_OPEN; 93: } else 94: msg = M_WATCH; 95: 96: scontrol(cp, msg+(cp->c_index<<8), u.u_uid); 97: sleep((caddr_t)cp,TTIPRI); 98: if (cp->c_flags&NMBUF) 99: prele(mpxip); 100: if (cp->c_flags & WCLOSE) { 101: chdrain(cp); 102: chfree(cp); 103: u.u_error = ENXIO; 104: return; 105: } 106: cp->c_fy = fp; 107: cp->c_pgrp = u.u_procp->p_pgrp; 108: } 109: 110: 111: char mxnmbuf[NMSIZE]; 112: int nmsize; 113: 114: mpxname(cp) 115: register struct chan *cp; 116: { 117: register char *np; 118: register c; 119: 120: np = mxnmbuf; 121: u.u_dirp = (caddr_t)u.u_arg[0]; 122: 123: while (np < &mxnmbuf[NMSIZE]) { 124: c = uchar(); 125: if (c <= 0) 126: break; 127: *np++ = c; 128: } 129: *np++ = '\0'; 130: nmsize = np - mxnmbuf; 131: 132: cp->c_flags |= NMBUF; 133: } 134: 135: 136: mxclose(dev, flag, fp) 137: dev_t dev; 138: register struct file *fp; 139: { 140: register struct group *gp; 141: register struct inode *ip; 142: register struct chan *cp = { fp->f_un.f_chan }; 143: int i, fmp; 144: 145: fmp = flag&FMP; 146: if ((gp=getmpx(dev)) == NULL) 147: return; 148: 149: ip = gp->g_inode; 150: if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) { 151: return; 152: } 153: 154: /* 155: * close a channel 156: */ 157: if (cp!=NULL && fmp && fmp!=FMP) { 158: for(fp=file; fp< fileNFILE; fp++) 159: if(fp->f_count && fp->f_flag&FMP && fp->f_un.f_chan==cp){ 160: return; 161: } 162: chdrain(cp); 163: if ((cp->c_flags&WCLOSE)==0) { 164: scontrol(cp, M_CLOSE, 0); 165: cp->c_flags |= WCLOSE; 166: } else { 167: chfree(cp); 168: } 169: goto out; 170: } 171: 172: 173: for(fp=file; fp < fileNFILE; fp++) { 174: if (fp->f_count && (fp->f_flag&FMP)==FMP && fp->f_inode==ip) 175: return; 176: } 177: 178: if (ip == mpxip) { 179: mpxip = NULL; 180: prele(ip); 181: } 182: 183: for(i=0;i<NINDEX;i++) 184: (void) detach(gp->g_chans[i]); 185: 186: out: 187: if (ip->i_count == 1) { 188: groups[minor(dev)] = NULL; 189: plock(ip); 190: zero((caddr_t)gp, sizeof (struct group)); 191: ip->i_mode = IFREG + 0666; 192: ip->i_un.i_rdev = 0; 193: ip->i_flag |= IUPD|ICHG; 194: iput(ip); 195: } 196: } 197: 198: zero(s, cc) 199: register char *s; 200: register cc; 201: { 202: while (cc--) 203: *s++ = 0; 204: } 205: 206: char m_eot[] ={ M_EOT, 0, 0, 0}; 207: 208: /* 209: * Mxread + mxwrite are entered from cdevsw 210: * for all read/write calls. Operations on 211: * an mpx file are handled here. 212: * Calls are made through linesw to handle actual 213: * data movement. 214: */ 215: mxread(dev) 216: { 217: register struct group *gp; 218: register struct chan *cp; 219: register esc; 220: struct rh h; 221: caddr_t base; 222: unsigned count; 223: int s, xfr, more, fmp; 224: 225: if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) { 226: u.u_error = ENXIO; 227: return; 228: } 229: 230: fmp = FP->f_flag & FMP; 231: if (fmp != FMP) { 232: if (u.u_count == 0) 233: return; 234: msread(fmp, FP->f_un.f_chan); 235: return; 236: } 237: 238: if ((int)u.u_base & 1) { 239: u.u_error = ENXIO; 240: return; 241: } 242: 243: s = spl6(); 244: if (u.u_count == 0) 245: { 246: if (gp->g_datq == 0) 247: u.u_error = ENXIO; 248: splx(s); 249: return; 250: } 251: while (gp->g_datq == 0) { 252: sleep((caddr_t)&gp->g_datq, TTIPRI); 253: } 254: splx(s); 255: 256: while (gp->g_datq && u.u_count >= CNTLSIZ + 2) { 257: esc = 0; 258: cp = nextcp(gp); 259: if (cp==NULL) { 260: continue; 261: } 262: h.index = cpx(cp); 263: if (count = cp->c_ctlx.c_cc) { 264: count += CNTLSIZ; 265: if (cp->c_flags&NMBUF) 266: count += nmsize; 267: if (count > u.u_count) { 268: (void) sdata(cp); 269: return; 270: } 271: esc++; 272: } 273: base = u.u_base; 274: count = u.u_count; 275: u.u_base += sizeof h; 276: u.u_count -= sizeof h; 277: xfr = u.u_count; 278: if (esc) { 279: more = mcread(cp); 280: } else { 281: more = (*linesw[cp->c_line].l_read)(cp->c_ttyp); 282: } 283: if (more > 0) 284: (void) sdata(cp); 285: if (more < 0) 286: scontrol(cp, M_CLOSE, 0); 287: (void) _spl0(); 288: if (xfr == u.u_count) { 289: esc++; 290: IOMOVE((caddr_t)m_eot, sizeof m_eot, B_READ); 291: } 292: xfr -= u.u_count; 293: if (esc) { 294: h.count = 0; 295: h.ccount = xfr; 296: } else { 297: h.count = xfr; 298: h.ccount = 0; 299: mxrstrt(cp, &cp->cx.datq, BLOCK|ALT); 300: } 301: if (u.u_count && (xfr&1)) { 302: u.u_base++; 303: u.u_count--; 304: } 305: (void) copyout((caddr_t)&h, base, sizeof h); 306: 307: } 308: } 309: 310: 311: mxwrite(dev) 312: { 313: register struct chan *cp; 314: struct wh h; 315: struct group *gp; 316: int ucount, esc, fmp, burpcount; 317: caddr_t ubase, hbase; 318: 319: if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) { 320: return; 321: } 322: fmp = FP->f_flag & FMP; 323: if (fmp != FMP) { 324: mswrite(fmp, FP->f_un.f_chan); 325: return; 326: } 327: 328: burpcount = 0; 329: while (u.u_count >= sizeof h) { 330: hbase = u.u_base; 331: IOMOVE((caddr_t)&h, sizeof h, B_WRITE); 332: if (u.u_error) 333: return; 334: esc = 0; 335: if (h.count==0) { 336: esc++; 337: h.count = h.ccount; 338: } 339: cp = xcp(gp, h.index); 340: if (cp==NULL || cp->c_flags&ISGRP) { 341: u.u_error = ENXIO; 342: return; 343: } 344: ucount = u.u_count; 345: ubase = u.u_base; 346: u.u_count = h.count; 347: u.u_base = h.data; 348: 349: if (esc==0) { 350: struct tty *tp; 351: caddr_t waddr; 352: int line; 353: 354: if (cp->c_flags&PORT) { 355: line = cp->c_line; 356: tp = cp->c_ttyp; 357: } else { 358: line = cp->c_oline; 359: tp = cp->c_ottyp; 360: } 361: loop: 362: waddr = (caddr_t)(*linesw[line].l_write)(tp); 363: if (u.u_count) { 364: if (gp->g_state&ENAMSG) { 365: burpcount++; 366: cp->c_flags |= BLKMSG; 367: /* 368: scontrol(cp, M_BLK, u.u_count); 369: */ 370: h.ccount = -1; 371: h.count = u.u_count; 372: h.data = u.u_base; 373: (void) copyout((caddr_t)&h, hbase, sizeof h); 374: } else { 375: if(waddr == 0) { 376: u.u_error = ENXIO; 377: return; 378: } 379: sleep(waddr, TTOPRI); 380: goto loop; 381: } 382: } 383: } else { 384: mxwcontrol(cp); 385: } 386: u.u_count = ucount; 387: u.u_base = ubase; 388: } 389: u.u_count = burpcount; 390: } 391: 392: 393: 394: /* 395: * Mcread and mcwrite move data on an mpx file. 396: * Transfer addr and length is controlled by mxread/mxwrite. 397: * Kernel-to-Kernel and other special transfers are not 398: * yet in. 399: */ 400: mcread(cp) 401: register struct chan *cp; 402: { 403: register struct clist *q; 404: register char *np; 405: 406: 407: q = (cp->c_ctlx.c_cc) ? &cp->c_ctlx : &cp->cx.datq; 408: (void) mxmove(q, B_READ); 409: 410: if (cp->c_flags&NMBUF && q == &cp->c_ctlx) { 411: np = mxnmbuf; 412: while (nmsize--) 413: (void) passc(*np++); 414: cp->c_flags &= ~NMBUF; 415: prele(mpxip); 416: } 417: if (cp->c_flags&PORT) 418: return(cp->c_ctlx.c_cc + cp->c_ttyp->t_rawq.c_cc); else 419: return(cp->c_ctlx.c_cc + cp->cx.datq.c_cc); 420: 421: } 422: 423: 424: caddr_t 425: mcwrite(cp) 426: register struct chan *cp; 427: { 428: register struct clist *q; 429: int s; 430: 431: q = &cp->cy.datq; 432: while (u.u_count) { 433: s = spl6(); 434: if (q->c_cc > HIQ || (cp->c_flags&EOTMARK)) { 435: cp->c_flags |= SIGBLK; 436: splx(s); 437: break; 438: } 439: splx(s); 440: (void) mxmove(q, B_WRITE); 441: } 442: wakeup((caddr_t)q); 443: return((caddr_t)q); 444: } 445: 446: 447: /* 448: * Msread and mswrite move bytes 449: * between user and non-multiplexed channel. 450: */ 451: msread(fmp, cp) 452: register struct chan *cp; 453: { 454: register struct clist *q; 455: int s; 456: 457: q = (fmp&FMPX) ? &cp->cx.datq : &cp->cy.datq; 458: s = spl6(); 459: while (q->c_cc == 0) { 460: if (cp->c_flags&WCLOSE) { 461: u.u_error = ENXIO; 462: goto out; 463: } 464: if (cp->c_flags & EOTMARK) { 465: cp->c_flags &= ~EOTMARK; 466: if(msgenab(cp)) 467: scontrol(cp, M_UBLK, 0); 468: else { 469: wakeup((caddr_t)cp); 470: wakeup((caddr_t)q); 471: } 472: goto out; 473: } 474: sleep((caddr_t)q,TTIPRI); 475: } 476: if (cp->c_flags&WCLOSE) { 477: u.u_error = ENXIO; 478: goto out; 479: } 480: splx(s); 481: while (mxmove(q, B_READ) > 0) 482: ; 483: mxrstrt(cp, q, SIGBLK); 484: return; 485: out: 486: splx(s); 487: } 488: 489: 490: mswrite(fmp, cp) 491: register struct chan *cp; 492: { 493: register struct clist *q; 494: register int cc; 495: 496: q = (fmp&FMPX) ? &cp->cy.datq : &cp->cx.datq; 497: while (u.u_count) { 498: (void) _spl6(); 499: if (cp->c_flags&WCLOSE) { 500: gsignal(cp->c_pgrp, SIGPIPE); 501: (void) _spl0(); 502: return; 503: } 504: if (q->c_cc>= HIQ || cp->c_flags&FBLOCK) { 505: if (cp->c_flags&WCLOSE) { 506: gsignal(cp->c_pgrp, SIGPIPE); 507: (void) _spl0(); 508: return; 509: } 510: (void) sdata(cp); 511: cp->c_flags |= BLOCK; 512: sleep((caddr_t)q+1,TTOPRI); 513: (void) _spl0(); 514: continue; 515: } 516: (void) _spl0(); 517: cc = mxmove(q, B_WRITE); 518: if (cc < 0) 519: break; 520: } 521: if (fmp&FMPX) { 522: if (cp->c_flags&YGRP) (void) sdata(cp); 523: else wakeup((caddr_t)q); 524: } else { 525: if (cp->c_flags&XGRP) (void) sdata(cp); 526: else wakeup((caddr_t)q); 527: } 528: } 529: 530: 531: /* 532: * move chars between clist and user space. 533: */ 534: 535: mxmove(q, dir) 536: register struct clist *q; 537: register dir; 538: { 539: register cc; 540: char cbuf[HIQ]; 541: 542: cc = MIN(u.u_count, sizeof cbuf); 543: if (dir == B_READ) 544: cc = q_to_b(q, cbuf, cc); 545: if (cc <= 0) 546: return(cc); 547: IOMOVE((caddr_t)cbuf, (unsigned)cc, dir); 548: if (dir == B_WRITE) 549: cc = b_to_q(cbuf, cc, q); 550: return(cc); 551: } 552: 553: 554: 555: mxrstrt(cp, q, b) 556: register struct chan *cp; 557: register struct clist *q; 558: register b; 559: { 560: int s; 561: 562: s = spl6(); 563: if (cp->c_flags&b && q->c_cc<LOQ) { 564: cp->c_flags &= ~b; 565: if (b&ALT) 566: wakeup((caddr_t)q+1); else 567: mcstart(cp, (caddr_t)q); 568: } 569: if (cp->c_flags&WFLUSH) 570: wakeup((caddr_t)q+2); 571: splx(s); 572: } 573: 574: 575: 576: /* 577: * called from driver start or xint routines 578: * to wakeup output sleeper. 579: */ 580: mcstart(cp, q) 581: register struct chan *cp; 582: register caddr_t q; 583: { 584: 585: if (cp->c_flags&(BLKMSG)) { 586: cp->c_flags &= ~BLKMSG; 587: scontrol(cp, M_UBLK, 0); 588: } else 589: wakeup((caddr_t)q); 590: } 591: 592: 593: mxwcontrol(cp) 594: register struct chan *cp; 595: { 596: short cmd; 597: struct sgttyb vec; 598: int s; 599: 600: IOMOVE((caddr_t)&cmd, sizeof cmd, B_WRITE); 601: if (u.u_error) 602: return; 603: switch(cmd) { 604: /* 605: * not ready to queue this up yet. 606: */ 607: case M_EOT: 608: s = spl6(); 609: while (cp->c_flags & EOTMARK) 610: if(msgenab(cp)){ 611: scontrol(cp, M_BLK, 0); 612: goto out; 613: } else 614: sleep((caddr_t)cp, TTOPRI); 615: cp->c_flags |= EOTMARK; 616: out: 617: wakeup((caddr_t)&cp->cy.datq); 618: splx(s); 619: break; 620: case M_IOCTL: 621: break; 622: case M_IOANS: 623: if (cp->c_flags&SIOCTL) { 624: IOMOVE((caddr_t)&vec, sizeof vec, B_WRITE); 625: (void) b_to_q((caddr_t)&vec, sizeof vec, &cp->c_ctly); 626: cp->c_flags &= ~SIOCTL; 627: wakeup((caddr_t)cp); 628: } 629: break; 630: case M_BLK: 631: cp->c_flags |= FBLOCK; 632: break; 633: case M_UBLK: 634: cp->c_flags &= ~FBLOCK; 635: chwake(cp); 636: break; 637: default: 638: u.u_error = ENXIO; 639: } 640: } 641: 642: 643: 644: /*ARGSUSED*/ 645: mxioctl(dev, cmd, addr, flag) 646: caddr_t addr; 647: { 648: struct group *gp; 649: int fmp; 650: struct file *fp; 651: struct { 652: short c_ctl; 653: short c_cmd; 654: struct sgttyb c_vec; 655: } ctlbuf; 656: 657: if ((gp=getmpx(dev))==NULL || (fp=getf(u.u_arg[0]))==NULL) { 658: return; 659: } 660: 661: fmp = fp->f_flag & FMP; 662: if (fmp == FMP) { 663: switch(cmd) { 664: 665: case MXLSTN: 666: if (mpxip == NULL) { 667: mpxip = gp->g_inode; 668: } else { 669: u.u_error = ENXIO; 670: return; 671: } 672: break; 673: 674: case MXNBLK: 675: gp->g_state |= ENAMSG; 676: break; 677: 678: default: 679: u.u_error = ENXIO; 680: return; 681: } 682: } else { 683: ctlbuf.c_ctl = M_IOCTL; 684: ctlbuf.c_cmd = cmd; 685: (void) copyin(addr, (caddr_t)&ctlbuf.c_vec, sizeof (struct sgttyb)); 686: sioctl(fp->f_un.f_chan, (char *)&ctlbuf, sizeof ctlbuf); 687: (void) copyout((caddr_t)&ctlbuf, addr, sizeof (struct sgttyb)); 688: } 689: } 690: 691: 692: chdrain(cp) 693: register struct chan *cp; 694: { 695: register struct tty *tp; 696: int wflag; 697: 698: chwake(cp); 699: 700: wflag = (cp->c_flags&WCLOSE)==0; 701: tp = cp->c_ttyp; 702: if (tp == NULL) /* prob not required */ 703: return; 704: if (cp->c_flags&PORT && tp->t_chan == cp) { 705: cp->c_ttyp = NULL; 706: tp->t_chan = NULL; 707: return; 708: } 709: if (wflag) 710: wflush(cp,&cp->cx.datq); else 711: flush(&cp->cx.datq); 712: if (!(cp->c_flags&YGRP)) { 713: flush(&cp->cy.datq); 714: } 715: } 716: 717: chwake(cp) 718: register struct chan *cp; 719: { 720: register char *p; 721: 722: wakeup((caddr_t)cp); 723: flush(&cp->c_ctlx); 724: p = (char *)&cp->cx.datq; 725: wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p); 726: p = (char *)&cp->cy.datq; 727: wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p); 728: } 729: 730: 731: chfree(cp) 732: register struct chan *cp; 733: { 734: register struct group *gp; 735: register i; 736: 737: gp = cp->c_group; 738: if (gp==NULL) 739: return; 740: i = cp->c_index; 741: if (cp == gp->g_chans[i]) { 742: gp->g_chans[i] = NULL; 743: } 744: cp->c_group = NULL; 745: wakeup((caddr_t)gp); 746: } 747: 748: 749: flush(q) 750: register struct clist *q; 751: { 752: 753: while(q->c_cc) 754: (void) getc(q); 755: } 756: 757: 758: wflush(cp,q) 759: register struct chan *cp; 760: register struct clist *q; 761: { 762: register s; 763: 764: s = spl6(); 765: if(q->c_cc && (cp->c_flags&WCLOSE) == 0) { 766: cp->c_flags |= WFLUSH; 767: (void) sdata(cp); 768: sleep((caddr_t)q+2, TTOPRI); 769: } 770: flush(q); 771: cp->c_flags &= ~WFLUSH; 772: splx(s); 773: } 774: 775: 776: scontrol(cp,event,value) 777: register struct chan *cp; 778: short event,value; 779: { 780: register struct clist *q; 781: int s; 782: 783: q = &cp->c_ctlx; 784: s = spl6(); 785: if (sdata(cp) == NULL) 786: return; 787: (void) putw(event,q); 788: (void) putw(value,q); 789: splx(s); 790: } 791: 792: 793: 794: sioctl(cp, vec, cc) 795: register struct chan *cp; 796: char *vec; 797: { 798: register s; 799: register struct clist *q; 800: 801: s = spl6(); 802: q = &cp->cx.datq; 803: while (q->c_cc) { 804: cp->c_flags |= BLOCK; 805: if (sdata(cp)==NULL) { 806: u.u_error = ENXIO; 807: return; 808: } 809: sleep((caddr_t)q+1, TTOPRI); 810: } 811: (void) b_to_q(vec, cc, &cp->c_ctlx); 812: cp->c_flags |= SIOCTL; 813: while (cp->c_flags&SIOCTL) { 814: if (cp->c_ctlx.c_cc) 815: if (sdata(cp)==NULL) { 816: u.u_error = ENXIO; 817: return; 818: } 819: sleep((caddr_t)cp, TTOPRI); 820: } 821: (void) q_to_b(&cp->c_ctly, vec, cp->c_ctly.c_cc); 822: splx(s); 823: } 824: 825: sdata(cp) 826: struct chan *cp; 827: { 828: register struct group *gp = (struct group *)cp; 829: register struct group *ngp; 830: register int s; 831: 832: ngp = gp->g_group; 833: if (ngp==NULL || (ngp->g_state&ISGRP)==0) 834: return(NULL); 835: 836: s = spl6(); 837: do { 838: ngp->g_datq |= cmask[gp->g_index]; 839: wakeup((caddr_t)&ngp->g_datq); 840: gp = ngp; 841: } while(ngp=ngp->g_group); 842: splx(s); 843: return((int)gp); 844: } 845: 846: 847: 848: struct chan * 849: xcp(gp, x) 850: register struct group *gp; 851: register short x; 852: { 853: register int i; 854: 855: while (gp->g_group) gp=gp->g_group; 856: for (i=0;i<NLEVELS;i++) { 857: if ((x&017) >= NINDEX) 858: break; 859: if (gp==NULL || (gp->g_state&ISGRP)==0) 860: return((struct chan *)NULL); 861: gp = (struct group *)gp->g_chans[x&017]; 862: x >>= 4; 863: } 864: return((struct chan *)gp); 865: } 866: 867: cpx(cp) 868: register struct chan *cp; 869: { 870: register x; 871: register struct group *gp; 872: 873: x = (-1<<4) + cp->c_index; 874: gp = cp->c_group; 875: while (gp->g_group) { 876: x <<= 4; 877: x |= gp->g_index; 878: gp = gp->g_group; 879: } 880: return(x); 881: } 882: 883: 884: struct chan * 885: nextcp(gp) 886: register struct group *gp; 887: { 888: register struct group *lgp, *ngp; 889: 890: do { 891: while ((gp->g_datq & cmask[gp->g_rot]) == 0) { 892: gp->g_rot = (gp->g_rot+1)%NINDEX; 893: } 894: lgp = gp; 895: gp = (struct group *)gp->g_chans[gp->g_rot]; 896: } while (gp!=NULL && gp->g_state&ISGRP); 897: 898: lgp->g_datq &= ~cmask[lgp->g_rot]; 899: lgp->g_rot = (lgp->g_rot+1)%NINDEX; 900: 901: while (ngp=lgp->g_group) { 902: ngp->g_datq &= ~cmask[lgp->g_index]; 903: if (ngp->g_datq) 904: break; 905: lgp = ngp; 906: } 907: return((struct chan *)gp); 908: } 909: 910: 911: 912: msgenab(cp) 913: register struct chan *cp; 914: { 915: register struct group *gp; 916: 917: for(gp=cp->c_group;gp;gp=gp->g_group) 918: if(gp->g_state & ENAMSG)return(1); 919: return(0); 920: }