Ultrix-3.1/sys/sys/prim.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * SCCSID: @(#)prim.c	3.0	4/21/86
 */
#include <sys/param.h>
#include <sys/tty.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/buf.h>
/*#include <sys/clist.h>	included in systm.h */
#include <sys/seg.h>

int	nodev();	/* needed by cinit() below */


#ifdef	UCB_CLIST
/*
 * Modification to move clists out of kernel data space.
 * Clist space is allocated by startup.
 */
memaddr clststrt;		/* Physical click address of clist */
extern unsigned clstdesc;	/* PDR for clist segment when mapped */

#else	UCB_CLIST
extern struct	cblock	cfree[];
#endif	UCB_CLIST

extern int nclist;
struct	cblock	*cfreelist;
int	cbad;

/*
 * Character list get/put
 */
getc(p)
register struct clist *p;
{
	register struct cblock *bp;
	register int c, s;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	s = spl6();
#ifdef	UCB_CLIST
	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	if (p->c_cc <= 0) {
		c = -1;
		p->c_cc = 0;
		p->c_cf = p->c_cl = NULL;
	} else {
		c = *p->c_cf++ & 0377;
		if (--p->c_cc<=0) {
			bp = (struct cblock *)(p->c_cf-1);
			bp = (struct cblock *) ((int)bp & ~CROUND);
			p->c_cf = NULL;
			p->c_cl = NULL;
			bp->c_next = cfreelist;
			cfreelist = bp;
		} else if (((int)p->c_cf & CROUND) == 0){
			bp = (struct cblock *)(p->c_cf);
			bp--;
			p->c_cf = bp->c_next->c_info;
			bp->c_next = cfreelist;
			cfreelist = bp;
		}
	}
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	splx(s);
	return(c);
}

/*
 ************************************************
 *						*
 *	q_to_b() moved to /sys/dev/mpxpk.c	*
 *						*
 ************************************************
 */

#ifdef	DH
/*
 * Return count of contiguous characters
 * in clist starting at q->c_cf.
 * Stop counting if flag&character is non-null.
 */
ndqb(q, flag)
register struct clist *q;
{
	register cc;
	int s;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	s = spl6();
	if (q->c_cc <= 0) {
		cc = -q->c_cc;
		goto out;
	}
	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
	cc -= (int)q->c_cf;
	if (q->c_cc < cc)
		cc = q->c_cc;
	if (flag) {
		register char *p, *end;

#ifdef	UCB_CLIST
		saveseg5(sav5);
		mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
		p = q->c_cf;
		end = p;
		end += cc;
		while (p < end) {
			if (*p & flag) {
				cc = (int)p;
				cc -= (int)q->c_cf;
				break;
			}
			p++;
		}
#ifdef	UCB_CLIST
		restorseg5(sav5);
#endif	UCB_CLIST
	}
out:
	splx(s);
	return(cc);
}



/*
 * Update clist to show that cc characters
 * were removed.  It is assumed that cc < CBSIZE.
 */
ndflush(q, cc)
register struct clist *q;
register cc;
{
	register s;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	s = spl6();
	if (q->c_cc < 0) {
		if (q->c_cf != NULL) {
			q->c_cc += cc;
			q->c_cf += cc;
			goto out;
		}
		q->c_cc = 0;
		goto out;
	}
	if (q->c_cc == 0) {
		goto out;
	}
	if (cc > CBSIZE || cc <= 0) {
		cbad++;
		goto out;
	}
	q->c_cc -= cc;
	q->c_cf += cc;
	if (((int)q->c_cf & CROUND) == 0) {
		register struct cblock *bp;

#ifdef	UCB_CLIST
		saveseg5(sav5);
		mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
		bp = (struct cblock *)(q->c_cf) -1;
		if (bp->c_next) {
			q->c_cf = bp->c_next->c_info;
		} else {
			q->c_cf = q->c_cl = NULL;
		}
		bp->c_next = cfreelist;
		cfreelist = bp;
#ifdef	UCB_CLIST
		restorseg5(sav5);
#endif	UCB_CLIST
	} else
	if (q->c_cc == 0) {
		register struct cblock *bp;
#ifdef	UCB_CLIST
		saveseg5(sav5);
		mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
		q->c_cf = (char *)((int)q->c_cf & ~CROUND);
		bp = (struct cblock *)(q->c_cf);
		bp->c_next = cfreelist;
		cfreelist = bp;
		q->c_cf = q->c_cl = NULL;
#ifdef	UCB_CLIST
		restorseg5(sav5);
#endif	UCB_CLIST
	}
out:
	splx(s);
}
#endif	DH


putc(c, p)
register struct clist *p;
{
	register struct cblock *bp;
	register char *cp;
	register s;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	s = spl6();
#ifdef	UCB_CLIST
	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
		if ((bp = cfreelist) == NULL) {
#ifdef	UCB_CLIST
			restorseg5(sav5);
#endif	UCB_CLIST
			splx(s);
			return(-1);
		}
		cfreelist = bp->c_next;
		bp->c_next = NULL;
		p->c_cf = cp = bp->c_info;
	} else if (((int)cp & CROUND) == 0) {
		bp = (struct cblock *)cp - 1;
		if ((bp->c_next = cfreelist) == NULL) {
#ifdef	UCB_CLIST
			restorseg5(sav5);
#endif	UCB_CLIST
			splx(s);
			return(-1);
		}
		bp = bp->c_next;
		cfreelist = bp->c_next;
		bp->c_next = NULL;
		cp = bp->c_info;
	}
	*cp++ = c;
	p->c_cc++;
	p->c_cl = cp;
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	splx(s);
	return(0);
}



/*
 * copy buffer to clist.
 * return number of bytes not transfered.
 */
b_to_q(cp, cc, q)
register char *cp;
struct clist *q;
register int cc;
{
	register char *cq;
	register struct cblock *bp;
	register s, acc;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	if (cc <= 0)
		return(0);
	acc = cc;


	s = spl6();
#ifdef	UCB_CLIST
	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
		if ((bp = cfreelist) == NULL)
			goto out;
		cfreelist = bp->c_next;
		bp->c_next = NULL;
		q->c_cf = cq = bp->c_info;
	}

	while (cc) {
		if (((int)cq & CROUND) == 0) {
			bp = (struct cblock *) cq - 1;
			if ((bp->c_next = cfreelist) == NULL)
				goto out;
			bp = bp->c_next;
			cfreelist = bp->c_next;
			bp->c_next = NULL;
			cq = bp->c_info;
		}
		*cq++ = *cp++;
		cc--;
	}
out:
	q->c_cl = cq;
	q->c_cc += acc-cc;
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	splx(s);
	return(cc);
}

/*
 * Initialize clist by freeing all character blocks, then count
 * number of character devices. (Once-only routine)
 *
 * Also set a bit in the character device configuration
 * word (el_cdcw) for each device present. Only the first 16
 * devices are checked because only those before `tty'
 * are of interest.
 */

cinit()
{
	register int ccp;
	register struct cblock *cp;
	register struct cdevsw *cdp;

#ifdef	UCB_CLIST
	cfree = SEG5;	/* Virt. Addr. of clists (0120000 - 0140000 */
	ccp = (int)cfree;
	mapseg5(clststrt, clstdesc);
#else	UCB_CLIST
	ccp = (int)cfree;
	ccp = (ccp+CROUND) & ~CROUND;
#endif	UCB_CLIST
	for(cp=(struct cblock *)ccp; cp <= &cfree[nclist-1]; cp++) {
		cp->c_next = cfreelist;
		cfreelist = cp;
	}
#ifdef	UCB_CLIST
	normalseg5();
#endif	UCB_CLIST
	ccp = 0;
	for(cdp = cdevsw; cdp->d_open; cdp++) {
		if((ccp < 16) && (cdp->d_write != &nodev))
			el_cdcw |= (1 << ccp);
		ccp++;
	}
	nchrdev = ccp;
}

/*
 ********************************************************
 *							*
 *	getw() and putw() moved to /sys/dev/mpxpk.c	*
 *							*
 ********************************************************
 */

/*
 * Given a non-NULL pointer into the list (like c_cf which
 * always points to a real character if non-NULL) return the pointer
 * to the next character in the list or return NULL if no more chars.
 *
 * Callers must not allow getc's to happen between nextc's so that the
 * pointer becomes invalid.  Note that interrupts are NOT masked.
 */
char *
nextc(p, cp)
register struct clist *p;
register char *cp;
{
	register char *rcp;
#ifdef	UCB_CLIST
	segm sav5;

	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	if (p->c_cc && ++cp != p->c_cl) {
		if (((int)cp & CROUND) == 0)
			rcp = ((struct cblock *)cp)[-1].c_next->c_info;
		else
			rcp = cp;
	}
	else {
		rcp = 0;
	}
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	return rcp;
}

/*
 * lookc returns the character pointed at by cp, which is a nextc-style
 * (e.g. possibly mapped out) char pointer.
 */
lookc(cp)
register char *cp;
{
	register char rc;
#ifdef	UCB_CLIST
	segm sav5;

	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	rc = *cp;
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	return rc;
}

/*
 * Remove the last character in the list and return it.
 */
unputc(p)
register struct clist *p;
{
	register struct cblock *bp;
	register int c, s;
	struct cblock *obp;
#ifdef	UCB_CLIST
	segm sav5;
#endif	UCB_CLIST

	s = spl6();
#ifdef	UCB_CLIST
	saveseg5(sav5);
	mapseg5(clststrt, clstdesc);
#endif	UCB_CLIST
	if (p->c_cc <= 0)
		c = -1;
	else {
		/*
		 * We don't have unsigned chars, so keep it from
		 * sign extending. 4/21/85 -Dave Borman
		 */
		c = (*--p->c_cl)&0377;
		if (--p->c_cc <= 0) {
			bp = (struct cblock *)p->c_cl;
			bp = (struct cblock *)((int)bp & ~CROUND);
			p->c_cl = p->c_cf = NULL;
			bp->c_next = cfreelist;
			cfreelist = bp;
		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
			bp = (struct cblock *)p->c_cf;
			bp = (struct cblock *)((int)bp & ~CROUND);
			while (bp->c_next != (struct cblock *)p->c_cl)
				bp = bp->c_next;
			obp = bp;
			p->c_cl = (char *)(bp + 1);
			bp = bp->c_next;
			bp->c_next = cfreelist;
			cfreelist = bp;
			obp->c_next = NULL;
		}
	}
#ifdef	UCB_CLIST
	restorseg5(sav5);
#endif	UCB_CLIST
	splx(s);
	return (c);
}

/*
 * Put the chars in the ``from'' queue
 * on the end of the ``to'' queue.
 */
catq(from, to)
struct clist *from, *to;
{
	register c;

	while ((c = getc(from)) >= 0)
		 putc(c, to);
}