#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" #define KERNEL 1 #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(); #define MIN(a,b) ((a= NGROUPS) return(NULL); return(groups[d]); } mxopen(dev, flag) { register struct group *gp; register struct file *fp; register struct chan *cp; int msg; gp = getmpx(dev); if (gp == NULL) { bad: u.u_error = ENXIO; return; } 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, 0))==NULL) goto bad; cp->c_flags = XGRP; cp->c_ottyp = cp->c_ttyp = (struct tty *)cp; cp->c_line = cp->c_oline = mpxline; fp->f_flag |= FMPY; fp->f_flag |= FREAD+FWRITE; fp->f_un.f_chan = cp; if (gp->g_inode == mpxip) { plock(mpxip); mpxname(cp); msg = M_OPEN; } else msg = M_WATCH; scontrol(cp, msg, u.u_uid); sleep((caddr_t)cp,TTIPRI); if (cp->c_flags&NMBUF) prele(mpxip); if (cp->c_flags & WCLOSE) { chdrain(cp); chfree(cp); goto bad; } cp->c_fy = fp; cp->c_pgrp = u.u_procp->p_pgrp; } char mxnmbuf[NMSIZE]; int nmsize; struct chan *mxnmcp; mpxname(cp) register struct chan *cp; { register char *np; register c; np = mxnmbuf; u.u_dirp = (caddr_t)u.u_arg[0]; while (np < &mxnmbuf[NMSIZE]) { c = uchar(); if (c <= 0) break; *np++ = c; } *np++ = '\0'; nmsize = np - mxnmbuf; cp->c_flags |= NMBUF; } mxclose(dev, flag, cp) dev_t dev; register struct chan *cp; { register struct group *gp; register struct inode *ip; register struct file *fp; int i, fmp; fmp = flag&FMP; /* * close a channel */ if (cp!=NULL && fmp && fmp!=FMP) { for(fp=file; fp < &file[NFILE]; fp++) if(fp->f_count && fp->f_flag&FMP && fp->f_un.f_chan==cp){ return; } chdrain(cp); if ((cp->c_flags&WCLOSE)==0) { scontrol(cp, M_CLOSE, 0); cp->c_flags |= WCLOSE; } else { chfree(cp); } return; } if ((gp = getmpx(dev)) == NULL) return; ip = gp->g_inode; if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) { return; } for(fp=file; fp < &file[NFILE]; fp++) { if (fp->f_count && (fp->f_flag&FMP)==FMP && fp->f_inode==ip) { return; } } if (ip == mpxip) { mpxip = NULL; prele(ip); } for(i=0;ig_chans[i])!=NULL) detach(cp); groups[minor(dev)] = NULL; plock(ip); i = ip->i_mode; i &= ~IFMT; i |= IFCHR; ip->i_mode = i; zero((caddr_t)gp, sizeof (struct group)); ip->i_flag |= IUPD|ICHG; iput(ip); } zero(s, cc) register char *s; register cc; { while (cc--) *s++ = 0; } char m_eot[] ={ M_EOT, 0, 0, 0}; /* * Mxread + mxwrite are entered from cdevsw * for all read/write calls. Operations on * an mpx file are handled here. * Calls are made through linesw to handle actual * data movement. */ mxread(dev) { register struct group *gp; register struct chan *cp; register esc; struct rh h; caddr_t base; unsigned count; int s, xfr, more, fmp; if ((gp=getmpx(dev))==NULL) { bad: u.u_error = ENXIO; return; } FP = getf(u.u_arg[0]); fmp = FP->f_flag & FMP; if (fmp != FMP) { msread(fmp, FP->f_un.f_chan); return; } if ((int)u.u_base & 1) goto bad; s = spl6(); while (gp->g_datq == 0) { sleep((caddr_t)&gp->g_datq, TTIPRI); } while (gp->g_datq && u.u_count >= CNTLSIZ + 2) { splx(s); esc = 0; cp = nextcp(gp); if (cp==NULL) { continue; } h.index = cpx(cp); if (count = cp->c_ctlx.c_cc) { count += CNTLSIZ; if (cp->c_flags&NMBUF) count += nmsize; if (count > u.u_count) { sdata(cp); return; } esc++; } base = u.u_base; count = u.u_count; u.u_base += sizeof h; u.u_count -= sizeof h; xfr = u.u_count; if (esc && cp->c_flags&PORT) { more = mcread(cp); } else { more = (*linesw[cp->c_line].l_read)(cp->c_ttyp); } if (more > 0) sdata(cp); if (more < 0) scontrol(cp, M_CLOSE, 0); if (xfr == u.u_count) { esc++; iomove((caddr_t)m_eot, sizeof m_eot, B_READ); } xfr -= u.u_count; if (esc) { h.count = 0; h.ccount = xfr; } else { h.count = xfr; h.ccount = 0; mxrstrt(cp, &cp->cx.datq, BLOCK|ALT); } if (u.u_count && (xfr&1)) { u.u_base++; u.u_count--; } copyout((caddr_t)&h, base, sizeof h); s = spl6(); } } mxwrite(dev) { register struct chan *cp; struct wh h; struct group *gp; int ucount, esc, fmp, burpcount; caddr_t ubase, hbase; if ((gp=getmpx(dev))==NULL) { u.u_error = ENXIO; return; } FP = getf(u.u_arg[0]); fmp = FP->f_flag & FMP; if (fmp != FMP) { mswrite(fmp, FP->f_un.f_chan); return; } burpcount = 0; while (u.u_count >= sizeof h) { hbase = u.u_base; iomove((caddr_t)&h, sizeof h, B_WRITE); if (u.u_error) return; esc = 0; if (h.count==0) { esc++; h.count = h.ccount; } cp = xcp(gp, h.index); if (cp==NULL) { continue; } ucount = u.u_count; ubase = u.u_base; u.u_count = h.count; u.u_base = h.data; if (esc==0) { struct tty *tp; caddr_t waddr; int line; if (cp->c_flags&PORT) { line = cp->c_line; tp = cp->c_ttyp; } else { line = cp->c_oline; tp = cp->c_ottyp; } loop: waddr = (caddr_t)(*linesw[line].l_write)(tp); if (u.u_count) { if (gp->g_state&ENAMSG) { burpcount++; cp->c_flags |= BLKMSG; /* scontrol(cp, M_BLK, u.u_count); */ h.ccount = -1; h.count = u.u_count; h.data = u.u_base; copyout((caddr_t)&h, hbase, sizeof h); } else { if (waddr==0) { u.u_error = ENXIO; return; } sleep(waddr, TTOPRI); goto loop; } } } else mxwcontrol(cp); u.u_count = ucount; u.u_base = ubase; } u.u_count = burpcount; } /* * Mcread and mcwrite move data on an mpx file. * Transfer addr and length is controlled by mxread/mxwrite. * Kernel-to-Kernel and other special transfers are not * yet in. */ mcread(cp) register struct chan *cp; { register struct clist *q; register char *np; int cc; q = (cp->c_ctlx.c_cc) ? &cp->c_ctlx : &cp->cx.datq; cc = mxmove(q, B_READ); if (cp->c_flags&NMBUF && q == &cp->c_ctlx) { np = mxnmbuf; while (nmsize--) passc(*np++); cp->c_flags &= ~NMBUF; prele(mpxip); } if (cp->c_flags&PORT) return(cp->c_ctlx.c_cc + cp->c_ttyp->t_rawq.c_cc); else return(cp->c_ctlx.c_cc + cp->cx.datq.c_cc); } char * mcwrite(cp) register struct chan *cp; { register struct clist *q; register cc; int s; q = &cp->cy.datq; while (u.u_count) { s = spl6(); if (q->c_cc > HIQ || (cp->c_flags&EOTMARK)) { cp->c_flags |= SIGBLK; splx(s); break; } splx(s); cc = mxmove(q, B_WRITE); } wakeup((caddr_t)q); return((caddr_t)q); } /* * Msread and mswrite move bytes * between user and non-multiplexed channel. */ msread(fmp, cp) register struct chan *cp; { register struct clist *q; int s; q = (fmp&FMPX) ? &cp->cx.datq : &cp->cy.datq; s = spl6(); while (q->c_cc == 0) { if (cp->c_flags & EOTMARK) { cp->c_flags &= ~EOTMARK; if (cp->c_flags&ENAMSG) scontrol(cp, M_UBLK, 0); else { wakeup((caddr_t)cp); wakeup((caddr_t)q); } goto out; } if (cp->c_flags&WCLOSE) { u.u_error = ENXIO; goto out; } sleep((caddr_t)q,TTIPRI); } splx(s); while (mxmove(q, B_READ) > 0) ; mxrstrt(cp, q, SIGBLK); return; out: splx(s); } mswrite(fmp, cp) register struct chan *cp; { register struct clist *q; register int cc; q = (fmp&FMPX) ? &cp->cy.datq : &cp->cx.datq; while (u.u_count) { spl6(); if (cp->c_flags&WCLOSE) { bad: signal(SIGPIPE, cp->c_pgrp); return; } while (q->c_cc>100) { if (cp->c_flags&WCLOSE) goto bad; sdata(cp); cp->c_flags |= BLOCK; sleep((caddr_t)q+1,TTOPRI); } spl0(); cc = mxmove(q, B_WRITE); if (cc < 0) break; } if (fmp&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); } } /* * move chars between clist and user space. */ mxmove(q, dir) register struct clist *q; register dir; { register cc; char buf[HIQ]; cc = MIN(u.u_count, sizeof buf); if (dir == B_READ) cc = q_to_b(q, buf, cc); if (cc <= 0) return(cc); iomove((caddr_t)buf, cc, dir); if (dir == B_WRITE) cc = b_to_q(buf, cc, q); return(cc); } mxrstrt(cp, q, b) register struct chan *cp; register struct clist *q; register b; { int s; s = spl6(); if (cp->c_flags&b && q->c_ccc_flags &= ~b; if (b&ALT) wakeup((caddr_t)q+1); else mcstart(cp, (caddr_t)q); } if (cp->c_flags&WFLUSH) wakeup((caddr_t)q+2); splx(s); } /* * called from driver start or xint routines * to wakeup output sleeper. */ mcstart(cp, q) register struct chan *cp; register caddr_t q; { if (cp->c_flags&(BLKMSG)) { cp->c_flags &= ~BLKMSG; scontrol(cp, M_UBLK, 0); } else wakeup((caddr_t)q); } mxwcontrol(cp) register struct chan *cp; { short cmd[2]; int s; iomove((caddr_t)cmd, sizeof cmd, B_WRITE); switch(cmd[0]) { /* * not ready to queue this up yet. */ case M_EOT: s = spl6(); while (cp->c_flags & EOTMARK) if (cp->c_flags&ENAMSG) { scontrol(cp, M_BLK, 0); goto out; } else sleep((caddr_t)cp, TTOPRI); cp->c_flags |= EOTMARK; out: splx(s); break; case M_IOCTL: printf("M_IOCTL"); break; default: u.u_error = ENXIO; } } mxioctl(dev, cmd, addr, flag) caddr_t addr; { struct group *gp; int fmp; struct file *fp; if ((gp = getmpx(dev)) == NULL) { bad: u.u_error = ENXIO; return; } fp = getf(u.u_arg[0]); if (fp==NULL) goto bad; fmp = fp->f_flag & FMP; if (fmp == FMP) { switch(cmd) { case MXLSTN: if (mpxip == NULL) { mpxip = gp->g_inode; } else goto bad; break; case MXNBLK: gp->g_state |= ENAMSG; break; default: goto bad; } } } chdrain(cp) register struct chan *cp; { register struct tty *tp; int wflag; chwake(cp); wflag = (cp->c_flags&WCLOSE)==0; tp = cp->c_ttyp; if (tp == NULL) /* prob not required */ return; if (cp->c_flags&PORT && tp->t_chan == cp) { cp->c_ttyp = NULL; tp->t_chan = NULL; return; } if (wflag) wflush(cp,&cp->cx.datq); else flush(&cp->cx.datq); if (!(cp->c_flags&YGRP)) { flush(&cp->cy.datq); } } chwake(cp) register struct chan *cp; { register char *p; wakeup((caddr_t)cp); flush(&cp->c_ctlx); p = (char *)&cp->cx.datq; wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p); p = (char *)&cp->cy.datq; wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p); } chfree(cp) register struct chan *cp; { register struct group *gp; register i; gp = cp->c_group; if (gp==NULL) return; i = cp->c_index; if (cp == gp->g_chans[i]) { gp->g_chans[i] = NULL; } cp->c_group = NULL; } 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(); if (sdata(cp) == NULL) return; putw(event,q); putw(value,q); splx(s); } sdata(cp) register struct chan *cp; { register struct group *gp; register short x; register struct group *lgp; int s; gp = cp->c_group; if (gp==NULL) { return(0); } x = cp->c_index; s = spl6(); while (gp) { if ((gp->g_state&ISGRP)==0) { return(0); } 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); return((int)gp); } struct chan * xcp(gp, x) register struct group *gp; register short x; { register i; i = 0; while (ig_state&ISGRP) { gp = (struct group *)gp->g_chans[x&017]; x >>= 4; if ((x&017) >= NINDEX) break; i++; } return((struct chan *)gp); } cpx(cp) register struct chan *cp; { register x; register struct group *gp; if (cp==NULL) return(-1); x = (-1<<4) + cp->c_index; gp = cp->c_group; if (gp==NULL || (gp->g_state&ISGRP)==0) return(-1); gp = gp->g_group; while (gp && gp->g_state&ISGRP) { 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); } prascii(s, cc) register char *s; register cc; { register c; while (cc--) { c = *s++; if (c>=040 && c<=0176) putchar(c); else printf(" %o ", c&0377); } } */