BSD 4_1_snap development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 21 Mar 1981 00:46:33 +0000 (16:46 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 21 Mar 1981 00:46:33 +0000 (16:46 -0800)
Work on file sys/dev/bk.c
Work on file sys/dev/flp.c
Work on file sys/dev/dsort.c
Work on file sys/dev/dkleave.c
Work on file sys/dev/mem.c
Work on file sys/dev/mx1.c
Work on file sys/dev/sw.c

Synthesized-from: CSRG/cd1/4.1.snap

sys/dev/bk.c [new file with mode: 0644]
sys/dev/dkleave.c [new file with mode: 0644]
sys/dev/dsort.c [new file with mode: 0644]
sys/dev/flp.c [new file with mode: 0644]
sys/dev/mem.c [new file with mode: 0644]
sys/dev/mx1.c [new file with mode: 0644]
sys/dev/sw.c [new file with mode: 0644]

diff --git a/sys/dev/bk.c b/sys/dev/bk.c
new file mode 100644 (file)
index 0000000..ad5f14d
--- /dev/null
@@ -0,0 +1,167 @@
+/*     bk.c    4.6     81/03/11        */
+
+#include "bk.h"
+
+#if NBK > 0
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/tty.h"
+#include "../h/proc.h"
+#include "../h/mx.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+/*
+ * Line discipline for Berkeley network.
+ *
+ * This supplies single lines to a user level program
+ * with a minimum of fuss.  Lines are newline terminated.
+ *
+ * This discipline requires that tty device drivers call
+ * the line specific l_ioctl routine from their ioctl routines,
+ * assigning the result to cmd so that we can refuse most tty specific
+ * ioctls which are unsafe because we have ambushed the
+ * teletype input queues, overlaying them with other information.
+ */
+
+/*
+ * Open as networked discipline.  Called when discipline changed
+ * with ioctl, this assigns a buffer to the line for input, and
+ * changing the interpretation of the information in the tty structure.
+ */
+/*ARGSUSED*/
+bkopen(dev, tp)
+dev_t dev;
+register struct tty *tp;
+{
+       register struct buf *bp;
+
+       if (u.u_error)
+               return;         /* paranoia */
+       if (tp->t_line == NETLDISC) {
+               u.u_error = EBUSY;              /* sometimes the network */
+               return;                         /* ... opens /dev/tty */
+       }
+       bp = geteblk();
+       flushtty(tp, FREAD|FWRITE);
+       tp->t_bufp = bp;
+       tp->t_cp = (char *)bp->b_un.b_addr;
+       tp->t_inbuf = 0;
+       tp->t_rec = 0;
+}
+
+/*
+ * Break down... called when discipline changed or from device
+ * close routine.
+ */
+bkclose(tp)
+register struct tty *tp;
+{
+       register s;
+
+       s = spl5();
+       wakeup((caddr_t)&tp->t_rawq);
+       if (tp->t_bufp) {
+               brelse(tp->t_bufp);
+               tp->t_bufp = 0;
+       } else
+               printf("bkclose: no buf\n");
+       tp->t_cp = 0;
+       tp->t_inbuf = 0;
+       tp->t_rec = 0;
+       tp->t_line = 0;         /* paranoid: avoid races */
+       splx(s);
+}
+
+/*
+ * Read from a network line.
+ * Characters have been buffered in a system buffer and are
+ * now dumped back to the user in one fell swoop, and with a
+ * minimum of fuss.  Note that no input is accepted when a record
+ * is waiting.  Our clearing tp->t_rec here allows further input
+ * to accumulate.
+ */
+bkread(tp)
+register struct tty *tp;
+{
+       register int i;
+       register s;
+
+       if ((tp->t_state&CARR_ON)==0)
+               return (-1);
+       s = spl5();
+       while (tp->t_rec == 0 && tp->t_line == NETLDISC)
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       splx(s);
+       if (tp->t_line != NETLDISC)
+               return (-1);
+       i = MIN(tp->t_inbuf, (int)u.u_count);
+       if (copyout(tp->t_bufp->b_un.b_addr, u.u_base, (unsigned)i)) {
+               u.u_error = EFAULT;
+               return (-1);
+       }
+       u.u_count -= i;
+       u.u_base += i;
+       u.u_offset += i;
+       tp->t_cp = (char *)tp->t_bufp->b_un.b_addr;
+       tp->t_inbuf = 0;
+       tp->t_rec = 0;
+       return (0);
+}
+
+/*
+ * Low level character input routine.
+ * Stuff the character in the buffer, and wake up the top
+ * half after setting t_rec if this completes the record
+ * or if the buffer is (ick!) full.
+ *
+ * Thisis where the formatting should get done to allow
+ * 8 character data paths through escapes.
+ *
+ * This rutine should be expanded in-line in the receiver
+ * interrupt routine of the dh-11 to make it run as fast as possible.
+ */
+bkinput(c, tp)
+register c;
+register struct tty *tp;
+{
+
+       if (tp->t_rec)
+               return;
+       *tp->t_cp++ = c;
+       if (++tp->t_inbuf == BSIZE || c == '\n') {
+               tp->t_rec = 1;
+               wakeup((caddr_t)&tp->t_rawq);
+       }
+}
+
+/*
+ * This routine is called whenever a ioctl is about to be performed
+ * and gets a chance to reject the ioctl.  We reject all teletype
+ * oriented ioctl's except those which set the discipline, and
+ * those which get parameters (gtty and get special characters).
+ */
+/*ARGSUSED*/
+bkioctl(tp, cmd, addr)
+struct tty *tp;
+caddr_t addr;
+{
+
+       if ((cmd>>8) != 't')
+               return (cmd);
+       switch (cmd) {
+
+       case TIOCSETD:
+       case TIOCGETD:
+       case TIOCGETP:
+       case TIOCGETC:
+               return (cmd);
+       }
+       u.u_error = ENOTTY;
+       return (0);
+}
+#endif
diff --git a/sys/dev/dkleave.c b/sys/dev/dkleave.c
new file mode 100644 (file)
index 0000000..709d28e
--- /dev/null
@@ -0,0 +1,33 @@
+/*     dkleave.c       4.2     81/03/08        */
+
+#ifdef INTRLVE
+#include "../h/param.h"
+#include "../h/buf.h"
+
+daddr_t
+dkblock(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       if (((dminor=minor(bp->b_dev))&0100) == 0)
+               return(bp->b_blkno);
+       dminor >>= 3;
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno/dminor);
+}
+
+dkunit(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       dminor = minor(bp->b_dev) >> 3;
+       if ((dminor&010) == 0)
+               return(dminor);
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno%dminor);
+}
+#endif
diff --git a/sys/dev/dsort.c b/sys/dev/dsort.c
new file mode 100644 (file)
index 0000000..b8f4190
--- /dev/null
@@ -0,0 +1,102 @@
+/*     dsort.c 4.3     81/03/08        */
+
+/*
+ * Seek sort for disks.  We depend on the driver
+ * which calls us using b_resid as the current cylinder number.
+ *
+ * The argument dp structure holds a b_actf activity chain pointer
+ * on which we keep two queues, sorted in ascending cylinder order.
+ * The first queue holds those requests which are positioned after
+ * the current cylinder (in the first request); the second holds
+ * requests which came in after their cylinder number was passed.
+ * Thus we implement a one way scan, retracting after reaching the
+ * end of the drive to the first request on the second queue,
+ * at which time it becomes the first queue.
+ *
+ * A one-way scan is natural because of the way UNIX read-ahead
+ * blocks are allocated.
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+
+#define        b_cylin b_resid
+
+disksort(dp, bp)
+       register struct buf *dp, *bp;
+{
+       register struct buf *ap;
+
+       /*
+        * If nothing on the activity queue, then
+        * we become the only thing.
+        */
+       ap = dp->b_actf;
+       if(ap == NULL) {
+               dp->b_actf = bp;
+               dp->b_actl = bp;
+               bp->av_forw = NULL;
+               return;
+       }
+       /*
+        * If we lie after the first (currently active)
+        * request, then we must locate the second request list
+        * and add ourselves to it.
+        */
+       if (bp->b_cylin < ap->b_cylin) {
+               while (ap->av_forw) {
+                       /*
+                        * Check for an ``inversion'' in the
+                        * normally ascending cylinder numbers,
+                        * indicating the start of the second request list.
+                        */
+                       if (ap->av_forw->b_cylin < ap->b_cylin) {
+                               /*
+                                * Search the second request list
+                                * for the first request at a larger
+                                * cylinder number.  We go before that;
+                                * if there is no such request, we go at end.
+                                */
+                               do {
+                                       if (bp->b_cylin < ap->av_forw->b_cylin)
+                                               goto insert;
+                                       ap = ap->av_forw;
+                               } while (ap->av_forw);
+                               goto insert;            /* after last */
+                       }
+                       ap = ap->av_forw;
+               }
+               /*
+                * No inversions... we will go after the last, and
+                * be the first request in the second request list.
+                */
+               goto insert;
+       }
+       /*
+        * Request is at/after the current request...
+        * sort in the first request list.
+        */
+       while (ap->av_forw) {
+               /*
+                * We want to go after the current request
+                * if there is an inversion after it (i.e. it is
+                * the end of the first request list), or if
+                * the next request is a larger cylinder than our request.
+                */
+               if (ap->av_forw->b_cylin < ap->b_cylin ||
+                   bp->b_cylin < ap->av_forw->b_cylin)
+                       goto insert;
+               ap = ap->av_forw;
+       }
+       /*
+        * Neither a second list nor a larger
+        * request... we go at the end of the first list,
+        * which is the same as the end of the whole schebang.
+        */
+insert:
+       bp->av_forw = ap->av_forw;
+       ap->av_forw = bp;
+       if (ap == dp->b_actl)
+               dp->b_actl = bp;
+}
diff --git a/sys/dev/flp.c b/sys/dev/flp.c
new file mode 100644 (file)
index 0000000..869f652
--- /dev/null
@@ -0,0 +1,267 @@
+/*     flp.c   4.5     81/03/08        */
+
+#if VAX780
+#include "../h/flp.h"
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/mtpr.h"
+#include "../h/buf.h"
+#include "../h/cons.h"
+#include "../h/cpu.h"
+
+struct {
+       short   fl_state;               /* open and busy flags */
+       short   fl_active;              /* driver state flag */
+       struct  buf *fl_buf;            /* buffer we're using */
+       unsigned char *fl_xaddr;        /* transfer address */
+       short   fl_errcnt;
+} fltab;
+
+/*ARGSUSED*/
+flopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       struct buf *geteblk();
+
+#if VAX750
+       if (cpu != VAX_780) {
+               u.u_error = ENXIO;
+               return;
+       }
+#endif
+       if (fltab.fl_state != 0) {
+               u.u_error = ENXIO;
+               return;
+       }
+       fltab.fl_state = FL_OPEN;
+       fltab.fl_buf = geteblk();
+       fltab.fl_active = FL_IDLE;
+}
+
+/*ARGSUSED*/
+flclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+
+       brelse(fltab.fl_buf);
+       fltab.fl_state = 0;
+}
+
+flstrategy(rw)
+       int rw;
+{
+       register struct buf *bp;
+       register unsigned i;
+
+       /*
+        * Assume one block read/written for each call - 
+        * and enforce this by checking for block size of 128.
+        * Use the b_blkno field to address
+        * physical, 128-byte blocks (u.u_offset/128).
+        * This is checked for validity, and is further interpreted as:
+        *
+        *      track# * (sectors/track) + sector #
+        */
+       if (u.u_count == 0) 
+               return;
+       (void) spl4();
+       while (fltab.fl_state & FL_BUSY)
+               sleep((caddr_t)&fltab, PRIBIO);
+       fltab.fl_state |= FL_BUSY;
+       (void) spl0();
+
+       bp = fltab.fl_buf;
+       while ((i = min(RXBYSEC, u.u_count)) != 0) {
+               bp->b_blkno = u.u_offset>>7;
+               if (bp->b_blkno >= MAXSEC || (u.u_offset & 0177) != 0) {
+                       /* block number out of range */
+                       /* or offset in middle of block */
+                       u.u_error = ENXIO;
+                       break;  
+               }
+               if (rw == B_WRITE) {
+                       iomove(bp->b_un.b_addr, i, B_WRITE);
+                       if (u.u_error != 0)
+                               break;
+               }
+               bp->b_flags = rw;
+               (void) spl4(); 
+               flstart();
+               while ((bp->b_flags & B_DONE) == 0)
+                       sleep((caddr_t)bp, PRIBIO);     
+               (void) spl0();
+               if (bp->b_flags & B_ERROR) {
+                       u.u_error = EIO;
+                       break;
+               }
+               if (rw == B_READ) {
+                       iomove(bp->b_un.b_addr, i, B_READ);
+                       if (u.u_error != 0)
+                               break;
+               }
+       }
+       u.u_count = bp->b_resid;
+       fltab.fl_state &= ~FL_BUSY;
+       wakeup((caddr_t)&fltab);
+}
+
+/*ARGSUSED*/
+flread(dev)
+       dev_t dev;
+{
+
+       flstrategy(B_READ);
+}
+
+/*ARGSUSED*/
+flwrite(dev)
+       dev_t dev;
+{
+
+       flstrategy(B_WRITE);
+}
+
+flstart()
+{
+       register struct buf *bp;
+
+       bp = fltab.fl_buf;
+       fltab.fl_active = FL_MAND;
+       fltab.fl_errcnt = 0;
+       fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
+       bp->b_resid = 0;
+       bp->b_bcount = RXBYSEC; /* always transfer a full sector */
+
+       if ((mfpr(TXCS) & TXCS_RDY) == 0)
+               /* not ready to receive order */
+               return;
+       /*
+        * Wake up floppy LSI software with command
+        */
+       fltab.fl_active = FL_SEC;
+       if ((bp->b_flags&B_READ) == B_READ)
+               mtpr(TXDB, FL_RS);
+       else
+               mtpr(TXDB, FL_WS);
+}
+
+/*
+ * See if we want to transmit something
+ * to the floppy - and do it
+ */
+conxfl()
+{
+       register int databyte;
+       register struct buf *bp;
+
+       bp = fltab.fl_buf;
+       switch (fltab.fl_active) {
+
+       case FL_MAND:           /* send command */
+               if ((bp->b_flags&B_READ) == B_READ)
+                       mtpr(TXDB,FL_RS);
+               else
+                       mtpr(TXDB,  FL_WS);
+               fltab.fl_active = FL_SEC;
+               break;
+
+       case FL_SEC:            /* send sector address */
+               databyte = (int)bp->b_blkno % RXSTRK + 1;
+               mtpr(TXDB, FL_DATA | databyte);
+               fltab.fl_active = FL_TRACK;
+               break;
+
+       case FL_TRACK:          /* send track address */
+               databyte = (int)bp->b_blkno / RXSTRK;
+               mtpr(TXDB , FL_DATA | databyte);
+               if ((bp->b_flags&B_READ) == B_READ)
+                       /* prepare to receive complete */
+                       fltab.fl_active = FL_COM;
+               else
+                       /* prepare to send data */
+                       fltab.fl_active = FL_DAX;
+               break;
+
+       case FL_DAX:
+               databyte = *(fltab.fl_xaddr++);
+               mtpr(TXDB, FL_DATA | databyte);
+               if (--bp->b_bcount == 0)
+                       fltab.fl_active = FL_COM;
+               break;
+
+       case FL_CAN:            /* give cancel order */
+               mtpr(TXDB, FL_CANCEL);
+               if (++fltab.fl_errcnt <= FLERRS) {
+                       /* If error count permits, retry order */
+                       fltab.fl_active = FL_MAND;
+                       bp->b_bcount = RXBYSEC;
+                       fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
+               } else {
+                       /*
+                        * We're really stupid today - call it an
+                        * error and give up
+                        */
+                       bp->b_flags |= B_ERROR | B_DONE;
+                       bp->b_resid = -RXBYSEC;
+                       fltab.fl_active = FL_IDLE;
+                       wakeup((caddr_t)bp);
+               }
+       }
+}
+
+cnrfl(c)
+       int c;
+{
+       register int datum;
+       register struct buf *bp;
+
+       datum = c;
+       bp = fltab.fl_buf;
+       if (datum == FL_PERR) {
+               /*
+                * Got a protocol error - cancel the
+                * current function and try again if error count isn't
+                * too great.  First, though, make sure that an actual
+                * transaction is in progress (so a spurious error from
+                * the LSI won't screw us up too much!
+                */
+               if (fltab.fl_active != FL_IDLE)
+                       fltab.fl_active = FL_CAN;
+       } else switch(fltab.fl_active ) {
+
+       case FL_DAR:            /* expecting a datum */
+               if ((c&RXDB_ID) != FL_DATA)
+                       goto error;
+               *(fltab.fl_xaddr++) = (c & RXDB_DATA);
+               if (--bp->b_bcount==0) {
+                       fltab.fl_active = FL_IDLE;
+                       bp->b_flags |= B_DONE;
+                       wakeup((caddr_t)bp);
+               }
+               break;
+
+       case FL_COM:            /* expecting a "function complete" */
+               if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){
+error:
+                       bp->b_flags |= B_ERROR | B_DONE;
+                       bp->b_resid = -bp->b_bcount;
+                       fltab.fl_active = FL_IDLE;
+                       wakeup((caddr_t)bp);
+               } else if ((bp->b_flags&B_READ) == B_READ)
+                       /* got function complete, now get data */
+                       fltab.fl_active = FL_DAR;
+               else {
+                       /* got function complete on write - finish up */
+                       fltab.fl_active = FL_IDLE;
+                       bp->b_flags |= B_DONE;
+                               wakeup((caddr_t)bp);
+               }
+               break;
+       }
+}
+#endif
diff --git a/sys/dev/mem.c b/sys/dev/mem.c
new file mode 100644 (file)
index 0000000..f397290
--- /dev/null
@@ -0,0 +1,163 @@
+/*     mem.c   4.3     81/03/08        */
+
+/*
+ * Memory special file
+ *     minor device 0 is physical memory
+ *     minor device 1 is kernel memory 
+ *     minor device 2 is EOF/RATHOLE
+ *     minor device 3 is unibus memory (addressed by shorts)
+ */
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/pte.h"
+#include "../h/mtpr.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+mmread(dev)
+{
+       register int o;
+       register unsigned c, v;
+
+       switch (minor(dev)) {
+
+       case 0:
+               while (u.u_count != 0 && u.u_error == 0) {
+                       if (fubyte(u.u_base) == -1)
+                               goto fault;
+                       v = btop(u.u_offset);
+                       if (v >= physmem)
+                               goto fault;
+                       *(int *)mmap = v | (PG_V | PG_KR);
+                       mtpr(TBIS, vmmap);
+                       o = (int)u.u_offset & PGOFSET;
+                       c = min((unsigned)(NBPG - o), u.u_count);
+                       c = min(c, (unsigned)(NBPG - ((int)u.u_base&PGOFSET)));
+                       if (copyout((caddr_t)&vmmap[o], u.u_base, c))
+                               goto fault;
+                       u.u_count -= c;
+                       u.u_base += c;
+                       u.u_offset += c;
+               }
+               return;
+
+       case 1:
+               if ((caddr_t)u.u_offset < (caddr_t)&umbabeg &&
+                   (caddr_t)u.u_offset + u.u_count >= (caddr_t)&umbabeg)
+                       goto fault;
+               if ((caddr_t)u.u_offset >= (caddr_t)&umbabeg &&
+                   (caddr_t)u.u_offset < (caddr_t)&umbaend)
+                       goto fault;
+               if (!kernacc((caddr_t)u.u_offset, u.u_count, B_READ))
+                       goto fault;
+               if (copyout((caddr_t)u.u_offset, u.u_base, u.u_count))
+                       goto fault;
+               c = u.u_count;
+               u.u_count = 0;
+               u.u_base += c;
+               u.u_offset += c;
+               return;
+
+       case 2:
+               return;
+
+       case 3:
+               if (!kernacc((caddr_t)u.u_offset, u.u_count, B_READ))
+                       goto fault;
+               if (!useracc(u.u_base, u.u_count, B_WRITE))
+                       goto fault;
+               UNIcpy((caddr_t)u.u_offset, u.u_base, u.u_count, B_READ);
+               c = u.u_count;
+               u.u_count = 0;
+               u.u_base += c;
+               u.u_offset += c;
+               return;
+       }
+fault:
+       u.u_error = EFAULT;
+       return;
+}
+
+mmwrite(dev)
+{
+       register int o;
+       register unsigned c, v;
+
+       switch (minor(dev)) {
+
+       case 0:
+               while (u.u_count != 0 && u.u_error == 0) {
+                       if (fubyte(u.u_base) == -1)
+                               goto fault;
+                       v = btop(u.u_offset);
+                       if (v >= physmem)
+                               goto fault;
+                       *(int *)mmap = v | (PG_V | PG_KW);
+                       mtpr(TBIS, vmmap);
+                       o = (int)u.u_offset & PGOFSET;
+                       c = min((unsigned)(NBPG - o), u.u_count);
+                       c = min(c, (unsigned)(NBPG - ((int)u.u_base&PGOFSET)));
+                       if (copyin(u.u_base, (caddr_t)&vmmap[o], c))
+                               goto fault;
+                       u.u_count -= c;
+                       u.u_base += c;
+                       u.u_offset += c;
+               }
+               return;
+
+       case 1:
+               if (!kernacc((caddr_t)u.u_offset, u.u_count, B_WRITE))
+                       goto fault;
+               if (copyin(u.u_base, (caddr_t)u.u_offset, u.u_count))
+                       goto fault;
+               u.u_base += u.u_count;
+               u.u_offset += u.u_count;
+               u.u_count = 0;
+               return;
+
+       case 2:
+               u.u_offset += u.u_count;
+               u.u_count = 0;
+               return;
+
+       case 3:
+               if (!kernacc((caddr_t)u.u_offset, u.u_count, B_WRITE))
+                       goto fault;
+               if (!useracc(u.u_base, u.u_count, B_READ))
+                       goto fault;
+               UNIcpy((caddr_t)u.u_offset, u.u_base, u.u_count, B_WRITE);
+               u.u_base += u.u_count;
+               u.u_offset += u.u_count;
+               u.u_count = 0;
+               return;
+       }
+fault:
+       u.u_error = EFAULT;
+       return;
+}
+
+/*
+ * UNIBUS Address Space <--> User Space transfer
+ */
+UNIcpy(uniadd, usradd, bknt, direct)
+       caddr_t uniadd, usradd;
+       unsigned bknt;
+{
+       register short *from, *to;
+       register int i;
+       if (direct == B_READ) {
+               from = (short *) uniadd;
+               to = (short *) usradd;
+       } else {
+               from = (short *) usradd;
+               to = (short *) uniadd;
+       }
+       for (i = (bknt>>1); i > 0; i--)
+               *to++ = *from++;
+}
diff --git a/sys/dev/mx1.c b/sys/dev/mx1.c
new file mode 100644 (file)
index 0000000..91e851d
--- /dev/null
@@ -0,0 +1,583 @@
+/*     mx1.c   4.6     81/03/11        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.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"
+
+/*
+ * Multiplexor:   clist version
+ *
+ * installation:
+ *     requires a line in cdevsw -
+ *             mxopen, mxclose, mxread, mxwrite, mxioctl, 0,
+ *
+ *     also requires a line in linesw -
+ *             mxopen, mxclose, mcread, mcwrite, mxioctl, nulldev, nulldev,
+ *
+ *     The linesw entry for mpx should be the last one in the table.
+ *     'nldisp' (number of line disciplines) should not include the
+ *     mpx line.  This is to prevent mpx from being enabled by an ioctl.
+ */
+struct chan    chans[NCHANS];
+struct schan   schans[NPORTS];
+struct group   *groups[NGROUPS];
+int    mpxline;
+struct chan *xcp();
+dev_t  mpxdev  = -1;
+
+
+char   mcdebugs[NDEBUGS];
+
+
+/*
+ * Allocate a channel, set c_index to index.
+ */
+struct chan *
+challoc(index, isport)
+{
+register s,i;
+register struct chan *cp;
+
+       s = spl6();
+       for(i=0;i<((isport)?NPORTS:NCHANS);i++) {
+               cp = (isport)? (struct chan *)(schans+i): chans+i;
+               if(cp->c_group == NULL) {
+                       cp->c_index = index;
+                       cp->c_pgrp = 0;
+                       cp->c_flags = 0;
+                       splx(s);
+                       return(cp);
+               }
+       }
+       splx(s);
+       return(NULL);
+}
+
+
+
+/*
+ * Allocate a group table cell.
+ */
+gpalloc()
+{
+       register i;
+
+       for (i=NGROUPS-1; i>=0; i--)
+               if (groups[i]==NULL) {
+                       groups[i]++;
+                       return(i);
+               }
+       u.u_error = ENXIO;
+       return(i);
+}
+
+
+/*
+ * Add a channel to the group in
+ * inode ip.
+ */
+struct chan *
+addch(ip, isport)
+struct inode *ip;
+{
+register struct chan *cp;
+register struct group *gp;
+register i;
+
+       plock(ip);
+       gp = &ip->i_un.i_group;
+       for(i=0;i<NINDEX;i++) {
+               cp = (struct chan *)gp->g_chans[i];
+               if (cp == NULL) {
+                       if ((cp=challoc(i, isport)) != NULL) {
+                               gp->g_chans[i] = cp;
+                               cp->c_group = gp;
+                       }
+                       break;
+               }
+               cp = NULL;
+       }
+       prele(ip);
+       return(cp);
+}
+
+/*
+ * Mpxchan system call.
+ */
+
+mpxchan()
+{
+       extern  mxopen(), mcread(), sdata(), scontrol();
+       struct  inode   *ip, *gip;
+       struct  tty     *tp;
+       struct  file    *fp, *chfp, *gfp;
+       struct  chan    *cp;
+       struct  group   *gp, *ngp;
+       struct  mx_args vec;
+       struct  a       {
+               int     cmd;
+               int     *argvec;
+       } *uap;
+       dev_t   dev;
+       register int i;
+
+       /*
+        * Common setup code.
+        */
+
+       uap = (struct a *)u.u_ap;
+       (void) copyin((caddr_t)uap->argvec, (caddr_t)&vec, sizeof vec);
+       gp = NULL; gfp = NULL; cp = NULL;
+
+       switch(uap->cmd) {
+
+       case NPGRP:
+               if (vec.m_arg[1] < 0)
+                       break;
+       case CHAN:
+       case JOIN:
+       case EXTR:
+       case ATTACH:
+       case DETACH:
+       case CSIG:
+               gfp = getf(vec.m_arg[1]);
+               if (gfp==NULL)
+                       return;
+               gip = gfp->f_inode;
+               gp = &gip->i_un.i_group;
+               if (gp->g_inode != gip) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+       }
+
+       switch(uap->cmd) {
+
+       /*
+        * Create an MPX file.
+        */
+
+       case MPX:
+       case MPXN:
+               if (mpxdev < 0) {
+                       for (i=0; linesw[i].l_open; i++) {
+                               if (linesw[i].l_read==mcread) {
+                                       mpxline = i;
+                                       for (i=0; cdevsw[i].d_open; i++) {
+                                               if (cdevsw[i].d_open==mxopen) {
+                                                       mpxdev = (dev_t)(i<<8);
+                                               }
+                                       }
+                               }
+                       }
+                       if (mpxdev < 0) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+               }
+               if (uap->cmd==MPXN) {
+                       if ((ip=ialloc(pipedev))==NULL)
+                               return;
+                       ip->i_mode = ((vec.m_arg[1]&0777)+IFMPC) & ~u.u_cmask;
+                       ip->i_flag = IACC|IUPD|ICHG;
+               } else {
+                       u.u_dirp = vec.m_name;
+                       ip = namei(uchar,1);
+                       if (ip != NULL) {
+                               i = ip->i_mode&IFMT;
+                               u.u_error = EEXIST;
+                               if (i==IFMPC || i==IFMPB) {
+                                       i = minor(ip->i_un.i_rdev);
+                                       gp = groups[i];
+                                       if (gp && gp->g_inode==ip)
+                                               u.u_error = EBUSY;
+                               }
+                               iput(ip);
+                               return;
+                       }
+                       if (u.u_error)
+                               return;
+                       ip = maknode((vec.m_arg[1]&0777)+IFMPC);
+                       if (ip == NULL)
+                               return;
+               }
+               if ((i=gpalloc()) < 0) {
+                       iput(ip);
+                       return;
+               }
+               if ((fp=falloc()) == NULL) {
+                       iput(ip);
+                       groups[i] = NULL;
+                       return;
+               }
+               ip->i_un.i_rdev = (daddr_t)(mpxdev+i);
+               ip->i_count++;
+               prele(ip);
+
+               gp = &ip->i_un.i_group;
+               groups[i] = gp;
+               gp->g_inode = ip;
+               gp->g_state = INUSE|ISGRP;
+               gp->g_group = NULL;
+               gp->g_file = fp;
+               gp->g_index = 0;
+               gp->g_rotmask = 1;
+               gp->g_rot = 0;
+               gp->g_datq = 0;
+               for(i=0;i<NINDEX;)
+                       gp->g_chans[i++] = NULL;
+
+               fp->f_flag = FREAD|FWRITE|FMP;
+               fp->f_inode = ip;
+               fp->f_un.f_chan = NULL;
+               return;
+
+       /*
+        * join file descriptor (arg 0) to group (arg 1)
+        * return channel number
+        */
+
+       case JOIN:
+               if ((fp=getf(vec.m_arg[0]))==NULL)
+                       return;
+               ip = fp->f_inode;
+               switch (ip->i_mode & IFMT) {
+
+               case IFMPC:
+                       if ((fp->f_flag&FMP) != FMP) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       ngp = &ip->i_un.i_group;
+                       if (mtree(ngp, gp) == NULL)
+                               return;
+                       fp->f_count++;
+                       u.u_r.r_val1 = cpx((struct chan *)ngp);
+                       return;
+
+               case IFCHR:
+                       dev = (dev_t)ip->i_un.i_rdev;
+                       tp = cdevsw[major(dev)].d_ttys;
+                       if (tp==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       tp = &tp[minor(dev)];
+                       if (tp->t_chan) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       if ((cp=addch(gip, 1))==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+                       tp->t_chan = cp;
+                       cp->c_fy = fp;
+                       fp->f_count++;
+                       cp->c_ttyp = tp;
+                       cp->c_line = tp->t_line;
+                       cp->c_flags = XGRP+PORT;
+                       u.u_r.r_val1 = cpx(cp);
+                       return;
+
+               default:
+                       u.u_error = ENXIO;
+                       return;
+
+               }
+
+       /*
+        * Attach channel (arg 0) to group (arg 1).
+        */
+
+       case ATTACH:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL || cp->c_flags&ISGRP) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               u.u_r.r_val1 = cpx(cp);
+               wakeup((caddr_t)cp);
+               return;
+
+       case DETACH:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               (void) detach(cp);
+               return;
+
+       /*
+        * Extract channel (arg 0) from group (arg 1).
+        */
+
+       case EXTR:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               if (cp->c_flags & ISGRP) {
+                       (void) mxfalloc(((struct group *)cp)->g_file);
+                       return;
+               }
+               if ((fp=cp->c_fy) != NULL) {
+                       (void) mxfalloc(fp);
+                       return;
+               }
+               if ((fp=falloc()) == NULL)
+                       return;
+               fp->f_inode = gip;
+               gip->i_count++;
+               fp->f_un.f_chan = cp;
+               fp->f_flag = (vec.m_arg[2]) ?
+                               (FREAD|FWRITE|FMPY) : (FREAD|FWRITE|FMPX);
+               cp->c_fy = fp;
+               return;
+
+       /*
+        * Make new chan on group (arg 1).
+        */
+
+       case CHAN:
+               if((gfp->f_flag&FMP)==FMP)cp = addch(gip, 0);
+                       if(cp == NULL){
+                       u.u_error = ENXIO;
+                       return;
+                       }
+               cp->c_flags = XGRP;
+               cp->c_fy = NULL;
+               cp->c_ttyp = cp->c_ottyp = (struct tty *)cp;
+               cp->c_line = cp->c_oline = mpxline;
+               u.u_r.r_val1 = cpx(cp);
+               return;
+
+       /*
+        * Connect fd (arg 0) to channel fd (arg 1).
+        * (arg 2 <  0) => fd to chan only
+        * (arg 2 >  0) => chan to fd only
+        * (arg 2 == 0) => both directions
+        */
+
+       case CONNECT:
+               if ((fp=getf(vec.m_arg[0]))==NULL)
+                       return;
+               if ((chfp=getf(vec.m_arg[1]))==NULL)
+                       return;
+               ip = fp->f_inode;
+               i = ip->i_mode&IFMT;
+               if (i!=IFCHR) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               dev = (dev_t)ip->i_un.i_rdev;
+               tp = cdevsw[major(dev)].d_ttys;
+               if (tp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               tp = &tp[minor(dev)];
+               if (!(chfp->f_flag&FMPY)) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               cp = chfp->f_un.f_chan;
+               if (cp==NULL || cp->c_flags&PORT) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               i = vec.m_arg[2];
+               if (i>=0) {
+                       cp->c_ottyp = tp;
+                       cp->c_oline = tp->t_line;
+               }
+               if (i<=0)  {
+                       tp->t_chan = cp;
+                       cp->c_ttyp = tp;
+                       cp->c_line = tp->t_line;
+               }
+               u.u_r.r_val1 = 0;
+               return;
+
+       case NPGRP: {
+               register struct proc *pp;
+
+               if (gp != NULL) {
+                       cp = xcp(gp, vec.m_arg[0]);
+                       if (cp==NULL) {
+                               u.u_error = ENXIO;
+                               return;
+                       }
+               }
+               pp = u.u_procp;
+               pp->p_pgrp = pp->p_pid;
+               if (vec.m_arg[2])
+                       pp->p_pgrp = vec.m_arg[2];
+               if (gp != NULL)
+                       cp->c_pgrp = pp->p_pgrp;
+               u.u_r.r_val1 = pp->p_pgrp;
+               return;
+       }
+
+       case CSIG:
+               cp = xcp(gp, vec.m_arg[0]);
+               if (cp==NULL) {
+                       u.u_error = ENXIO;
+                       return;
+               }
+               gsignal(cp->c_pgrp, vec.m_arg[2]);
+               u.u_r.r_val1 = vec.m_arg[2];
+               return;
+
+       case DEBUG:
+               i = vec.m_arg[0];
+               if (i<0 || i>NDEBUGS)
+                       return;
+               mcdebugs[i] = vec.m_arg[1];
+               if (i==ALL)
+                       for(i=0;i<NDEBUGS;i++)
+                               mcdebugs[i] = vec.m_arg[1];
+               return;
+
+       default:
+               u.u_error = ENXIO;
+               return;
+       }
+
+}
+detach(cp)
+register struct chan *cp;
+{
+       register struct group *master,*sub;
+       register index;
+
+       if (cp==NULL)
+               return(0);
+       if (cp->c_flags&ISGRP) {
+               sub = (struct group *)cp;
+               master = sub->g_group;  index = sub->g_index;
+               closef(sub->g_file);
+               if (master != NULL)
+                       master->g_chans[index] = NULL;
+               return(0);
+       } else if (cp->c_flags&PORT && cp->c_ttyp != NULL) {
+               closef(cp->c_fy);
+               chdrain(cp);
+               chfree(cp);
+               return(0);
+       }
+       if (cp->c_flags & WCLOSE) {
+               if (cp->c_fy) {
+                       if (cp->c_fy->f_count)
+                               return(1);
+                       chdrain(cp);
+                       chfree(cp);
+                       return(0);
+               }
+       }
+       cp->c_flags |= WCLOSE;
+       chwake(cp);
+       return(1);
+}
+
+
+mxfalloc(fp)
+register struct file *fp;
+{
+register i;
+
+       if (fp==NULL) {
+               u.u_error = ENXIO;
+               return(-1);
+       }
+       i = ufalloc();
+       if (i < 0)
+               return(i);
+       u.u_ofile[i] = fp;
+       fp->f_count++;
+       u.u_r.r_val1 = i;
+       return(i);
+}
+
+/*
+ * Grow a branch on a tree.
+ */
+
+mtree(sub,master)
+register struct group *sub, *master;
+{
+       register i;
+       int mtresiz, stresiz;
+
+       if ((mtresiz=mup(master,sub)) == NULL) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if ((stresiz=mdown(sub,master)) <= 0) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if (sub->g_group != NULL) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       if (stresiz+mtresiz > NLEVELS) {
+               u.u_error = ENXIO;
+               return(NULL);
+       }
+       for (i=0;i<NINDEX;i++) {
+               if (master->g_chans[i] != NULL)
+                       continue;
+               master->g_chans[i] = (struct chan *)sub;
+               sub->g_group = master;
+               sub->g_index = i;
+               return(1);
+       }
+       u.u_error = ENXIO;
+       return(NULL);
+}
+
+mup(master,sub)
+struct group *master, *sub;
+{
+       register struct group *top;
+       register int depth;
+
+       depth = 1;  top = master;
+       while (top->g_group) {
+               depth++;
+               top = top->g_group;
+       }
+       if(top == sub)
+               return(NULL);
+       return(depth);
+}
+
+
+mdown(sub,master)
+struct group *sub, *master;
+{
+       register int maxdepth, i, depth;
+
+       if(sub == (struct group *)NULL || (sub->g_state&ISGRP) == 0)
+               return(0);
+       if(sub == master)
+               return(-1);
+       maxdepth = 0;
+       for(i=0; i<NINDEX; i++) {
+               if((depth=mdown((struct group *)sub->g_chans[i],master)) == -1)
+                       return(-1);
+               maxdepth = (depth>maxdepth) ? depth: maxdepth;
+       }
+       return(maxdepth+1);
+}
diff --git a/sys/dev/sw.c b/sys/dev/sw.c
new file mode 100644 (file)
index 0000000..7d77c4b
--- /dev/null
@@ -0,0 +1,126 @@
+/*     sw.c    4.4     81/03/08        */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/map.h"
+
+struct buf rswbuf;
+/*
+ * Indirect driver for multi-controller paging.
+ */
+swstrategy(bp)
+       register struct buf *bp;
+{
+       int sz, off, seg;
+       dev_t dev;
+
+       sz = (bp->b_bcount+511)/512;
+       off = bp->b_blkno % DMMAX;
+       if (bp->b_blkno+sz > nswap || off+sz > DMMAX) {
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               return;
+       }
+       seg = bp->b_blkno / DMMAX;
+       dev = swdevt[seg % nswdev].sw_dev;
+       seg /= nswdev;
+       bp->b_blkno = seg*DMMAX + off;
+       bp->b_dev = dev;
+       if (dev == 0)
+               panic("swstrategy");
+       (*bdevsw[major(dev)].d_strategy)(bp);
+}
+
+swread(dev)
+{
+
+       physio(swstrategy, &rswbuf, dev, B_READ, minphys);
+}
+
+swwrite(dev)
+{
+
+       physio(swstrategy, &rswbuf, dev, B_WRITE, minphys);
+}
+
+/*
+ * System call swapon(name) enables swapping on device name,
+ * which must be in the swdevsw.  Return EBUSY
+ * if already swapping on this device.
+ */
+vswapon()
+{
+       register struct inode *ip;
+       dev_t dev;
+       register struct swdevt *sp;
+
+       ip = namei(uchar, 0);
+       if (ip == NULL)
+               return;
+       if ((ip->i_mode&IFMT) != IFBLK) {
+               u.u_error = ENOTBLK;
+               iput(ip);
+               return;
+       }
+       dev = (dev_t)ip->i_un.i_rdev;
+       iput(ip);
+       if (major(dev) >= nblkdev) {
+               u.u_error = ENXIO;
+               return;
+       }
+       /*
+        * Search starting at second table entry,
+        * since first (primary swap area) is freed at boot.
+        */
+       for (sp = &swdevt[1]; sp->sw_dev; sp++)
+               if (sp->sw_dev == dev) {
+                       if (sp->sw_freed) {
+                               u.u_error = EBUSY;
+                               return;
+                       }
+                       swfree(sp - swdevt);
+                       return;
+               }
+       u.u_error = ENODEV;
+}
+
+/*
+ * Swfree(index) frees the index'th portion of the swap map.
+ * Each of the nswdev devices provides 1/nswdev'th of the swap
+ * space, which is laid out with blocks of DMMAX pages circularly
+ * among the devices.
+ */
+swfree(index)
+       int index;
+{
+       register swblk_t vsbase;
+       register int blk;
+
+       swdevt[index].sw_freed = 1;
+       for (vsbase = index*DMMAX; vsbase < nswap; vsbase += nswdev*DMMAX) {
+               blk = nswap - vsbase;
+               if (blk > DMMAX)
+                       blk = DMMAX;
+               if (vsbase == 0) {
+                       /*
+                        * Can't free a block starting at 0 in the swapmap
+                        * but need some space for argmap so use 1/2 this
+                        * hunk which needs special treatment anyways.
+                        */
+                       argdev = swdevt[0].sw_dev;
+                       rminit(argmap, blk/2-CLSIZE, CLSIZE,
+                           "argmap", ARGMAPSIZE);
+                       /*
+                        * First of all chunks... initialize the swapmap
+                        * the second half of the hunk.
+                        */
+                       rminit(swapmap, blk/2, blk/2, "swap", nswapmap);
+               } else
+                       rmfree(swapmap, blk, vsbase);
+       }
+}