SRI-NOSC/new/dist.ufmt

<File 1>
 h/filsys.h
1221
/*
 * Definition of the unix super block.
 * The root super block is allocated and
 * read in iinit/alloc.c. Subsequently
 * a super block is allocated and read
 * with each mount (smount/sys3.c) and
 * released with unmount (sumount/sys3.c).
 * A disk block is ripped off for storage.
 * See alloc.c for general alloc/free
 * routines for free list and I list.
 */
struct	filsys
{
	int	s_isize;	/* size in blocks of I list */
	char	*s_fsize;	/* size in blocks of entire volume */
	int	s_nfree;	/* number of in core free blocks (0-100) */
	int	s_free[100];	/* in core free blocks */
	int	s_ninode;	/* number of in core I nodes (0-100) */
	int	s_inode[100];	/* in core free I nodes */
	char	s_flock;	/* lock during free list manipulation */
	char	s_ilock;	/* lock during I list manipulation */
	char	s_fmod;		/* super block modified flag */
	char	s_ronly;	/* mounted read-only flag */
	int	s_time[2];	/* current date of last update */
	int	pad[50];
/*PWB	int	pad[40];
/*PWB	char	*s_tfree;	/* total free blocks available */
/*PWB	char	*s_tinode;	/* total free inodes available */
/*PWB	char	s_fname[6];	/* name of the file system */
/*PWB	char	s_fpack[6];	/* name of the pack (pack ID) */
};
<File 1>
 h/systm.h
2328
/*
 * Random set of variables
 * used by more than one
 * routine.
 */
#ifdef CMAPSIZ
int	coremap[CMAPSIZ];	/* space for core allocation */
#endif CMAPSIZ
#ifdef SMAPSIZ
int	swapmap[SMAPSIZ];	/* space for swap allocation */
#endif SMAPSIZ
int	*rootdir;		/* pointer to inode of root directory */
int	cputype;		/* type of cpu =40, 45, or 70 */
int	execnt;			/* number of processes in exec */
int	lbolt;			/* time of day in 60th not in time */
int	time[2];		/* time in sec from 1970 */
/*
 * The callout structure is for
 * a routine arranging
 * to be called by the clock interrupt
 * (clock.c) with a specified argument,
 * in a specified amount of time.
 * Used, for example, to time tab
 * delays on teletypes.
 */
struct	callo
{
	int	c_time;		/* incremental time */
	int	c_arg;		/* argument to routine */
	int	(*c_func)();	/* routine */
};
#ifdef NCALL
struct callo callout[NCALL];
#endif NCALL
/*
 * Mount structure.
 * One allocated on every mount.
 * Used to find the super block.
 */
struct	mount
{
	int	m_dev;		/* device mounted */
	int	*m_bufp;	/* pointer to superblock */
	int	*m_inodp;	/* pointer to mounted on inode */
#ifdef UCBUFMOD
	int	m_isize;	/* incore copy of s_isize */
	char	*m_fsize;	/* incore copy of s_fsize */
	int	m_nfree;	/* incore copy of s_nfree */
	int	m_ninode;	/* incore copy of s_ninode */
	char	m_flock;	/* lock during free list manipulation */
	char	m_ilock;	/* lock during I list manipulation */
	char	m_fmod;		/* super block modified flag */
	char	m_ronly;	/* mounted read-only flag */
/*PWB	char	*m_tfree;	/* total free blocks available */
/*PWB	char	*m_tinode;	/* total free inodes avaliable */
#endif UCBUFMOD
};
#ifdef NMOUNT
struct mount mount[NMOUNT];
#endif NMOUNT
char	runin;			/* scheduling flag */
char	runout;			/* scheduling flag */
char	runrun;			/* scheduling flag */
char	curpri;			/* more scheduling */
int	maxmem;			/* actual max memory per process */
int	*lks;			/* pointer to clock device */
int	rootdev;		/* dev of root see conf.c */
int	swapdev;		/* dev of swap see conf.c */
int	swplo;			/* block number of swap space */
int	nswap;			/* size of swap space */
int	updlock;		/* lock for sync */
int	rablock;		/* block to be read ahead */
char	regloc[];		/* locs. of saved user registers (trap.c) */
<File 1>
 ncpk/drivers/vdh.c
9718
#include	"param.h"
#include	"buf.h"
#include	"net_net.h"
#include	"net_netbuf.h"
#include	"net_ncp.h"
#include	"net_vdhstat.h"
#include	"net_vdh_imp.h"
#include	"net_vdh.h"

char vdhlock -1;

v_pan (msg)
char *msg;
{
	register t;
	struct vdhregs sv_regs;
	register int *p, *q;

	t = PS->integ;
	spl7();
	p = &sv_regs.wco;  q = &VDH->wco;
	do {			/* save registers at time of panic */
		*p-- = *q--;
	} while q >= &VDH->csri;
	VDH->csri =& ~ V_INTENB;
	VDH->csro =& ~ (V_INTENB|V_TIMRUN);
	panic (msg);
}

imp_init ()
{
	register	t, *ptr;
	register int	oldps;

	oldps = PS->integ;
	spl_imp ();

	vdhichn = 0;
	prvictl = 0;
	vstatebits = VDHILAST;
	impldrd ();

	hellonext = 2*VDH_T*VDH_R;
	vdhosnd = -1;
	vdhofill = 0;
	vdhoack = V_HTOI;
	for(t = 0; t < NCHNS; t++)
		vdhouse[t] = -1;
	ptr = &VDH->csro;
	if ((*ptr & V_INTENB) == 0)
	{
		*ptr++ = V_TIMSEL;
		*ptr = 12500/(HZ/10);	/* 125000 too big for one word */
		*--ptr = V_TIMRUN | V_INTENB;
	}

	oimp.o_type = ih_nop;
	for ( t = 3; --t>=0; )
		sndnetbytes (&oimp,4,0,0,1); 
	PS->integ = oldps;
}

#ifndef UCBUFMOD
imp_output()
{
#endif UCBUFMOD
#ifdef UCBUFMOD
imp_output(msg)
struct netbuf *msg;
{
	register sps;

	sps = PS->integ;
	spl_imp();
	msg_q(&impoq, 0, 0, msg);
#endif UCBUFMOD
	if (((vstatebits ^ UP) & (OUTBUSY|UP)) == 0)
	{
		vdhostart ();
	}
#ifdef UCBUFMOD
	PS->integ = sps;
#endif UCBUFMOD
}

vdhiint ()
{
	register int	t;
	register int	*p;
	register int	*state;
	int	*q;
	int	xorrot;

	if (++vdhlock)
		v_pan ("VDH-i");
#ifdef	PARANOID
	v_bufck ();
#endif	PARANOID

	state = &vstatebits;
	p = &VDH->csri;

#ifndef VDHE
	while ( (*p ^ V_GO) & (V_EOT|V_GO) ) {
#endif not VDHE
#ifdef VDHE
	while (*p & V_EOT) {
#endif VDHE
		if (!(*state & TRYING)) {
			VDH->csri =& ~ V_INTENB;
			goto finis;
		}
		if (*p<0) {
			vs.harderr++;
			vdherr = *p; 
			goto eot_done;
		}

		p = (*state&VDHIAB) ? &vdhibuf[1][0]:&vdhibuf[0][0];

		if ((t = (VDH->cwai - p) - 1) < 0) {	/* null transfer */
	wcerr:
			/* log some error? */
			goto eot_done;
		}
		if (*p & V_HTOI) {
			vs.looped++;
			goto eot_done;
		}
		if (*p & V_SPBIT) {
			if (t != 0) goto wcerr;
			if (*p>0) {
				*state =| (SAWHELLO|OUT2GO);
			} else {
				hellounacked = 0;
				helloinarow++;
			}
			goto eot_done;
		}
		if (t != (p->hibyte&077)) goto wcerr;
		if (!(*state & UP)) {
			vs.wpaks++;
			goto eot_done;
		}

		xorrot = (prvictl ^ *p) << (14-NCHNS);
		t = NCHNS-1;
		do {
			if (xorrot<0) {
				vdhouse[t] = -1;
				*state =| OUT2GO;
			}
			xorrot =<< 1;
		} while (--t>=0);
		prvictl = *p;
		if ((*p & V_WCBITS)==0) {
			vs.inulls++;
			goto eot_done;
		}
		*state =| (ACK2SND|OUT2GO); 
		if ((t = *p & V_CHBITS) != vdhichn) {
			vs.chwrong++;
			goto eot_done;
		}
		if ((*p ^ ((vdhoack>>t)*(V_EVNODD/V_C0ACK)))
		     & V_EVNODD)  {
			vs.idups++;
			goto eot_done;
		}
		if (*state & VDHILAST) {
			wakeup ( &imp );
			vs.ifull++;
			goto eot_done;
		}
		if (net_b.b_cntfree < (VDHDSIZE + NET_B_SIZE - 1)/NET_B_SIZE) {
			vs.nobuf++;
			*state =| VDHINEED; 
			wakeup (&imp); 
			goto eot_done;
		}
		t = (p++->hibyte & 077); 
		swabuf (p,t); 
		t =<< 1;
		if (impi_msg==0) {
			q = impleader ? &imp.type : &imp.pad1;
			t =- 4;
			*q++ = *p++; 
			*q   = *p++; 
		}
		if (t && vectomsg (p,t,&impi_msg,1))
			v_pan ("vdh: vectomsg failed");
		impleader = 0; 
		vdhoack =^ V_C0ACK<<vdhichn;
		if (prvictl & V_LAST) {
#ifdef	PARANOID
			v_bufck();
#endif	PARANOID
			*state =| VDHILAST;
			wakeup (&imp);
		}
		vdhichn++; 
		vdhichn =& NCHNS-1;
		vs.igood++;
eot_done:

		p = &VDH->csri;

		VDH->cwai = (*state&VDHIAB)?&vdhibuf[1][0]:&vdhibuf[0][0];
#ifndef	VDHE
		VDH->wci = VDHSIZE; 
		do {
			*p =| V_GO;
		} while !(*p&V_GO);
#endif	not VDHE
#ifdef	VDHE
		VDH->wci = -(VDHSIZE*2);
		*p =| V_GO;
#endif	VDHE
		*state =^ VDHIAB;
		*p = (*state&VDHIAB) ? (V_ABSEL | V_INTENB) : V_INTENB; 
	} 
	if (((*state ^ OUT2GO) & (OUT2GO|OUTBUSY)) == 0) {
		vdhostart();
	}
	*state =& ~OUT2GO;
finis:
#ifdef	PARANOID
	v_bufck ();
#endif	PARANOID

	--vdhlock;
}

vdhoint ()
{
	register	*p;
	register	xorrot;
	register	*state;

	if (++vdhlock)
		v_pan ("VDH-o");


	state = &vstatebits;

	if (VDH->csro&V_TIMINT)
	{
		VDH->csro =& ~ V_TIMINT;
#ifdef	NOCLOCK
		*state =| CLOCKINT;
#endif	NOCLOCK
		if (ncpopnstate == 0)
		{
			*state =& ~(UP | TRYING);
			goto clock_done;
		}
		for(xorrot = 0; xorrot < NCHNS; xorrot++)
			if(vdhouse[xorrot] > 0)
				vdhouse[xorrot]--;
		if (--hellonext > 0)
			goto clock_done;
		hellonext =+ VDH_R;

		switch (*state & (UP | TRYING))
		{
		case UP|TRYING:
			if (hellounacked > VDH_T)  
			{
				*state =& ~(TRYING | UP);
				hellonext = 077777;
				needinit++;
				wakeup ( &imp ); 
				goto	clock_done;
			}  
			break;
		case TRYING:
			if (hellounacked)
			{
				helloinarow = 0;
			}
			else
			if (helloinarow >= VDH_K)
			{

				*state =| UP;
				wakeup ( &imp );
			}
			break;
		default:
			*state =| TRYING;
			*state =& ~(SAWHELLO | SENDHELLO | UP);
#ifndef	VDHE
			VDH->csri = 0;
			VDH->cwai = &vdhibuf[0][0];
			VDH->wci = VDHSIZE;
			VDH->csri = V_GO | V_ABSEL;
			VDH->cwai = &vdhibuf[1][0];
			VDH->wci = VDHSIZE;
			VDH->csri = V_INTENB | V_GO;
#endif	not VDHE
#ifdef	VDHE
			VDH->csri = 0;
			VDH->cwai = &vdhibuf[0][0];
			VDH->wci = -(VDHSIZE*2);
			VDH->csri = V_GO;
			VDH->csri =| V_ABSEL;
			VDH->cwai = &vdhibuf[1][0];
			VDH->wci = -(VDHSIZE*2);
			VDH->csri = V_INTENB | V_GO | V_ABSEL;
			VDH->csri =& ~ V_ABSEL;
#endif	VDHE
		}
		*state =| SENDHELLO;
	}

clock_done:

	if (VDH->csro&V_EOTINT)
	{
		*state =& ~OUTBUSY;
	}

	if ((*state & OUTBUSY) == 0) {
		vdhostart();
#ifdef	PARANOID
		v_bufck ();
#endif	PARANOID
	}


	--vdhlock;

#ifdef NOCLOCK
	if (*state & CLOCKINT)
	{
		*state =& ~CLOCKINT;
		vdh_clock();	/* no return */
	}
#endif	NOCLOCK
}

vdhostart ()
{
	register int	*p;
	register int	i;
	register int	*state;

	state = &vstatebits;

	if ((*state & TRYING) == 0)
		return;
#ifdef	PARANOID
	v_bufck();
#endif	PARANOID
	if (*state & SAWHELLO)
	{
		I_HEARD_YOU;
		*state =& ~ SAWHELLO;
		return;
	}
	if (*state & SENDHELLO)
	{
		HELLO;
		hellounacked++;
		*state =& ~SENDHELLO;
		return;
	}
	if ((*state & UP) == 0)
		return;
	/* Proceed below if we are UP&TRYING -- I just didn't want */
	/* to indent that much.... */

	fillochans();
	for (i = 0; i < NCHNS; i++)
	{
		vdhosnd++;
		vdhosnd =& NCHNS-1;
		if (vdhouse[vdhosnd] == 0) {
			p = vdhobuf [vdhosnd];
			p [0] = (p [0] & ~V_ACKBITS) | vdhoack;
			vdhsnd (p);
			vdhouse[vdhosnd] = HZ*100/1000;	/* hold off 100 ms */
			*state =& ~ACK2SND;
			return;
		}
	}
		/* No data to be sent */
	if (*state & ACK2SND) {	/* And an ack to send? */
		OACK;
		*state =& ~ACK2SND;
	}
}

#ifndef UCBUFMOD
struct	buf vdbuf;
#endif UCBUFMOD
#ifdef UCBUFMOD
struct netbuf *vdhmsg;
#endif UCBUFMOD

fillochans ()
{
	register int	*p;
	register char	*bp;
	register int	len;

	while (vdhouse[vdhofill] < 0) {
#ifndef UCBUFMOD
		if (vdbuf.b_dev==0)
		{
			bp = impotab.d_actf;
			if (bp==0)
				return;
			impotab.d_actf = bp->b_forw;
			bytesout (&bp->b_dev, &vdbuf, BUFSIZE, 1);
			vdbuf.b_wcount = msglen (vdbuf.b_dev);
			len = 4;
		}
		else
			len = min (VDHDSIZE, vdbuf.b_wcount);
		bytesout (&vdbuf.b_dev, p = &vdhobuf[vdhofill][1], len, 1);
		vdbuf.b_wcount =- len;
		if (vdbuf.b_wcount<0)
			v_pan ("Bad wcount");
#endif UCBUFMOD
#ifdef UCBUFMOD
		if(vdhmsg==0) {		/* must pick up new message? */
			if((bp = impoq) == 0)	/* if nothing to output */
				return;		/* just go away */
			bp->b_resv =| b_eom;	/* so I'm paranoid */
			do {		/* remove first message from q */
				bp = bp->b_qlink;
			} while( (bp->b_resv&b_eom) == 0 );
			/* now pointing at last buffer of msg */
			if(bp == impoq) {	/* only message in q? */
				impoq = 0;	/* clear q pointer */
			} else {
				len = impoq->b_qlink;	/* use len as temp */
				impoq->b_qlink = bp->b_qlink;
				bp->b_qlink = len;
			}
			vdhmsg = bp; len = 4;	/* only header in first packet */
		} else
			len = VDHDSIZE;
		len =- bytesout(&vdhmsg, p = &vdhobuf[vdhofill][1], len, 1);
#endif UCBUFMOD
		*--p = vdhofill;
		len =>> 1;
		p->hibyte = len;
#ifndef UCBUFMOD
		if (vdbuf.b_wcount==0)
#endif UCBUFMOD
#ifdef UCBUFMOD
		if (vdhmsg==0)
#endif UCBUFMOD
			*p =| V_LAST;
		if ( (prvictl>>vdhofill) & V_C0ACK )
			*p =| V_EVNODD;
		swabuf (&p[1], len);
		vdhouse[vdhofill] = 0;
		vdhofill++;
		vdhofill =& NCHNS-1;
		vs.opaks++;
	}
}

#ifndef UCBUFMOD
msglen(abp)	char *abp;
{
	register char	*bp;
	register int	cnt;

	bp = abp;
	if(bp==0)	return 0;
	for( cnt = bp->b_len; (bp=bp->b_qlink)!=abp; )
		cnt =+ bp->b_len&0377;

	return cnt;
}
#endif UCBUFMOD

impldrd ()
{
	spl_imp ();

	if (!(vstatebits & VDHILAST))
		log_to_ncp ("Bad impldrd");
	else
	{
		impleader = 1;
		impi_msg = 0;		/* can a buffer get lost here ? */
		vstatebits =& ~VDHILAST;
	}
}

vdh1snd (oneliner)  int oneliner;
{
	static vdh1buf;		/* static because we dma out of here */
	vdh1buf = oneliner;

	vdhsnd (&vdh1buf);
}

vdhsnd (buffer)  int *buffer;
{
	vstatebits =| OUTBUSY;
	if ((buffer[0]&V_HTOI) == 0) v_pan ("vdhsnd");
	VDH->cwao = buffer; 
#ifndef	VDHE
	VDH->wco = (buffer->hibyte & 077)+1;
#endif	not VDHE
#ifdef	VDHE
	VDH->wco = -(((buffer->hibyte & 077)+1)<<1);
#endif	VDHE
	VDH->csro =& ~ V_EOTINT; 
	VDH->csro =| V_GO;
}
<File 1>
 ken/acct.c
2235
#
#include "param.h"
#include "inode.h"
#include "user.h"
#include "acct.h"
#include "proc.h"

#ifdef ACCTSYS

int acc_lock;		/* lock for exclusive use */
char	accsvuid;

char	accbuf	[512];
char	*accbufp accbuf;
char	acc_vec [ACCVLEN]; /* for system users to build in */

accinput (vecaddr)	/* internal form */
char	*vecaddr;
{
	register int n;
	register char *vptr, *bptr;

	acc_lock++;
	while (acc_lock > 1)
		sleep( &acc_lock, -1 );
	bptr = accbufp;
	vptr = vecaddr;
	for (n=ACCVLEN; n--; *bptr++ = *vptr++);
	accbufp = bptr;
	accwrite ();
	if (--acc_lock) signal ( &acc_lock );
}

accput ()	/* called via sys accput;addr;passwd */
{
	register int n, t;
	register char *cp;

	acc_lock++;
	while (acc_lock > 1)
		sleep( &acc_lock, -1 );
	u.u_error = 0;
	if (u.u_arg[1] != ACCPSWD) {
		u.u_error = EACCT;
		if (--acc_lock) signal ( &acc_lock );
		return;
	}
	cp = accbufp;
	u.u_base = u.u_arg[0];
	u.u_count = n = ACCVLEN;
	u.u_segflg = 0;	/* data from user space */
	do {
		if (( t = cpass () ) < 0) {
			printf ("ACC cpass error \n");
		}
		*cp++ = t;
	} while --n;
	accbufp = cp;
	accwrite ();
	if (--acc_lock) signal ( &acc_lock );
}


accwrite ()
{
	register int *ip;
	extern schar ();

	if (accbufp < &accbuf[sizeof accbuf - ACCVLEN])
		return;
	/*
	 * set su priv, open file, check access, and write, then reset
	 * su priv
	 */
	accsvuid = u.u_uid;		/* save uid, and set su priv */
	u.u_uid = 0;
	u.u_error = 0;			/* open file */
	u.u_dirp = "/usr/lpd/logs/logfile";
	ip = namei (&schar, 0);		/* file must already be on disk */
	if (ip == NULL)
		goto out;	/* else fix pointer and return */
	if (( !access (ip, IWRITE))	/* su allowed to write ? */
	&& (ip->i_mode & IFMT) == 0) {	/* is it a data file on disk */
		u.u_offset[0] = ip->i_size0;	/* seek eof */
		u.u_offset[1] =
			ip->i_size1 & 0177000; /* force to a block boundary */
		u.u_base = accbuf;	/* set up for write */
		u.u_count = 512;
		u.u_segflg = 1;		/* we are writing from sys space */
		writei (ip);		/* do the io */
	}
	iput (ip);			/* close the file */
out:
	u.u_uid = accsvuid;		/* relinquish su priv */
	u.u_error = 0;
	accbufp = accbuf;
}

#endif ACCTSYS
<File 1>
 ncpp/ftp-s/srvrdaemon.c
2242
#               /* Server FTP daemon */

#include "net_open.h"
#define SIGINR 15
#include "spawn.c"

/*name:
	srvrdaemon

installation:
	if $1x = newerx goto newer
	if $1e = finale goto finale
	cc -L/usr/include:..:/usr/sys/ncpp srvrdaemon.c
	exit
: newer
	if ! { newer srvrdaemon.c /usr/net/etc/ftpsvr } exit
	echo ncpp/ftp-s/srvrdaemon.c:
: finale
	cc -L/usr/include:..:/usr/sys/ncpp -O -s srvrdaemon.c
	if ! -r a.out exit
	if ! -r /usr/sys/ncpp/ftp-s/srvrdaemon.c goto same
	if { cmp -s srvrdaemon.c /usr/sys/ncpp/ftp-s/srvrdaemon.c } goto same
	su cp srvrdaemon.c /usr/sys/ncpp/ftp-s/srvrdaemon.c
	su chmod 444 /usr/sys/ncpp/ftp-s/srvrdaemon.c
	rm -f srvrdaemon.c
: same
	su rm -f /usr/net/etc/ftpsvr
	su cp a.out /usr/net/etc/ftpsvr
	rm -f a.out
	su chmod 544 /usr/net/etc/ftpsvr
	su chown root /usr/net/etc/ftpsvr
	su chgrp system /usr/net/etc/ftpsvr

function:
	to handle server ftp connections to socket 3 and start
	up a program to handle the traffic.  It was done as two
	pieces to keep down the size of process waiting for connections
	to open( that is a smaller program to swap in and out ).


algorithm:
	forever
		set up params for a server connection to socket 3
		wait for a connection to complete

		spawn a child process
			make file desc 0 and 1 the telnet file
			exec the server process
		close the network file


parameters:
	none

returns:
	nothing

globals:
	openparams=

calls:
	open (sys)
	fork (sys)
	exec (sys)
	dup  (sys)
	close(sys)

called by:
	/etc/rc file as /etc/srvrdaemon

history:
	initial coding 4/18/76 by S. F. Holmgren

*/

struct openparams openparams;

main( argc, argv )
int argc;
char **argv;
{
	register netfid;

signal(SIGINR,1);               /* ignore INS interrupts */
while( 1 )
{
	netfid = -1;
	while( netfid < 0 )
	{
		openparam.o_lskt = 3;
		openparam.o_type = 2;
		openparam.o_fskt[0] = 0;
		openparam.o_fskt[1] = 0;
		netfid = open( "/dev/net/anyhost",&openparam );
	}

	if( spawn() == 0 )
	{
		close( 0 );
		dup( netfid );
		close( 1 );
		dup( netfid );
		close( netfid );
		execl( "/usr/net/etc/srvrftp", argv[0], "server process", 0);
		exit( 1 );
	}
	close( netfid );
}
}
<File 1>
 dmr/hp.c
4716
#
/*
 */

/*
 * RP04 disk driver
 *
 * This driver has been tested on a working RP04 for a few hours.
 * It does not attempt ECC error correction and is probably
 * deficient in general in the case of errors and when packs
 * are dismounted.
 */

#include "param.h"
#include "buf.h"
#include "conf.h"
#include "user.h"

struct {
	int	hpcs1;	/* Control and Status register 1 */
	int	hpwc;	/* Word count register */
	int	hpba;	/* UNIBUS address register */
	int	hpda;	/* Desired address register */
	int	hpcs2;	/* Control and Status register 2*/
	int	hpds;	/* Drive Status */
	int	hper1;	/* Error register 1 */
	int	hpas;	/* Attention Summary */
	int	hpla;	/* Look ahead */
	int	hpdb;	/* Data buffer */
	int	hpmr;	/* Maintenance register */
	int	hpdt;	/* Drive type */
	int	hpsn;	/* Serial number */
	int	hpof;	/* Offset register */
	int	hpca;	/* Desired Cylinder address register*/
	int	hpcc;	/* Current Cylinder */
	int	hper2;	/* Error register 2 */
	int	hper3;	/* Error register 3 */
	int	hppos;	/* Burst error bit position */
	int	hppat;	/* Burst error bit pattern */
	int	hpbae;	/* 11/70 bus extension */
};

#define	HPADDR	0176700
#define	NHP	8

struct {
	char	*nblocks;
	int	cyloff;
} hp_sizes[] {
	9614,	0,		/* cyl 0 thru 23 */
				/* cyl 24 thru 43 available */
	-1,	44,		/* cyl 44 thru 200 */
	-1,	201,		/* cyl 201 thru 357 */
	20900,	358,		/* cyl 358 thru 407 */
				/* cyl 408 thru 410 blank */
	40600,	0,
	40600,	100,
	40600,	200,
	40600,	300,
};


struct	devtab	hptab;
struct	buf	hpbuf;

char	hp_openf;

			/* Drive Commands */
#define	GO	01
#define	PRESET	020
#define	RECAL	06
#define RCLR	010
#define OFFSET	014

#define	READY	0200	/* hpds - drive ready */
#define	PIP	020000	/* hpds - Positioning Operation in Progress */
#define	ERR	040000	/* hpcs1 - composite error */

#define	DU	040000	/* hper1 - Drive Unsafe	*/
#define	DTE	010000  /* hper1 - Drive Timing Error	*/
#define	OPI	020000  /* hper1 - Operation Incomplete	*/
		/* Error Correction Code errors */
#define DCK	0100000	/* hper1 - Data Check error */
#define ECH	0100    /* hper1 - ECC hard error */

#define CLR	040	/* hpcs2 - Controller Clear */

#define FMT22	010000	/* hpof - 16 bit /word format */
/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */

#define	trksec	av_back
#define	cylin	b_resid

hpopen(dev)
{

	if(!hp_openf)
		HPADDR->hpcs2 = CLR;
	if(! ( (hp_openf>>(dev.d_minor>>3))&1) ) {
		hp_openf =| 1<<(dev.d_minor>>3);
		HPADDR->hpcs2 = dev.d_minor>>3;
		HPADDR->hpcs1 = RCLR|GO;
		HPADDR->hpcs1 = PRESET|GO;
		HPADDR->hpof = FMT22;
	}
}

hpstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char *p1, *p2;

	bp = abp;
	p1 = &hp_sizes[bp->b_dev.d_minor&07];
	if (bp->b_dev.d_minor >= (NHP<<3) ||
	    bp->b_blkno >= p1->nblocks) {
		bp->b_flags =| B_ERROR;
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	bp->cylin = p1->cyloff;
	p1 = bp->b_blkno;
	p2 = lrem(p1, 22);
	p1 = ldiv(p1, 22);
	bp->trksec = (p1%19)<<8 | p2;
	bp->cylin =+ p1/19;
	spl5();
	if ((p1 = hptab.d_actf)==0)
		hptab.d_actf = bp;
	else {
		for (; p2 = p1->av_forw; p1 = p2) {
			if (p1->cylin <= bp->cylin
			 && bp->cylin <  p2->cylin
			 || p1->cylin >= bp->cylin
			 && bp->cylin >  p2->cylin) 
				break;
		}
		bp->av_forw = p2;
		p1->av_forw = bp;
	}
	if (hptab.d_active==0)
		hpstart();
	spl0();
}

hpstart()
{
	register struct buf *bp;

	if ((bp = hptab.d_actf) == 0)
		return;
	hptab.d_active++;
	HPADDR->hpcs2 = bp->b_dev.d_minor >> 3;
	HPADDR->hpca = bp->cylin;
	rhstart(bp, &HPADDR->hpda, bp->trksec, &HPADDR->hpbae);
}

hpintr()
{
	register struct buf *bp;
	register int ctr;

	if (hptab.d_active == 0)
		return;
	bp = hptab.d_actf;
	hptab.d_active = 0;
	if (HPADDR->hpcs1 & ERR) {		/* error bit */
		deverror(bp, HPADDR->hpcs2, HPADDR->hper1);
		deverror(bp,HPADDR->hper2);
		if(HPADDR->hper1 & (DU|DTE|OPI)) {
			HPADDR->hpcs2 =| CLR;
			HPADDR->hpcs1 = RECAL|GO;
			ctr = 0;
			while ((HPADDR->hpds&PIP) && --ctr);
		}
		HPADDR->hpcs1 = RCLR|GO;
		if (++hptab.d_errcnt <= 10) {
			hpstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	hptab.d_errcnt = 0;
	hptab.d_actf = bp->av_forw;
	bp->b_resid = HPADDR->hpwc;
	iodone(bp);
	hpstart();
}

hpread(dev)
{

	if(hpphys(dev))
	physio(hpstrategy, &hpbuf, dev, B_READ);
}

hpwrite(dev)
{

	if(hpphys(dev))
	physio(hpstrategy, &hpbuf, dev, B_WRITE);
}

hpphys(dev)
{
	register c;

	c = lshift(u.u_offset, -9);
	c =+ ldiv(u.u_count+511, 512);
	if(c > hp_sizes[dev.d_minor & 07].nblocks) {
		u.u_error = ENXIO;
		return(0);
	}
	return(1);
}

<File 1>
 dmr/rx.c
4650
#
/*
 * RX floppy disk driver
 * Ron Broersma -- Naval Ocean Systems Center, San Diego, California
 */

#include "param.h"
#include "buf.h"
#include "conf.h"
#include "user.h"
#include "seg.h"

#ifndef RXADDR
#define	RXADDR	0177170
#endif not RXADDR
#define NRX	2
#define	NRXBLK	500

#define GO	1
#define FILL	0
#define EMPTY	2
#define WRITE	4
#define READ	6
#define RDSTAT	012
#define RDERR	016
#define IENABLE	0100
#define	TR	0200
#define DRVRDY	0200
#define DONE	040
#define INIT	040000
#define INITDONE 4

#define WAIT while(!(RXADDR->rxcs&(TR | DONE)))

struct {
    int rxcs;
    int rxdb;
};

struct devtab rxtab;
struct buf rrxbuf;
struct rxadr {
    char sector;
    char track;
};

rxstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	if (bp->b_blkno >= NRXBLK) {
		if (bp->b_blkno==NRXBLK)
			bp->b_wcount = max(bp->b_wcount, -128);
					/* so we don't get errors when */
					/* trying to read the last 2 sectors */
		else {
			bp->b_flags =| B_ERROR;
			iodone(bp);
			return;
		}
	}
	bp->b_resid = -bp->b_wcount; /* used to tell how far to go */
	bp->b_wcount = 0; /* used to tell how far we are (in bytes!) */
	bp->av_forw = 0;
	spl5();
	if (!(rxtab.d_actf))
		rxtab.d_actf = bp;
	else
		rxtab.d_actl->av_forw = bp;
	rxtab.d_actl = bp;
	if (!(rxtab.d_active)) rxstart();
	spl0();
}

rxaddr(abp)
struct buf *abp;
{
	register int sect, track;
	register struct buf *bp;
	int t1, t2, dtyp;

	bp = abp;
	dtyp = (bp->b_dev.d_minor&6) >> 1;
	sect = (bp->b_blkno<<2) + (bp->b_wcount>>7);
	if (!dtyp)
		sect = sect==36?NRXBLK*4:sect==NRXBLK*4?36:sect;
	t1 = sect/26;
	if ((!dtyp) || dtyp == 2) {
		t2 = sect%26;
		track = t1 + (dtyp?1:0);
		sect = 6*t1 + t2*2 + (t2>=13?1:0);
	}
	else track = t1;
	return((track << 8) + sect%26 + 1);
}

rxto(word)
{
	WAIT;
	RXADDR->rxdb.lobyte = word.lobyte;
	WAIT;
	RXADDR->rxdb.lobyte = word.hibyte;
}

rxfrom()
{
	int word;

	WAIT;
	word.lobyte = RXADDR->rxdb.lobyte;
	WAIT;
	word.hibyte = RXADDR->rxdb.lobyte;
	return(word);
}

char sbuf[128];

rxdata(bp, command, wcount)
struct buf *bp;
{
	register char *cp;
	register int nbytes;
	register int bn;
	int tn[2];
#ifndef UCBUFMOD
	int sa, sps;
#endif not UCBUFMOD

	cp = bp;	/* for speed and size */
	tn[0] = cp->b_xmem;  tn[1] = cp->b_addr;
	dpadd(tn, cp->b_wcount);
	bn = lshift(tn, -6);
	tn[1] =& 077;
	RXADDR->rxcs = command | GO;
	nbytes = wcount<<1;
	if (command == FILL) {
#ifndef UCBUFMOD
		cp = ka6-6;  sa = cp->integ;
		sps = PS->integ;  PS->integ = 030340;
		cp->integ = bn;
		copyin(tn[1], sbuf, nbytes);
		cp->integ = sa;  PS->integ = sps;
#endif not UCBUFMOD
#ifdef UCBUFMOD
		btk(bn, tn[1], sbuf, wcount);
#endif UCBUFMOD
		cp = sbuf;
		do {
			WAIT;
			RXADDR->rxdb.lobyte = *cp++;
		} while --nbytes;
		while(!(RXADDR->rxcs&DONE)) rxto(0);
	}
	else {
		cp = sbuf;
		do {
			WAIT;
			*cp++ = RXADDR->rxdb.lobyte;
		} while --nbytes;
#ifndef UCBUFMOD
		cp = ka6-6;  sa = cp->integ;
		sps = PS->integ;  PS->integ = 030340;
		cp->integ = bn;
		copyout(sbuf, tn[1], wcount<<1);
		cp->integ = sa;  PS->integ = sps;
#endif not UCBUFMOD
#ifdef UCBUFMOD
		ktb(bn, tn[1], sbuf, wcount);
#endif UCBUFMOD
		while(!(RXADDR->rxcs&DONE)) rxfrom();
	}
}

rxstart()
{
	register struct buf *bp;
	register cmd;

	if (!(bp = rxtab.d_actf))
		return;
	cmd = WRITE | GO | IENABLE | ((bp->b_dev.d_minor&1)<<4);
	if (bp->b_flags&B_READ) 
		cmd =| READ;
		else rxdata(bp, FILL, min(bp->b_resid, 64));
	rxtab.d_active++;
	RXADDR->rxcs = cmd;
	rxto(rxaddr(bp));
}

rxintr()
{
	register struct buf *bp;
	int ersave;

	if (!(rxtab.d_active))
		return;
	rxtab.d_active = 0;
	bp = rxtab.d_actf;
	if (RXADDR->rxcs < 0) {
		RXADDR->rxcs = RDSTAT | GO | ((bp->b_dev.d_minor&1)<<4);
		while (!(RXADDR->rxcs&DONE)); 
		if ((ersave = RXADDR->rxdb) & DRVRDY) {
			RXADDR->rxcs = RDERR;
			while(!(RXADDR->rxcs&DONE));
			deverror(bp, ersave, RXADDR->rxdb);
			RXADDR->rxcs = INIT;
			while (!(RXADDR->rxdb&INITDONE));
			if (++rxtab.d_errcnt <= 10) {
				rxstart();
				return;
			}
		}
		bp->b_flags =| B_ERROR;
	}
	if (bp->b_flags&B_READ) 
		rxdata (bp, EMPTY, min(bp->b_resid, 64));
	bp->b_resid =- min(bp->b_resid, 64);
	bp->b_wcount =+ 128;
	if (bp->b_resid && !(bp->b_flags&B_ERROR)) {
		rxstart();
		return;
	}
	rxtab.d_errcnt = 0;
	rxtab.d_actf = bp->av_forw;
	iodone(bp);
	rxstart();
}

rxread(dev)
{
	physio(rxstrategy, &rrxbuf, dev, B_READ);
}

rxwrite(dev)
{
	physio(rxstrategy, &rrxbuf, dev, B_WRITE);
}
<File 1>
 ncpp/mail/mailer.c
15964
#/*
Module Name:
	mailer.c -- ARPAnet mailer daemon

Installation:
	if $1x = newerx goto newer
	if $1e = finale goto finale
	cc -c mailer.c
	if ! -r mailer.o exit
	cc mailer.o /usr/net/hnconv.c
	rm -f mailer.o hnconv.o
	exit
: newer
	if ! { newer mailer.c /usr/net/etc/mailer } exit
	echo ncpp/mail/mailer.c:
: finale
	cc -O -c mailer.c
	if ! -r mailer.o exit
	cc -O -s mailer.o /usr/net/hnconv.c -lj
	if ! -r a.out exit
	if ! -r /usr/sys/ncpp/mail/mailer.c goto same
	if { cmp -s mailer.c /usr/sys/ncpp/mail/mailer.c } goto same
	su cp mailer.c /usr/sys/ncpp/mail/mailer.c
	su chmod 444 /usr/sys/ncpp/mail/mailer.c
	rm -f mailer.c
: same
	if -r /usr/net/etc/mailer su rm -f /usr/net/etc/mailer
	su cp a.out /usr/net/etc/mailer
	rm -f a.out mailer.o hnconv.o
	su chmod 555 /usr/net/etc/mailer
	su chown bin /usr/net/etc/mailer
	su chgrp bin /usr/net/etc/mailer

Synopsis:
	mailer [ delay-time [ bypass-count [ log-word [ debug-dir ] ] ] ]

Function:
	Deliver ARPAnet mail.

Module History:
	modified for Illinois NCP
	return undeliverable mail as a message
	fixed write length in returned.mail
	6Mar79 Greg Noel.  Introduced paranoia about slugish hosts.
	30Apr79 Greg Noel.  Transient remote errors are now retried later.
	15May79 Greg Noel.  450 User Unknown is hard error, not transient.
*/
#include "net_open.h"

struct openparam openparam;

#define true 1
#define false 0
#define SLPTIME  600 /* default sleep time   */
#define NTBYPASS 3   /* default bypass count */
#define MSGSEP "\001\001\001\001\n"
#define MSGSEPL 5

char hostname[100];
char mailcomd[256] { "mail <list of user names>                           "};
char returnto[256];
char linebuf[256];
char badhost[256];
char mailbuf[512];
char netbuf[512];


int dirfd;
int nflag, nflag1, tvec[2];
int slptime;
int ntbypass;

/*	don't separate these two declarations	*/
int entry;
char filename[16];
/*	don't separate the preceding two declarations */

int statbuf[32];
int timoutflg;
int mailproc;
int timeout();
struct fcb {
	int f_fd;
	char *f_ptr;
	char *f_buf;
	int f_count;
}
	netfcb,mailfcb;

/* name:
	maildaemon

function:
	To see if there is any mail waiting delivery to some other
	site on the network, and deliver it.

algorithm:
	If there is any mail, send it.
	Wait a while and look for mail again.

parameters:
	If argv[1] is present, it is the number of seconds to sleep
	between passes through the mail directory.  If it is absent
	or 0, a default value is used (SLPTIME).
	If argv[2] is present, it is the number of passes through
	which to bypass mail for hosts which are not responding.
	If argv[3] is present, messages will be written out indicating
	the progress of the mailer.
	If argv[4] is present, use this as the mail directory and make
	one pass through it.  Used for debugging.

returns:

globals:
	dirfd		fd of /usr/netmail

calls:
	open	sys
	seek	sys
	printf	library
	get_next_file
	ship_it_off

called by:

history:
	Design and initial coding by Mark Kampe, 12/27/75

 */
main(argc, argv)
 int argc;
 char **argv;
{
	int i;
	extern int fout;

	signal(1,1);
	signal(2,1);
	signal(3,1);

	mailproc = getpid();
	if (argc < 2 ||  (slptime=atoi(argv[1])) <= 0) slptime = SLPTIME;
	if (argc < 3 || (ntbypass=atoi(argv[2])) <= 0) ntbypass = NTBYPASS;
	if (argc > 3) nflag++;

	if (chdir(argc > 4 ? argv[4] : "/usr/netmail") < 0  ||
	   (dirfd = open(".",0)) < 0) {
		printf("Unable to open /usr/netmail\n");
		exit(-1);
	}

	fout = dup(1);	/* buffer all further output */
	log("Sleep time = %d, Bypass = %d\n", slptime, ntbypass);
	nflag1 = 0;

	openparam.o_host = 0;
	netfcb.f_fd = -1;
loop:
		/*
		 *  The mailer should lock this directory so that conflicts
		 *  with other incarnations of the mailer will not occur.
		 *  The lock should be established here and removed below.
		 *  The routine get_next_file must be modified to skip
		 *  over the lock.  Another alternative is to fork for each
		 *  new destination host encountered and lock only on the
		 *  basis of destination; this will maximize parallelism
		 *  of transmission.
		 */
	seek(dirfd,0,0);
	while(get_next_file())
		ship_it_off();
	closenet();	/* close last connection */

	for (i=0; i<256; i++)
	if (badhost[i]) --badhost[i];

	if(nflag1) {
		log("Ending cycle\n");
		nflag1 = 0;
	}

		/* Remove lock here.... */

	if(argc>4) exit(0);	/* used for testing */

	sleep(slptime);
	goto loop;
}

/* name:
	log

function:
	to log something if logging is enabled.

algorithm:
	if logging is enabled
		print leading banner
		print message to be logged

parameters:
	identical to printf

returns:
	nothing

globals:
	nflag	set if logging is enabled
	tvec	time at which current cycle began

calls:
	printf	(sys)
	time	(sys)
	ctime	(sys)

called by:
	many places

history:
	24 Aug 77 coded by Greg Noel
	24 Jul 78 modified by Greg Noel to condense logging printout

*/
log(t, a, b, c, d)
{
	if (nflag)
	{	time(tvec);
		printf("%-16.16sMailer: ", ctime(tvec)+4);
		printf(t, a, b, c, d);
		flush();
		nflag1++;
	}
}

/* name:
	get_next_file

function:
	To find get the next file in /usr/netmail and set up all
	of the parameters for the mailing.

algorithm:
	Read next non-empty record
	if end of file, return error
	set up hostname
		mail command line
		file name (for future deletion)
		root of sender for possible return.
	return true

parameters:

returns:
	boolean	true means a file was found and set up
		false means no more files in directory

globals:
	hostname
	mailcomd
	mailfcb
	filename
	dirfd
	returnto

calls:
	read	(sys)
	open	(sys)
	getline
	unlink	(sys)

called by:
	main

history:
	Initial coding by Mark Kampe	11/27/75

 */
get_next_file()
{	register char *p;
	register char *s;
	register int i;

 loop:	i = read(dirfd,&entry,16);
	if (i != 16) return(false);
	if (entry == 0) goto loop;
	if (filename[0] == '.') goto loop;

	if (filename[13]) filename[14] = '\000';

	mailfcb.f_fd = open(filename,0);
	if (mailfcb.f_fd < 0)
		goto badfile;

	mailfcb.f_count = 0;
	mailfcb.f_buf = mailbuf;
	p = getline(&mailfcb);
	if (p == 0) goto badfile;

	s = hostname;
	while(*p != ':') if ((*s++ = *p++) == '\000') goto badfile;
	*s++ = '\000';
	p++;

	s = &mailcomd[5];
	while(*p != ':') if ((*s++ = *p++) == '\000') goto badfile;
	*s++ = '\000';
	p++;
	
	s = returnto;
	if (*p == ':')
		*s = '\0';
	else {  while(*p != ':') if ((*s++ = *p++) == '\000') goto badfile;
		for(p = "/.mail"; *s++ = *p++;);
	}

	return(true);

badfile:
	log("File %s in illegal format -- deleted\n", filename);
	unlink(filename);
	goto loop;
}
/* name:
	ship_it_off

function:
	To carry out the protocol to mail off a file over the network

algorithm:
	Connect to the forign host
	Await a ready command
	send the mail command
	Await the send your mail response.
	send the mail
	Await the confirmation.
	Delete the file if the transmission was successful.
	If there was a permanent failure, put the file in the sender's
	 root with an explanatory message.

parameters:

returns:

globals:
	hostname	contains name of foreign host
	mailcomd	contains a mail command with all appt names
	netfcb		file descriptor of network file
	filename	name of the current file
	returnto	sender's mailbox (if return is necessary);
	badhost

calls:
	getline
	writef
	reply
	open	sys
	close	sys
	getline

called by:
	main

history:
	Initial coding by Mark Kampe  12/27/75
	Modified by Greg Noel 7/24/78 to maintain connection if destination
	    host does not change

 */
ship_it_off()
{
	extern char *hnconv();
	int hnum;
	register char *p;
	register int i;
	register int rtnfd;
	int timeproc;

	netfcb.f_count = 0;
	openparam.o_fskt[1] = 3;
	openparam.o_timo = 60;
	if ((hnum=atoi(hnconv(hostname))) <= 0) /***/
	{	log("Mail in %s for %s at %s\n",
			filename, &mailcomd[5], hostname); /***/
		p = "Destination host is unknown.";
		goto fail;
	}

	if (badhost[hnum])
		goto nogood;

	log("Mail in %s for %s at %s\n", filename, &mailcomd[5], hostname);

	if ((openparam.o_host&0377) != hnum) {
		closenet();
		openparam.o_host = hnum;
		set_alarm(120);
		netfcb.f_fd = open("/dev/net/anyhost",&openparam);
		alarm(0);
		if (netfcb.f_fd <= 0)
		{	log("Unable to open connection\n");
			badhost[hnum] = ntbypass; /* number of times to bypass */
			goto nogood;
		}
		netfcb.f_count = 0;
		netfcb.f_buf = netbuf;

		do {	p = getline(&netfcb);
			if (p == 0) goto tempfail;
			i = reply(p);
			if (i >= 400) goto tempfail;
		} while(i != 300);
	}

	i = writef(netfcb.f_fd,mailcomd);
	if (i < 0) goto tempfail;
	i = writef(netfcb.f_fd,"\r\n");
	if (i < 0) goto tempfail;
	i = 0;
	while(i != 350)
	{	p = getline(&netfcb);
		if (p == 0) goto tempfail;
		i = reply(p);
		if (i == 951) continue;		/* Mail will be forwarded... */
		if (i == 504)
			switch (loginfirst())
			{	case -1: goto fail;
				case 0:  goto tempfail;
				case 1:  continue;
			};
		if (i >= 500) goto fail;
		if (i == 450) goto fail;	/* User unknown */
		if (i > 400) goto tempfail;
		if (i == 400) goto fail;	/* Service not implemented */
		if (i == 331) goto fail;	/* Need account parameter */
	}

	while(p = getline(&mailfcb)) {
		i = writef(netfcb.f_fd,p);
		if (i < 0) goto tempfail;
		i = writef(netfcb.f_fd,"\r\n");
		if (i < 0) goto tempfail;
	}

	i = writef(netfcb.f_fd, ".\r\n");
	if (i < 0) goto tempfail;

	i = 0;
	while(i != 256)
	{	p = getline(&netfcb);
		if (p == 0) goto tempfail;
		i = reply(p);
		if (i >= 500) goto fail;
		if (i > 400) goto tempfail;
		if (i > 300) goto fail;
	}

	close(mailfcb.f_fd);
	unlink(filename);
	return(true);

fail:
	log("Unrecoverable error; mail returned to sender\n");
	/* now return the message to the sender */
	if (returnto  &&
	       (   ((rtnfd=open(returnto,1))     >= 0) ||
		   ((rtnfd=creat(returnto,0666)) >= 0)   )   )
	{	seek(rtnfd,0,2);
		writef(rtnfd,"From: mailer\n");
		writef(rtnfd,"Subject: Undeliverable mail\n\n");
		writef(rtnfd, "Mail for "); writef(rtnfd, &mailcomd[5]);
		writef(rtnfd, " at "); writef(rtnfd, hostname);
		writef(rtnfd, " undeliverable because:\n\t");
		writef(rtnfd,p);
		writef(rtnfd,"\n------- Unsent message is below -------\n\n");
		seek(mailfcb.f_fd,0,0);
		mailbuf[0] = 0;
		while(mailbuf[0] != '\n') read(mailfcb.f_fd,mailbuf,1);
		while((i = read(mailfcb.f_fd,mailbuf,512)) > 0)
			write(rtnfd,mailbuf,i);
		close(rtnfd);
	}
	unlink(filename);
tempfail:
	closenet();
nogood:
	close(mailfcb.f_fd);
	return(false);
}

closenet()
{
	openparam.o_host = 0;
	if(netfcb.f_fd < 0) return;	/* not currently open */
	writef(netfcb.f_fd,"BYE\r\n");
	getline(&netfcb);	/* keep NCP happy until 'flush user' fixed */
	close(netfcb.f_fd);
	netfcb.f_fd = -1;
}

timeout()
{	timoutflg++;
	wait();		/* get rid of zombie */
	reset();	/* return to ship_it_off */
}

/* name:
	getline

function:
	To retrieve one "line" from the file on the specified descriptor.

algorithm:
	Ignore carriage returns.
	While the next character is not a new line, stash it in linebuf;
	null terminate the string in linebuf;
	return a pointer to linebuf;

	If we should reach end of file and have a line started, terminate
		it and return.  If no line is started, return a zero.

parameters:
	*fcb	file control block for the file in question.

returns:
	*char	pointer to a null terminated string.
	or a zero indicating end of file.

globals:
	linebuf		destination of read

calls:
	read	(sys)

called by:
	get_next_file
	ship_it_off

history:
	Initial coding by Mark Kampe 12/27/75

 */
getline(afcb)
 struct fcb *afcb;
{	register int count;
	register char *nextin;
	register char *nextout;
	char lastchar;

	count = afcb->f_count;
	nextin = afcb->f_ptr;
	nextout = linebuf;
	lastchar = '\000';

	while(lastchar != '\n') {
		if (count <= 0) {
			set_alarm(60);
			count = read(afcb->f_fd,afcb->f_buf,512);
			alarm(0);
			if (count <= 0) 
			{	count = -1;
				nextin = "\n";
			}
			else nextin = afcb->f_buf;
		}
		count--;
		lastchar = *nextin++;
		if(nextout < &linebuf[sizeof linebuf])
			*nextout++ = lastchar;
		if (lastchar == '\r') nextout--;
	}
	afcb->f_count = count;
	afcb->f_ptr = nextin;
	*--nextout = '\000';
	if (nextout == linebuf)
		if (count < 0) return(0);
	if (nextout == &linebuf[1] && linebuf[0] == '.') {
		*nextout++ = ' ';
		*nextout = '\0';
	}
	return(linebuf);
}
/* name:
	writef

function:
	To write a null terminated string out to the specified file descriptor.

algorithm:
	Find the length of the string.
	Write it out .

parameters:
	int	file descriptor
	*char	address of string to be written.

returns:
	int	value returned by write.

globals:

calls:
	write	(sys)

called by:
	ship_it_off

history:
	Initial coding by Mark Kampe 12/27/75

 */
writef(afd,as)
 int afd;
 char *as;
{	register char *s;
	register int i;
	register int j;

	i = 0;
	for(s = as; *s++; i++);
	if(i == 0) return 0;
	set_alarm(60);
	j = write(afd, as, i);
	alarm(0);
	if (j != i)	/* did error occur? */
	{	log("write(%d,0%o,%d) returned %d.\n",afd,as,i,j);
		log("line was '%s'.\n", as);
	}
	return(j);
}
/* name:
	reply

function:
	To find the reply number from a network message.

algorithm:
	Convert the first three characters into an integer.
	If any are non numeric, return a zero.

parameters:
	*char	pointer to the string in question (null terminated)

returns:
	int

globals:

calls:

called by:
	ship_it_off

history:
	Initial coding by Mark Kampe 12/27/75

 */
reply(ap)
 char *ap;
{	register char c;
	int i;
	register int j;
	register char *s;

	s = ap;
	log("%s\n",s);

	while((*s<'0') || (*s>'9')) if (*s++ == '\000') return(0);	/* fuckers at multics */

	j = 0;
	for(i = 3; i; i--)
	{	c = *s++;
		if ((c < '0') || (c > '9')) return(0);
		j =* 10;
		j =+ c;
		j =- '0';
	}
	return(j);
}
/* name:
	loginfirst

function:
	to login to a bastard host who insists on it

algorithm:
	send a "user NETML\npassNETML\n";
	wait for the 330 230
	resend the mail command

	if a transmission failure return 0
	if a bad reply return -1
	else return 1

parameters:

returns:
	-1	permanent failure
	0	temperary failure
	1	success

globals:
	netfcb
	mailcomd

calls:
	getline
	reply
	writef

called by:
	ship_it_off

history:
	Designed and coded by a disgruntled Mark Kampe 1/5/76

 */
loginfirst()
{	register int i;
	register char *p;

	i = writef(netfcb.f_fd,"USER NETML\r\n");
	if (i<=0) return(0);

	i = 0;
	while(i != 330)
	{	p = getline(&netfcb);
		if (p == 0) return(0);
		i = reply(p);
		if (i == 230) goto gotin;
		if (i >= 400) return(-1);
	};

	i = writef(netfcb.f_fd, "PASS NETML\r\n");
	if (i <= 0) return(0);
	i = 0;
	while(i != 230)
	{	p = getline(&netfcb);
		if (p == 0) return(0);
		i = reply(p);
		if (i >= 400) return(-1);
	}

	gotin:
	i = writef(netfcb.f_fd, mailcomd);
	if (i<=0) return(0);
	i = writef(netfcb.f_fd, "\r\n");
	if (i <= 0) return(0);

	return(1);
}
/*
name:
	set_alarm, ring

function:
	to terminate an operation if the remote host is too slugish.

algorithm:
	set an alarm for the specified period.
	when the alarm occurs, just return -- the interrupted system call
	    will return -1.

parameters:
	the number of seconds to wait

returns:
	yes

globals:
	none.

calls:
	alarm	(sys)
	signal	(sys)
	log

called by:
	several people.

history:
	coded 6Mar79 by Greg Noel
*/
set_alarm(v)
int v;
{
	int ring();

	signal(14, &ring);
	alarm(v);
}
ring()
{
	log("Timeout\n");
}
<File 1>
 dmr/rl.c
4123
#

/*
 * RL01 disk driver
 *
 * Tom Ferrin - 19 July 78
 * UCSF Computer Graphics Laboratory
 *
 * This driver has now been running for several weeks on a dual drive 11/60.
 * It doesn't minimize seek scheduling & totally ignores DEC's bad block table.
 */

#include "param.h"
#include "buf.h"
#include "conf.h"
#include "user.h"

#ifndef NRL
#define	NRL	4
#endif not NRL
#ifndef RLADDR
#define	RLADDR	0174400
#endif not RLADDR
#define	NRLBLK	10220	/* block = 2 sectors = 512 bytes, last track reserved */

#define HNF	010000
#define OPI	02000
#define	CRDY	0200
#define	IENABLE	0100
#define RCOM	014
#define WCOM	012
#define RHCOM	010
#define SCOM	06
#define GSCOM	04
#define DRST	010
#define DSDIR	04
#define DSTAT	02
#define DMARK	01
#define VC	01000

#define rlexec(a,b) dp->rlcs=((a)<<8)|(b); while((dp->rlcs&CRDY)==0)

struct {
	int rlcs;
	int rlba;
	int rlda;
	int rlmp;
};

struct {
	char openf;	/* open flag */
	int cyltrk;	/* current cylinder & head select */
} rl01[NRL];

struct	devtab	rltab;
struct	buf	rrlbuf;

rlopen(dev, flag)
{
	register int unit, *dp, i;

	if (rl01[unit=dev.d_minor].openf == 0) {
		dp = RLADDR;
		spl5();
		dp->rlda = DRST|DSTAT|DMARK;
		rlexec(unit, GSCOM);
		rlexec(unit, RHCOM);
		i = dp->rlcs;
		spl0();
		if (i < 0) {
			u.u_error = EIO;
			return;
		}
		rl01[unit].cyltrk = dp->rlmp & ~077;
		rl01[unit].openf++;
	}
}

rlstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register int i;

	bp = abp;
	if (bp->b_flags&B_PHYS)
		mapalloc(bp);
	if (bp->b_dev.d_minor >= NRL || (i=bp->b_blkno) >= NRLBLK) {
		u.u_error = ENXIO;
		bp->b_flags =| B_ERROR;
		iodone(bp);
		return;
	}
	bp->av_back = (i/20)<<6 | (i%20)<<1;	/* desired address */
	bp->av_forw = 0;
	spl5();
	if (rltab.d_actf==0)
		rltab.d_actf = bp;
	else
		rltab.d_actl->av_forw = bp;
	rltab.d_actl = bp;
	if (rltab.d_active==0)
		rltran();
	spl0();
}

rltran()
{
	register struct buf *bp;
	register int i;

	if ((bp=rltab.d_actf) == 0)
		return;
	i = bp->av_back;
	i = (40-(i&077))*128;	/* words left on track */
	if (i >= -bp->b_wcount)
		bp->b_resid = 0;
	else {
		bp->b_resid = bp->b_wcount+i; /* words left for next transfer */
		bp->b_wcount = -i;
	}
	rlstart();
}

rlstart()
{
	register struct buf *bp;
	register int da, *dp;
	int unit, ca, rda;

	rltab.d_active++;
	bp = rltab.d_actf;
	unit = bp->b_dev.d_minor;
	da = bp->av_back;
	dp = &rl01[unit].cyltrk;
	if ((da&~077) != *dp) {
		ca = *dp & ~100;
		*dp = da & ~077;
		dp = RLADDR;
		rda = da & ~0177;
		da = (da&0100)>>2;
		if ((ca =- rda) < 0)
			ca = -ca|DSDIR;
		dp->rlda = da|ca|DMARK;
		rlexec(unit, SCOM);
	}
	dp = &RLADDR->rlmp;
	*dp = bp->b_wcount;
	*--dp = bp->av_back;
	*--dp = bp->b_addr;
	da = (bp->b_xmem&03)<<4 | unit<<8 | IENABLE;
	if (bp->b_flags&B_READ)
		da =| RCOM;
	else
		da =| WCOM;
	*--dp = da;
}

rlintr()
{
	register struct buf *bp;
	register int *dp, i;
	int n[2];

	if (rltab.d_active == 0)
		return;
	bp = rltab.d_actf;
	rltab.d_active = 0;
	if ((dp=RLADDR)->rlcs < 0) {	/* error bit */
		n[0] = dp->rlcs;
		i = bp->b_dev.d_minor;
		dp->rlda = DSTAT|DMARK;
		rlexec(i, GSCOM);
		n[1] = dp->rlmp;
		deverror(bp, n[0], n[1]);
		dp->rlda = DRST|DSTAT|DMARK;
		rlexec(i, GSCOM);
		if ((n[0]&(HNF|OPI))==(HNF|OPI) || (n[1]&VC)) {
			rlexec(i, RHCOM);
			if (dp->rlcs < 0)
				goto abort;
			rl01[i].cyltrk = dp->rlmp & ~077;
		}
		if (++rltab.d_errcnt <= 10) {
			rlstart();
			return;
		}
	  abort:
		bp->b_flags =| B_ERROR;
		bp->b_resid = 0;
	}
	rltab.d_errcnt = 0;
	if (bp->b_resid) {
		n[0] = bp->b_xmem;	/* more of previous transfer */
		n[1] = bp->b_addr;
		dpadd(n, -bp->b_wcount<<1);
		bp->b_xmem = n[0];
		bp->b_addr = n[1];
		bp->b_wcount = bp->b_resid;
		i = bp->av_back;
		bp->av_back = (i&~077) + 0100;
	} else {
		rltab.d_actf = bp->av_forw;
		iodone(bp);
	}
	rltran();
}

rlread(dev)
{

	physio(rlstrategy, &rrlbuf, dev, B_READ);
}

rlwrite(dev)
{

	physio(rlstrategy, &rrlbuf, dev, B_WRITE);
}
<File 1>
 dmr/tm.c
6249
#
/*
 */

/*
 * TM tape driver
 */

#include "param.h"
#include "buf.h"
#include "conf.h"
#include "user.h"

struct {
	int tmer;
	int tmcs;
	int tmbc;
	int tmba;
	int tmdb;
	int tmrd;
};

struct	devtab	tmtab;
struct	buf	rtmbuf;

#ifdef NOSC	/* extra flag in rtmbuf.b_flags to handle odd-length writes */
#define B_ODDLEN 0100000
#endif NOSC
#define B_SCOM	 0040000

char	t_openf[8];
#define TMopen	0001
#define TMeof	0002	/* last read an EOF */
#define TMflush	0004	/* purge all I/O to this device */
char	*t_blkno[8];
char	*t_nxrec[8];

#define	TMADDR	0172520

#define NOREW	020

#define	GO	01
#define NOCMD	000
#define	RCOM	002
#define	WCOM	004
#define	WEOF	006
#define	SFORW	010
#define	SREV	012
#define	WIRG	014
#define	REW	016
#define	DENS	060000		/* 9-channel */
#define	IENABLE	0100
#define	CRDY	0200
#define GAPSD	010000
#define	TUR	1
#define	HARD	0102200	/* ILC, EOT, NXM */
#define	EOF	0040000

#define	SSEEK	1
#define	SIO	2
#define SCOM	3

tmopen(dev, flag)
{
	register dminor;

	dminor = dev.d_minor&07;
	if (t_openf[dminor])
		u.u_error = ENXIO;
	else {
		t_openf[dminor] = TMopen;
		t_blkno[dminor] = 0;
		t_nxrec[dminor] = 65535;
	}
}

tmclose(adev, flag)
{
	register int dminor, dev;

	dev = adev;
	dminor = dev.d_minor&07;
	if (flag) {
		tcommand(dev, WEOF);
		tcommand(dev, WEOF);
		tcommand(dev, dev&NOREW ? SREV : REW);
	} else {
		if((dev&NOREW)==0)
			tcommand(dev, REW);
		else if((t_openf[dminor] & TMeof) == 0)
			tcommand(dev, SFORW);
	}
	t_openf[dminor] = 0;
}

tcommand(dev, com)
{
	register struct buf *bp;

	bp = &rtmbuf;
	spl6();
	while(bp->b_flags & B_BUSY) {
		bp->b_flags =| B_WANTED;
		sleep(bp, PRIBIO);
	}
	spl0();
	bp->b_dev = dev;
	bp->b_resid = com;
	bp->b_blkno = 0;
	bp->b_flags = B_SCOM | B_BUSY | B_READ;
	tmqup(bp);
	iowait(bp);
	if(bp->b_flags & B_WANTED)
		wakeup(bp);
	bp->b_flags = 0;
	return(bp->b_resid);
}

tmstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char **p;

	bp = abp;
	if(bp->b_flags&B_PHYS)
		mapalloc(bp);
	p = &t_nxrec[bp->b_dev.d_minor&07];
	if (*p <= bp->b_blkno) {
		if (*p < bp->b_blkno) {
			bp->b_flags =| B_ERROR;
			iodone(bp);
			return;
		}
		if (bp->b_flags&B_READ) {
			clrbuf(bp);
			iodone(bp);
			return;
		}
	}
	if ((bp->b_flags&B_READ)==0)
		*p = bp->b_blkno + 1;
	tmqup(bp);
}

tmqup(abp)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	bp->av_forw = 0;
	spl5();
	if (tmtab.d_actf==0)
		tmtab.d_actf = bp;
	else
		tmtab.d_actl->av_forw = bp;
	tmtab.d_actl = bp;
	if (tmtab.d_active==0)
		tmstart();
	spl0();
}

tmstart()
{
	register struct buf *bp;
	register int com;
	int unit;
	register char *blkno;

    loop:
	if ((bp = tmtab.d_actf) == 0)
		return;
	com = ((bp->b_dev.d_minor&~NOREW)<<8) | ((bp->b_xmem & 03) << 4);
	if(bp->b_flags&B_SCOM) {
		if(bp->b_resid == NOCMD) {
			/* don't want IENABLE bit or else */
			/* interrupt will occur immediately */
			TMADDR->tmcs = com;
			bp->b_resid = TMADDR->tmer;
			tmdone();
			goto loop;
		}
		tmtab.d_active = SCOM;
		TMADDR->tmbc = 1;	/* i.e. infinity, or until eof */
		TMADDR->tmcs = bp->b_resid | com | IENABLE | GO;
		return;
	}
	unit = bp->b_dev.d_minor&07;
	if ((t_openf[unit] & TMflush) || (TMADDR->tmcs & CRDY)==0) {
		bp->b_flags =| B_ERROR;
		tmdone();
		goto loop;
	}
	t_openf[unit] =& ~TMeof;
	blkno = t_blkno[unit];
	if (blkno != bp->b_blkno) {
		tmtab.d_active = SSEEK;
		if (blkno < bp->b_blkno) {
			com =| SFORW|IENABLE|GO;
			TMADDR->tmbc = blkno - bp->b_blkno;
		} else {
			com =| SREV|IENABLE|GO;
			TMADDR->tmbc = bp->b_blkno - blkno;
		}
		TMADDR->tmcs = com;
		return;
	}
	tmtab.d_active = SIO;
	TMADDR->tmbc = bp->b_wcount << 1;
#ifdef NOSC
	if(bp->b_flags & B_ODDLEN) TMADDR->tmbc++;
#endif NOSC
	TMADDR->tmba = bp->b_addr;		/* core address */
	TMADDR->tmcs = com | ((bp->b_flags&B_READ)? RCOM|IENABLE|GO:
	    ((tmtab.d_errcnt)? WIRG|IENABLE|GO: WCOM|IENABLE|GO));
}

tmdone()
{
	register struct buf *bp;

	bp = tmtab.d_actf;
	tmtab.d_errcnt = 0;
	tmtab.d_actf = bp->av_forw;
	tmtab.d_active = 0;
	iodone(bp);
}

tmintr()
{
	register struct buf *bp;
	register int unit;

	if ((bp = tmtab.d_actf)==0)
		return;
	unit = bp->b_dev.d_minor&07;
	/* ignore errors on SCOM */
	if (tmtab.d_active == SCOM) {
		bp->b_resid = TMADDR->tmbc -1;	/* return skip count */
		tmdone();
		tmstart();
		return;
	}
	if (TMADDR->tmcs < 0) {		/* error bit */
		while(TMADDR->tmrd & GAPSD) ; /* wait for gap shutdown */
		if ((TMADDR->tmer&(HARD|EOF))==0 && tmtab.d_active==SIO) {
			if (++tmtab.d_errcnt < 10) {
				t_blkno[unit]++;
				tmtab.d_active = 0;
				tmstart();
				return;
			}
/*
			deverror(bp, TMADDR->tmer, 0);
 */
		} else if (TMADDR->tmer&EOF) {
			t_openf[unit] =| TMeof;
			if (bp != &rtmbuf)	/* flush future I/O on */
				t_openf[unit] =| TMflush; /* cooked device */
			bp->b_resid = bp->b_wcount << 1;
			tmdone();
			tmstart();
			return;
		}
/*
		else	deverror(bp, TMADDR->tmer, 0);
 */
		bp->b_flags =| B_ERROR;
		tmtab.d_active = SIO;
	}
	if (tmtab.d_active == SIO) {
		t_blkno[unit]++;
		bp->b_resid = TMADDR->tmbc;
		tmdone();
	} else
		t_blkno[unit] = bp->b_blkno;
	tmstart();
}
#ifndef NOSC
tmread(dev)
{
	tmphys(dev);
	physio(tmstrategy, &rtmbuf, dev, B_READ);
	u.u_count = -rtmbuf.b_resid;
}

tmwrite(dev)
{
	tmphys(dev);
	physio(tmstrategy, &rtmbuf, dev, B_WRITE);
	u.u_count = 0;
}

tmphys(dev)
{
	register unit, a;

	unit = dev.d_minor&07;
	a = lshift(u.u_offset, -9);
	t_blkno[unit] = a;
	t_nxrec[unit] = ++a;
}
#endif NOSC
#ifdef NOSC
		/* Special NOSC code to permit odd-length reads and writes */
tmread(dev)
{
	physio(tmstrategy, &rtmbuf, dev, tmphys(dev)|B_READ);
	u.u_count = -rtmbuf.b_resid;
}

tmwrite(dev)
{
	physio(tmstrategy, &rtmbuf, dev, tmphys(dev)|B_WRITE);
	u.u_count = 0;
}

tmphys(dev)
{
	register unit, a;

	unit = dev.d_minor&07;
	a = lshift(u.u_offset, -9);
	t_blkno[unit] = a;
	t_nxrec[unit] = ++a;
	if(u.u_count & 01) {
		u.u_count++;
		return (B_ODDLEN);
	}
	return 0;
}
#endif NOSC
<File 1>
 dmr/dz.c
15304
#
/*
module name:
	dz.c

function:
	Device driver for the DEC dz11 8 line asynchronous multiplexor

globals containied:
	dz11	array of tty structures for the dz11 lines
	dzaddrs	array of addresses of the various dz11 controllers
	dzmodem	array specifying which dz ports have modem control
	dzcycling	whether or not modem control is cycling

routines contained:
	dzopen		open system call routine
	dzclose		close system call routine
	dzread		read system call routine
	dzwrite         write system call routine
	dzrint          receive interrupt routine
	dzxint          transmit interrupt routine
	dzstart         I/O startup routine
	dzsgtty         sgtty system call routine
	dzparam         hardare parameter setting routine
	dzstatus	modem control cycling routine

routines referenced:
	ttread, ttwrite, ttyinput, ttystty, ttrstrt
	sleep, wakeup
	timeout
	issig, psig

modules referenced:
	user.h          needed because of the error code definitions
	param.h         contains constants required by user.h
	conf.h          contains the device structure definition
	tty.h           contains definition of tty structure
	options.h       to get system compile time parameters

compile time parameters:
	UCLATTY         define this if you are using the ucla tty.c
			leave this undefined if you are using the standard one

history:
	Designed and coded by Mark Kampe, 9/27/77.
*/
#include "param.h"
#include "conf.h"
#include "user.h"
#include "tty.h"

#define true    0177777
#define false   0000000
#define then    /* */

#ifndef NDZ11
#define NDZ11   8		/* default number of DZ lines */
#endif not NDZ11
#ifndef DZADDRS
#define DZADDRS 0760100		/* default address of dz registers */
#endif not DZADDRS
#ifndef DZMODEM
#define DZMODEM	1, 1, 1, 1, 1, 1, 1, 1	/* default modem control enable */
#endif not DZMODEM
#define DZRATE	5*HZ		/* sample modem status every 5 seconds */

struct  tty     dz11[ NDZ11 ];

struct  dzregs          /* the readable DZ11 registers          */
{       int     dzcsr;          /* control status register      */
	int     dzrcv;          /* receive buffer register      */
	int     dztcr;          /* transmit control register    */
	int     dzmsr;          /* modem status register        */
};

struct                  /* the writeable DZ11 registers         */
{       int     dzcsr;          /* control status register      */
	int     dzlpr;          /* line parameter register      */
	int     dztcr;          /* transmit control register    */
	int     dztdr;          /* transmit data register       */
};

struct  dzregs  *dzaddrs[] { DZADDRS };	/* addresses of DZ registers */

/* specification of which lines have modem control enabled */
char    dzmodem[ NDZ11 ]                /* Setting the i'th entry to a 1  */
{	DZMODEM		};		/* enables modem control on that  */
					/* line.  Although this array is  */
					/* statically initialized, it can */
					/* be changed dynamically.        */

int dzcycling;			/* whether or not the dz has a modem test
				   pending on any modem controlled lines */
extern	ttrstrt();
int	dzstart();

char speedmap[ 16 ]             /* map a Unix speed into a DZ11 equivalent */
{       000,                    /* 0 baud */
	000,                    /* 50 baud */
	001,                    /* 75 baud */
	002,                    /* 110 baud */
	003,                    /* 134.5 baud */
	004,                    /* 150 baud */
	000,                    /* dz doesn't support 200 baud */
	005,                    /* 300 baud */
	006,                    /* 600 baud */
	007,                    /* 1200 baud */
	010,                    /* 1800 baud */
	012,                    /* 2400 baud */
	014,                    /* 4800 baud */
	016,                    /* 9600 baud */
	000,                    /* external 1 not supported */
	000                     /* external 2 not supported */
};


/* definitions for bits in the DZ11 registers */
#define MUXCLR  0000020         /* clear multiplexer    in csr  */
#define SCENABL 0000040         /* scan enable          in csr  */
#define IENABLE 0040100         /* xmt & rcv interrupts in csr  */
#define RINT    0000200         /* receive done bit     in csr  */
#define XINT    0100000         /* transmit done bit    in csr  */
#define LINENUM 0003400         /* line # mask    in rcv & csr  */
#define PERROR  0010000         /* parity error         in rcv  */
#define FRERROR 0020000         /* framing error        in rcv  */
#define OVERRUN 0040000         /* data over run        in rcv  */
#define BITS_6  0000010         /* six bit characters   in lpr  */
#define BITS_7  0000020         /* seven bit characters in lpr  */
#define BITS_8  0000030         /* eight bit characters in lpr  */
#define ONE_SB  0000000         /* one stop bit         in lpr  */
#define TWO_SB  0000040         /* two stop bits        in lpr  */
#define PENABLE 0000100         /* parity enabled       in lpr  */
#define OPAR    0000200         /* odd parity selected  in lpr  */
#define SSPEED  0000007         /* unix notation for 300 baud   */
#define RCV_ON  0010000         /* receiver enable      in lpr  */
#define DEFAULT 0012470         /* initial parameters for  lpr  */

/* name:
	dzopen  and dzclose

function:
	open system call routine for the dz11
	close system call routine for the dz11

algorithm:
open:
	validate the device unit number
	get the controller address
	if the line isn't already open
		initialize the hardware
		if modem control is enabled on that line
			wait for the line to come up
		initialize the software parameters
	call ttyopen on it

close:
	flush any pending output
	mark the line closed
	disable further input from that line

parameters:
	device designation      (major and minor numbers)
	flag                    (whether or not write access is desired)

returns:
	a setting of u.u_error if it fails

globals:
	dz11            tty tables for the dz11 lines
	dzaddrs         pointer to the registers
	dzmodem
	dzcycling

calls:
	ttyopen         to complete the opening operation
	wflushtty       to flush the queues
	dzparam         to set the initial parameters
	dzstatus	to start modem status cycling

called by:
	openi through cdevsw
*/
dzopen( dev , flag )
 int dev, flag;
{       register struct dzregs *dzp;
	register struct tty *tp;
	register int unit;

	unit = dev.d_minor;
	if (unit >= NDZ11)
		then    return( u.u_error = ENXIO );

	dzp = dzaddrs[ (unit >> 3) ];
	tp = &dz11[ unit ];
	unit =& 7;

	if ((tp->t_state & ISOPEN) == 0) then
	{       dzp->dztcr =| (0400 << unit);
		dzp->dzcsr =| (SCENABL|IENABLE);

		if ( dzmodem[dev.d_minor] ) then
		{       spl5();
			dzp->dzlpr = unit|DEFAULT;
			tp->t_state = WOPEN;
			if (~dzcycling)
				then	dzstatus();
			while((tp->t_state & CARR_ON) == 0)
			{       sleep( tp, TTIPRI );
				if (issig()) then
				{       spl0();
					psig();
					return;
				}
			}
			spl0();
		}

		tp->t_state =| SSTART|CARR_ON;
		tp->t_flags = XTABS|ECHO|CRMOD|EVENP|ODDP;
		tp->t_erase = CERASE;
		tp->t_kill = CKILL;
		tp->t_speeds = SSPEED | (SSPEED << 8);
		tp->t_addr = dzstart;

		dzparam( dev.d_minor );
	}

	ttyopen( dev, tp );
}


dzclose( dev, flag )
 int dev, flag;
{       register struct tty *tp;
	register int unit;
	register struct dzregs *dzp;

	unit = dev.d_minor;
	tp = &dz11[ unit ];
	dzp = dzaddrs[ unit >> 3 ];

	wflushtty( tp );

	tp->t_state = 0;
	unit =& 7;
	dzp->dzlpr = unit;
	dzp->dztcr =& ~(0400 << unit);
}
/* name:
	dzread and dzwrite

function:
	read system call routine for the dz11
	write system call routine for the dz11

algorithm:
	convert the minor device designation into a pointer to a tty struct
	call the appropriate device independent routine

parameters:
	major and minor device designations

globals:
	dz11

calls:
	ttread
	ttwrite

called by:
	readi and writei through the cdevsw
*/

dzread( dev )
 int dev;
{       register int unit;
	register struct tty *tp;

	unit = dev.d_minor;
	tp = &dz11[ unit ];
	ttread( tp );
}

dzwrite( dev )
 int dev;
{       register int unit;
	register struct tty *tp;

	unit = dev.d_minor;
	tp = &dz11[ unit ];
	ttwrite( tp );
}
/* name:
	dzrint

function:
	receive interrupt handling routine for the dz11

algorithm:
	get a pointer to the registers for the interrupting dz11
	while there is data in the silo
		get the next character
		if from an illegal line,
			continue
		if a framing error
			say the character was a null
		call ttyinput with the character

parameters:
	dz11 controller number of the interrupting unit

globals:
	dz11    tty structures for the dz11 lines
	dzaddrs address of dz11 controllers

calls:
	ttyinput        to process the received characters

called by:
	trap
*/
dzrint( unit )
 int unit;
{       register struct dzregs *dzp;
	register struct tty *tp;
	register int c;
	int lineno;

	dzp = dzaddrs[ unit ];
	unit =<< 3;

	while((c = dzp->dzrcv) < 0)
	{       lineno = ((c & LINENUM) >> 8) + unit;
		if (lineno >= NDZ11)
			then    continue;

		tp = &dz11[ lineno ];

		if (c & PERROR)
			then    continue;

		if (c & FRERROR)
			then    c = 0;
			else    c =& 0377;

		if (tp->t_state & ISOPEN)
			then    ttyinput( c , tp );
			else    wakeup( tp );
	}
}
/* name:
	dzxint

function:
	dz11 transmit interrupt routine

algorithm:
	get a pointer to the controller that interrupted
	while the dj thinks that I am done with some line
		get the line number
		get the associated tty structure
		if it is timed out, or done disable this line
		get the next character
		if it is a delay indication, schedule the restart
			and disable this line
		else set the character up for output
		if there is a sleeping writer and the queue has drained some
			wake him up

parameters:
	the controller number for the dz11 that interrupted

globals:
	dz11    pointers to the teletype structures for the dz11 lines
	dzaddrs pointers to the dz11 controllers

calls:
	wakeup
	timeout

called by:
	trap
*/
dzxint( unit )
 int unit;
{       register struct dzregs *dzp;
	register struct tty *tp;
	register int lineno;
	int  c;

	dzp = dzaddrs[ unit ];
	unit =<< 3;
	while( dzp->dzcsr&XINT )
	{       lineno = (dzp->dzcsr&LINENUM) >> 8;
		tp = &dz11[ lineno + unit ];

		if ((tp->t_state&TIMEOUT) || ((tp->t_state&ISOPEN) == 0))
			then goto disable;

		if ((c = getc( &tp->t_outq )) < 0 )
			then goto disable;

#ifdef  UCLATTY
		if (c == CESCAPE)
			then c = getc( &tp->t_outq );
			else
#endif
		if (c & 0200)   then
		{       tp->t_state =| TIMEOUT;
			if (c =& 0177)
				then timeout( ttrstrt, tp, c&0177 );
#ifdef  UCLATTY
				else tp->t_state =| STOPOUT;
#endif
				goto disable;
		}

		dzp->dztdr = c;

		if ((tp->t_state&ASLEEP) && (tp->t_outq.c_cc <= TTLOWAT)) then
		{       tp->t_state =& ~ASLEEP;
			wakeup( &tp->t_outq );
		}
		continue;

disable:
		dzp->dztcr =& ~(1 << lineno);
	}

	dzp->dzcsr =| IENABLE;
}
/* name:
	dzstart

function:
	to start an output operation on a dz line

algorithm:
	if the line is timed out, do nothing
	else enable it for transmission

parameters:
	pointer to the tty structure for that line

globals:
	dzaddrs         pointers to addresses of dz11 controllers
	dz11            table of tty structures for dz lines

calls:
	wakeup          to notify a sleeping writer
	timeout         to schedule resuming output

called by:
	dzxint          to continue an output operation
	ttstart         to initiate an output operation
*/


dzstart( atp )
 struct tty *atp;
{       register struct dzregs *dzp;
	register struct tty *tp;
	register int lineno;

	tp = atp;

	if (tp->t_state&TIMEOUT)
		then    return;

	lineno = tp - dz11;
	dzp = dzaddrs[ lineno >> 3 ];
	lineno =& 7;

	dzp->dztcr =| (1 << lineno);
}
/* name:
	dzsgtty

function:
	dz11 sgtty system call routine

algorithm:
	get a pointer to the corresponding tty structure
	call ttystty
	if anything changed, call dzparam

parameters:
	major and minor device designation
	argument vector pointer

globals:
	dzaddrs         addresses of dz11 controllers

calls:
	ttystty         device independent special function routine

called by:
	sgtty           (throught cdevsw)
*/

#ifdef  UCLATTY
dzsgtty( dev )
 int dev;
#endif
#ifndef   UCLATTY
dzsgtty( dev , v )
 int dev, *v;
#endif
{       register struct tty *tp;
	register int unit;

	unit = dev.d_minor;
	tp = &dz11[ unit ];

#ifdef  UCLATTY
	if (ttystty( tp ))
#endif
#ifndef   UCLATTY
	if (ttystty( tp, v ))
#endif
		then    return;
		else    dzparam( unit );
}
/* name:
	dzparam

function:
	DZ11 parameter setting routine

algorithm:
	ascertain what controller the specified unit is on
	get a pointer to its tty structure
	if the speed is set to 0, just turn the line off
	else, compute the parametersd
	and install them for that line

parameters:
	DZ unit number

globals:
	dzaddrs         to get the controller addresses
	dz11            tty structure for the dz lines

called by:
	dzopen          to initialize the line for the first time
	dzsgtty         to change parameters
*/

dzparam( unit )
 int unit;
{       register struct dzregs *dzp;
	register struct tty *tp;
	register int parms;
	int speed;

	dzp = dzaddrs[ unit >> 3 ];
	tp = &dz11[ unit ];
	unit =& 7;

	if (tp->t_speeds == 0) then
	{       dzp->dzlpr = unit;       /* just turn the line off */
		return;
	}
	else
	{       speed = tp->t_speeds&017;
		speed = speedmap[ speed ];
	}
	parms = unit|RCV_ON;
	parms =| (speed << 8);
	if (tp->t_flags & EVENP) then
		if (tp->t_flags & ODDP)
			then    parms =| BITS_8;
			else    parms =| (BITS_7|PENABLE);
		else    parms =| (BITS_7|OPAR|PENABLE);
	if (tp->t_speeds.lobyte == 3)
		then    parms =| TWO_SB;

	dzp->dzlpr = parms;
}
/* name:
	dzstatus

function:
	to see if the lines with modem control enabled still have the
	appropriate signals up

algorithm:
	For all open lines with modem control enabled,
		if the carrier has dropped, send a hangup to the group
	if any open lines still have modem control
		schedule the next call to dzstatus
	else	turn off dzcycling

parameters:
	none

globals:
	dz11
	dzmodem
	dzcycling

calls:
	timeout

called by:
	timeout

*/
dzstatus()
{	register int line;
	register struct tty *tp;
	register struct dzregs *dzp;
	int numlines;

	numlines = 0;
	for( line = 0; line < NDZ11; line++ )
	{	dzp = dzaddrs[ line >> 3 ];
		tp = &dz11[ line ];

		if ((dzmodem[ line ] == 0) || ((tp->t_state&(ISOPEN+WOPEN)) == 0) )
			then	continue;

		numlines++;

		if (dzp->dzmsr & (0400 << (line&7))) then
		{	tp->t_state =| CARR_ON;
			if (tp->t_state&WOPEN)
				then	wakeup( tp );
		}
		else
		{	tp->t_state =& ~CARR_ON;
			if (tp->t_state & ISOPEN) 
				then	signal( tp->t_pgrp, SIGHUP );
		}
	}

	if (numlines) then
	{	timeout( &dzstatus, 0, DZRATE );
		dzcycling = true;
	}
	else	dzcycling = false;
}