#include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" #include "../h/tty.h" #include "../h/inode.h" #include "../h/mx.h" #include "../h/file.h" #include "../h/conf.h" #include "../h/buf.h" /* * multiplexor driver */ struct chan chans[NCHANS]; struct group *groups[NGROUPS]; int mpxline; struct chan *xcp(); struct chan *addch(); struct chan *nextcp(); int chzero; short cmask[16] ={ 01, 02, 04, 010, 020, 040, 0100, 0200, 0400, 01000, 02000, 04000, 010000, 020000, 040000, 0100000 }; char mcdebugs[NDEBUGS]; mxopen(dev,flag) { register struct group *gp; register struct file *fp; register struct chan *cp; int d; struct inode *ip; d = minor(dev); if (d>=NGROUPS) { bad: u.u_error = ENXIO; printf("bad mxopen\n"); return; } gp = groups[d]; if (gp->g_state == COPEN) { gp->g_state = INUSE+ISGRP; return; } if (!(gp->g_state&INUSE)) goto bad; fp = u.u_ofile[u.u_r.r_val1]; if (fp->f_inode != gp->g_inode) goto bad; if ((cp=addch(gp->g_inode))==NULL) goto bad; cp->c_flags = XGRP; cp->c_ottyp = cp->c_ittyp = (struct tty *)cp; cp->c_iline = cp->c_oline = mpxline; fp->f_flag |= FMPY; fp->f_flag |= FREAD+FWRITE; fp->f_un.f_chan = cp; cp->c_pgrp = u.u_procp->p_pgrp; #ifdef CTRACE printf("open pgrp %d\n",cp->c_pgrp); #endif scontrol(cp, M_WATCH+(cp->c_index<<8), u.u_uid); sleep((caddr_t)cp,TTIPRI); if (cp->c_flags & WCLOSE) { printf("WCLOSE on %o\n",cp); chfree(cp,0); goto bad; } cp->c_fy = fp; } mxclose(dev,cp) dev_t dev; struct chan *cp; { register i; register struct group *gp; register struct inode *ip; gp = groups[minor(dev)]; ip = gp->g_inode; if (ip==NULL) { if (cp==NULL || (int)cp==FWRITE) printf("bad close gp %o gpi %o ip %o ipg %o\n", gp,gp->g_inode,ip,ip->i_un.i_group); if (cp==NULL) return; } if (cp!=NULL && (int)cp!=FWRITE) { i = cp->c_index; if (!cp->c_flags&WCLOSE) { chfree(cp,1); scontrol(cp, M_CLOSE, 0); printf("x1 close\n"); } else { chfree(cp,0); #ifdef CTRACE printf("WC close\n"); #endif } gp->g_chans[i] = NULL; cp->c_pgrp = 0; cp->c_group = NULL; cp->c_flags |= WCLOSE; return; } if ((ip->i_mode&IFMT)!=IFMPC) { printf("close on inode %o\n",ip); return; } for(i=0;i<NINDEX;i++) { if ((cp=gp->g_chans[i])!=NULL) { if (cp->c_flags&ISGRP) { ((struct group *)cp)->g_state &= ~ISGRP; ((struct group *)cp)->g_group = NULL; continue; } cp->c_flags |= WCLOSE; wakeup((caddr_t)cp); signal(cp->c_pgrp,SIGHUP); chfree(cp,0); if (gp->g_chans[i]) printf("chfree didn't clear inode\n"); } } gp->g_state = NULL; groups[minor(dev)] = NULL; i = ip->i_mode; i &= ~IFMT; i |= IFCHR; ip->i_mode = i; ip->i_flag |= IUPD|ICHG; iput(ip); } mxread(dev) { register struct group *gp; struct clist *q; struct chan *cp; register i; struct file *fp; struct header h; caddr_t base; unsigned count; int s,xfr,more; int esc; i = minor(dev); if (i>=NGROUPS) { u.u_error = ENXIO; return; } gp = groups[i]; fp = getf(u.u_arg[0]); if ((fp->f_flag&FMP)!=FMP) { msread(fp,gp); return; } s = spl6(); while (gp->g_datq == 0) { sleep((caddr_t)&gp->g_datq, TTIPRI); } while (gp->g_datq && u.u_count >= CNTLSIZ) { splx(s); esc = 0; cp = nextcp(gp); if (cp==NULL) { continue; } if (cp->c_ctlx.c_cc) esc = 2; base = u.u_base; count = u.u_count; u.u_base += HDRSIZE + esc; u.u_count -= HDRSIZE + esc; xfr = u.u_count; more = (*linesw[cp->c_iline].l_read)(cp->c_ittyp); if (esc || more > 0) { sdata(cp); } if (more<0) { printf("m<0\n"); printf("x2 close\n"); scontrol(cp, M_CLOSE, 0); } xfr -= u.u_count; if (xfr==0) { u.u_base = base; u.u_count = count; chzero++; continue; } h.index = cpx(cp); if (esc) { h.count = 0; h.ccount = xfr; } else h.count = xfr; if (xfr&1) { u.u_base++; u.u_count--; } copyout(&h, base, HDRSIZE+esc); q = &cp->cx.datq; if (cp->c_flags&BLOCK && esc==0) { if (q->c_cc<25) { wakeup((caddr_t)q+1); cp->c_flags &= ~BLOCK; } else { } } if (cp->c_flags&WFLUSH) wakeup((caddr_t)q+2); s = spl6(); } } mcread(cp) register struct chan *cp; { register struct clist *q; register c; if (cp->c_ctlx.c_cc) q = &cp->c_ctlx; else q = &cp->cx.datq; while( (c=getc(q)) >= 0) { passc(c); } return(q->c_cc); } msread(fp, gp) struct file *fp; struct group *gp; { register struct clist *q; register struct chan *cp; register i; cp = fp->f_un.f_chan; q = (fp->f_flag&FMPX) ? &cp->cx.datq : &cp->cy.datq; i = spl6(); if (!q->c_cc) { if (cp->c_flags&WCLOSE) { printf("ms sees it %o\n",cp); u.u_error = ENXIO; return; } sleep((caddr_t)q,TTIPRI); } splx(i); i = 0; while(u.u_count && q->c_cc) { passc(getc(q)); i++; } if (cp->c_flags&SIGBLK && q->c_cc < 20) { cp->c_flags &= ~SIGBLK; if (cp->c_flags&ENAMSG) scontrol(cp, M_UBLK, 0); else wakeup((caddr_t)q); } if (cp->c_flags&WFLUSH) wakeup((caddr_t)q+2); } mxwrite(dev) { register i; register struct chan *cp; struct header h; struct file *fp; struct group *gp; int ucount; caddr_t ubase; i = minor(dev); if (i>=NGROUPS) { u.u_error = ENXIO; return; } gp = groups[i]; fp = getf(u.u_arg[0]); if ((fp->f_flag&FMP)!=FMP) { ucount = mswrite(fp,gp); return; } while (u.u_count) { iomove(&h, sizeof(struct header), B_WRITE); /* if (count==0) { esc++; h.count = h.ccount; } */ cp = xcp(gp, h.index); if (cp==NULL) { printf("nullo %o %o\n",cp,chans); u.u_count -= h.count; u.u_base += h.count; continue; } ucount = u.u_count; ubase = u.u_base; u.u_count = h.count; u.u_base = h.addr; (*linesw[cp->c_oline].l_write)(cp->c_ottyp); u.u_count = ucount; u.u_base = ubase; } } mcwrite(cp) register struct chan *cp; { register struct clist *q; register c; int s; q = &cp->cy.datq; while ((c=cpass())>=0) { s = spl6(); while (q->c_cc > 100) { cp->c_flags |= SIGBLK; splx(s); if (cp->c_flags&ENAMSG) { scontrol(cp, M_BLK, (short)u.u_count); wakeup((caddr_t)q); while (cpass()>=0); return; } else sleep((caddr_t)q, TTOPRI); } splx(s); putc(c, q); } wakeup((caddr_t)q); } mcttwrite(tp,cc) register struct tty *tp; register cc; { register c; struct chan *cp; if ((tp->t_state&CARR_ON)==0) return; while (cc && (c=cpass())>=0) { spl5(); if (tp->t_outq.c_cc > 10) { ttstart(tp); spl0(); cp = tp->t_chan; cp->c_flags |= SIGBLK; scontrol(cp, M_BLK, cc); while (cc-- && cpass()>=0); return; } spl0(); ttyoutput(c,tp); cc--; } ttstart(tp); } mcttstart(tp) struct tty *tp; { register struct chan *cp; cp = tp->t_chan; if (cp->c_flags&(BLKMSG+ENAMSG)) { cp->c_flags &= ~BLKMSG; scontrol(cp, M_UBLK, 0); } } mswrite(fp,gp) struct file *fp; struct group *gp; { register struct clist *q; struct chan *cp; register c; int cc; cp = fp->f_un.f_chan; q = (fp->f_flag&FMPX) ? &cp->cy.datq : &cp->cx.datq; cc = 0; while((c=cpass())>=0) { spl6(); if (cp->c_flags&WCLOSE) { bad: u.u_error = ENXIO; printf("ms write sees it %o\n",cp); return(cc); } while (q->c_cc>100) { if (cp->c_flags&WCLOSE) goto bad; sdata(cp); /* if (q->c_cc) { printf("choops\n"); sdata(cp); printf("sent\n"); } */ cc = 0; cp->c_flags |= BLOCK; sleep((caddr_t)q+1,TTOPRI); } spl0(); if (putc(c,q)>=0) cc++; else printf("qe\n"); } if (fp->f_flag&FMPX) { if (cp->c_flags&YGRP) sdata(cp); else wakeup((caddr_t)q); } else { if (cp->c_flags&XGRP) sdata(cp); else wakeup((caddr_t)q); } return(cc); } mxioctl(dev, cmd, addr, flag) caddr_t addr; { /* u.u_error = ENOTTY; */ } chfree(cp, flag) register struct chan *cp; { register struct tty *tp; struct group *gp; struct inode *ip; if (chclear(cp)) goto out; tp = cp->c_ittyp; if (tp->t_chan == cp) { cp->c_ittyp = NULL; tp->t_chan = NULL; if (flag && cp->c_iline==0) wflushtty(tp); else flushtty(tp); } if (flag) wflush(cp,&cp->cx.datq); else flush(&cp->cx.datq); if (!(cp->c_flags&YGRP)) { flush(&cp->cy.datq); } cp->c_flags = NULL; out: if (!flag) { gp = cp->c_group; cp->c_group = NULL; ip = gp->g_inode; if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) { printf("chfree on %o\n",ip); return; } gp->g_chans[cp->c_index] = NULL; } } chclear(cp) register struct chan *cp; { register char *p; #ifdef CTRACE register struct file *fp; fp = cp->c_fy; if (fp) { printf(" count %d on cp %o\n",fp->f_count,cp); } #endif p = (char *)&cp->cx.datq; wakeup(p); wakeup(++p); wakeup(++p); p = (char *)&cp->cy.datq; wakeup(p); wakeup(++p); wakeup(++p); return(0); } flush(q) register struct clist *q; { while(q->c_cc) getc(q); } wflush(cp,q) register struct chan *cp; register struct clist *q; { register s; s = spl6(); while(q->c_cc) { if (cp->c_flags & WCLOSE) { flush(q); goto out; } cp->c_flags |= WFLUSH; sdata(cp); sleep((caddr_t)q+2,TTOPRI); } out: cp->c_flags &= ~WFLUSH; splx(s); } scontrol(cp,event,value) register struct chan *cp; short event,value; { register struct clist *q; int s; q = &cp->c_ctlx; s = spl6(); putw(event,q); putw(value,q); splx(s); sdata(cp); } sdata(cp) register struct chan *cp; { register struct group *gp; register short x; register struct group *lgp; int s; gp = cp->c_group; x = cp->c_index; s = spl6(); while (gp) { gp->g_datq |= cmask[x]; x = gp->g_index; lgp = gp; gp = gp->g_group; } gp = lgp; splx(s); wakeup((caddr_t)&gp->g_datq); } struct chan * xcp(gp, x) register struct group *gp; register short x; { register i; i = 0; while (i<NLEVELS && gp->g_state&ISGRP) { gp = (struct group *)gp->g_chans[x&017]; x >>= 4; } return((struct chan *)gp); } cpx(cp) register struct chan *cp; { register x; register struct group *gp; x = cp->c_index; gp = cp->c_group; gp = gp->g_group; while (gp) { x <<= 4; x |= gp->g_index; gp = gp->g_group; } return(x); } struct chan * nextcp(gp) register struct group *gp; { if (gp->g_datq == 0) { gp = NULL; goto out; } while (gp != NULL && gp->g_state&ISGRP) { while ( (gp->g_datq & gp->g_rotmask) == 0) { gp->g_rot++; gp->g_rot &= 017; if (gp->g_rot) gp->g_rotmask <<= 1; else gp->g_rotmask = 1; } gp = (struct group *)gp->g_chans[gp->g_rot]; } if (gp) rmdata(gp); out: return((struct chan *)gp); } rmdata(cp) register struct chan *cp; { register struct group *gp; register short x; gp = cp->c_group; x = cp->c_index; while (gp) { gp->g_datq &= ~cmask[x]; if (gp->g_datq) return; x = gp->g_index; gp = gp->g_group; } } mcrint(c, tp) struct tty *tp; { } mcxint(tp) struct tty *tp; { } prstuff(s,cc) register char *s; register cc; { while (cc--) printf("%o ",*s++&0377); }