Xinu7/src/serve11/sys/ttyiin.c

/* ttyiin.c ttyiin, erase1, eputc, echoch */

#include <conf.h>
#include <kernel.h>
#include <tty.h>
#include <io.h>
#include <slu.h>

/*------------------------------------------------------------------------
 *  ttyiin  --  lower-half tty device driver for input interrupts
 *------------------------------------------------------------------------
 */
INTPROC	ttyiin(iptr)
	register struct	tty	*iptr;	/* pointer to tty block		*/
{
	register struct	csr *cptr;
	register int	ch;
	int	ct;

	cptr = iptr->ioaddr;
	if ( (ch=cptr->crbuf) & SLUERMASK)	/* read char from device*/
		return;				/* discard if error	*/
	if (iptr->imode == IMRAW) {
		if (scount(iptr->isem) >= IBUFLEN) {
			return;			/* discard if no space	*/
		}
		iptr->ibuff[iptr->ihead++] = ch & SLUCHMASK;
		if (iptr->ihead	>= IBUFLEN)	/* wrap buffer pointer	*/
			iptr->ihead = 0;
	        signal(iptr->isem);
	} else {				/* cbreak | cooked mode	*/
		ch &= SLUCHMASK;
		if ( ch	== RETURN && iptr->icrlf )
			ch = NEWLINE;
		if (iptr->iintr && ch == iptr->iintrc) {
			send(iptr->iintpid, INTRMSG);
			eputc(ch, iptr, cptr);
			return;
		}
		if (iptr->oflow) {
			if (ch == iptr->ostart)	{
				iptr->oheld = FALSE;
				cptr->ctstat = SLUENABLE;
				return;
			}
			if (ch == iptr->ostop) {
				iptr->oheld = TRUE;
				return;
			}
		}
		iptr->oheld = FALSE;
		if (iptr->imode	== IMCBREAK) {		/* cbreak mode	*/
			if (scount(iptr->isem) >= IBUFLEN) {
				eputc(iptr->ifullc,iptr,cptr);
				return;
			}
			iptr->ibuff[iptr->ihead++] = ch;
			if (iptr->ihead	>= IBUFLEN)
				iptr->ihead = 0;
			if (iptr->iecho)
				echoch(ch,iptr,cptr);
			if (scount(iptr->isem) < IBUFLEN)
				signal(iptr->isem);
		} else {				/* cooked mode	*/
			if (ch == iptr->ikillc && iptr->ikill) {
				iptr->ihead -= iptr->icursor;
				if (iptr->ihead	< 0)
					iptr->ihead += IBUFLEN;
				iptr->icursor =	0;
				eputc(RETURN,iptr,cptr);
				eputc(NEWLINE,iptr,cptr);
				return;
			}
			if (ch == iptr->ierasec	&& iptr->ierase) {
				if (iptr->icursor > 0) {
					iptr->icursor--;
					erase1(iptr,cptr);
				}
				return;
			}
			if (ch == NEWLINE || ch == RETURN ||
				(iptr->ieof && ch == iptr->ieofc)) {
				if (iptr->iecho) {
					echoch(ch,iptr,cptr);
					if (ch == iptr->ieofc)
						echoch(NEWLINE,iptr,cptr);
				}
				iptr->ibuff[iptr->ihead++] = ch;
				if (iptr->ihead	>= IBUFLEN)
					iptr->ihead = 0;
				ct = iptr->icursor+1; /* +1 for \n or \r*/
				iptr->icursor =	0;
				signaln(iptr->isem,ct);
				return;
			}
			ct = scount(iptr->isem);
			ct = ct	< 0 ? 0	: ct;
			if ((ct	+ iptr->icursor) >= IBUFLEN-1) {
				eputc(iptr->ifullc,iptr,cptr);
				return;
			}
			if (iptr->iecho)
				echoch(ch,iptr,cptr);
			iptr->icursor++;
			iptr->ibuff[iptr->ihead++] = ch;
			if (iptr->ihead	>= IBUFLEN)
				iptr->ihead = 0;
		}
	}
}

/*------------------------------------------------------------------------
 *  erase1  --  erase one character honoring erasing backspace
 *------------------------------------------------------------------------
 */
LOCAL erase1(iptr,cptr)
	struct	tty   *iptr;
	struct	csr	*cptr;
{
	char	ch;

	if (--(iptr->ihead) < 0)
		iptr->ihead += IBUFLEN;
	ch = iptr->ibuff[iptr->ihead];
	if (iptr->iecho) {
		if (ch < BLANK || ch == 0177) {
			if (iptr->evis)	{
				eputc(BACKSP,iptr,cptr);
				if (iptr->ieback) {
					eputc(BLANK,iptr,cptr);
					eputc(BACKSP,iptr,cptr);
				}
			}
			eputc(BACKSP,iptr,cptr);
			if (iptr->ieback) {
				eputc(BLANK,iptr,cptr);
				eputc(BACKSP,iptr,cptr);
			}
		} else {
			eputc(BACKSP,iptr,cptr);
			if (iptr->ieback) {
				eputc(BLANK,iptr,cptr);
				eputc(BACKSP,iptr,cptr);
			}
		}
	} else
		cptr->ctstat = SLUENABLE;
}

/*------------------------------------------------------------------------
 *  echoch  --  echo a character with visual and ocrlf options
 *------------------------------------------------------------------------
 */
LOCAL echoch(ch, iptr, cptr)
	char	ch;		/* character to	echo			*/
	struct	tty   *iptr;	/* pointer to I/O block for this devptr	*/
	struct	csr	*cptr;	/* csr address for this devptr		*/
{
	if ((ch==NEWLINE||ch==RETURN)&&iptr->ecrlf) {
		eputc(RETURN,iptr,cptr);
		eputc(NEWLINE,iptr,cptr);
	} else if ((ch<BLANK||ch==0177) && iptr->evis) {
		eputc(UPARROW,iptr,cptr);
		eputc(ch+0100,iptr,cptr);	/* make it printable	*/
	} else {
		eputc(ch,iptr,cptr);
	}
}

/*------------------------------------------------------------------------
 *  eputc - put one character in the echo queue
 *------------------------------------------------------------------------
 */
LOCAL eputc(ch,iptr,cptr)
	char	ch;
	struct	tty   *iptr;
	struct	csr	*cptr;
{
	iptr->ebuff[iptr->ehead++] = ch;
	if (iptr->ehead	>= EBUFLEN)
		iptr->ehead = 0;
	cptr->ctstat = SLUENABLE;
}