From: CSRG Date: Sat, 21 Mar 1981 00:46:33 +0000 (-0800) Subject: BSD 4_1_snap development X-Git-Tag: BSD-4_1_snap~424 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/01395141cceb626189a5d7b74176fc799dacecaa BSD 4_1_snap development 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 --- diff --git a/sys/dev/bk.c b/sys/dev/bk.c new file mode 100644 index 0000000000..ad5f14dc10 --- /dev/null +++ b/sys/dev/bk.c @@ -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 index 0000000000..709d28e5fa --- /dev/null +++ b/sys/dev/dkleave.c @@ -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 index 0000000000..b8f41902fb --- /dev/null +++ b/sys/dev/dsort.c @@ -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 index 0000000000..869f652833 --- /dev/null +++ b/sys/dev/flp.c @@ -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 index 0000000000..f39729077b --- /dev/null +++ b/sys/dev/mem.c @@ -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 index 0000000000..91e851ddec --- /dev/null +++ b/sys/dev/mx1.c @@ -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;ig_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;ig_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;ic_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;ig_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; ig_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 index 0000000000..7d77c4b0f9 --- /dev/null +++ b/sys/dev/sw.c @@ -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); + } +}