Research V7 development
authorDennis Ritchie <dmr@research.uucp>
Mon, 14 May 1979 03:18:18 +0000 (22:18 -0500)
committerDennis Ritchie <dmr@research.uucp>
Mon, 14 May 1979 03:18:18 +0000 (22:18 -0500)
Work on file usr/sys/dev/mx2.c

Synthesized-from: v7

usr/sys/dev/mx2.c [new file with mode: 0644]

diff --git a/usr/sys/dev/mx2.c b/usr/sys/dev/mx2.c
new file mode 100644 (file)
index 0000000..cd93315
--- /dev/null
@@ -0,0 +1,915 @@
+#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<b)?a:b)
+short  cmask[16]       ={
+       01,     02,     04,
+       010,    020,    040,
+       0100,   0200,   0400,
+       01000,  02000,  04000,
+       010000, 020000, 040000, 0100000
+};
+
+#define        HIQ     100
+#define        LOQ     20
+#define        FP      ((struct file *)cp)
+
+
+
+char mcdebugs[NDEBUGS];
+
+/*
+ * Timing cell
+ */
+int    mxdummy;
+int    *MP     = &mxdummy;
+
+
+
+struct group *
+getmpx(dev)
+dev_t dev;
+{
+register d;
+
+       d = minor(dev);
+       if (d >= 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;i<NINDEX;i++)
+               if ((cp=gp->g_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_cc<LOQ) {
+               cp->c_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 (i<NLEVELS && gp->g_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);
+       }
+}
+*/