home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / sys / dev / mx2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-03  |  13.6 KB  |  916 lines

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