[comp.os.minix] new tty driver

marks@elec.uq.oz (Mark Schulz) (09/22/88)

Please reply to hannam.uq.oz . I'm using someone elses account to send
this.

echo x - ioctl.c
sed 's/^X//' >ioctl.c <<'*-*-END-of-ioctl.c-*-*'
X/* ioctl.c - get/set character device modes
X *
X * Modifications:
X * 18/9/88  -	Modified for new tty driver & improved efficiency of
X *			code produced.
X */
X
X#include "lib.h"
X#include <minix/com.h>
X#include <sgtty.h>
X
Xtypedef union {
X	long				l;
X	struct {int i0, i1;}		i;
X	struct {char c0,c1,c2,c3;}	c;
X	} olong;
X
Xunion ioctl_struct {
X  struct sgttyb *argp;
X  struct tchars *argt;
X  int		*argi;
X  char		*argc;
X};
X
XPUBLIC int ioctl(fd, request, u)
Xint fd;
Xint request;
Xunion ioctl_struct u;
X{
X  olong tmp;
X  int n;
X
X  M.TTY_REQUEST = request;
X  M.TTY_LINE = fd;
X
X  switch(request) {
X     case TIOCGETP:
X  	n = callx(FS, IOCTL);
X	tmp.l = M.TTY_FLAGS;
X  	u.argp->sg_flags  = tmp.i.i0;
X  	tmp.l = M.TTY_SPEK;
X	u.argp->sg_ospeed = tmp.c.c3;		/* Non - compat with old */
X	u.argp->sg_ispeed = tmp.c.c2;
X	u.argp->sg_erase  = tmp.c.c1;
X	u.argp->sg_kill   = tmp.c.c0;
X  	return n;
X
X     case TIOCSETN:
X     case TIOCSETP:
X	tmp.i.i1 = 0;
X	tmp.i.i0 = u.argp->sg_flags;
X	M.TTY_FLAGS = tmp.l;
X	tmp.c.c3 = u.argp->sg_ospeed;
X	tmp.c.c2 = u.argp->sg_ispeed;
X	tmp.c.c1 = u.argp->sg_erase;
X	tmp.c.c0 = u.argp->sg_kill;
X	M.TTY_SPEK = tmp.l;
X	break;
X 
X     case TIOCGETC:
X  	n = callx(FS, IOCTL);
X  	tmp.l = M.TTY_SPEK;
X  	u.argt->t_intrc  = tmp.c.c3;
X  	u.argt->t_quitc  = tmp.c.c2;
X  	u.argt->t_startc = tmp.c.c1;
X  	u.argt->t_stopc  = tmp.c.c0;
X  	tmp.l = M.TTY_FLAGS;
X  	u.argt->t_eofc   = tmp.c.c1;
X  	u.argt->t_brkc   = tmp.c.c0;
X  	return n;
X
X     case TIOCSETC:
X	tmp.c.c3 = u.argt->t_intrc;
X	tmp.c.c2 = u.argt->t_quitc;
X	tmp.c.c1 = u.argt->t_startc;
X	tmp.c.c0 = u.argt->t_stopc;
X  	M.TTY_SPEK = tmp.l;
X  	tmp.i.i1 = 0;
X  	tmp.c.c1 = u.argt->t_eofc;
X  	tmp.c.c0 = u.argt->t_brkc;
X  	M.TTY_FLAGS = tmp.l;
X  	break;
X
X     case FIONREAD:
X     case TIOCMODG:
X     case TIOCGETM:
X	n= callx(FS, IOCTL);
X	*u.argi = (unsigned) M.TTY_FLAGS;
X	return n;
X
X     case TIOCMODS:
X     case TIOCSETM:
X	M.TTY_FLAGS = (unsigned long) *u.argi;
X	break;
X
X     case TIOCSTI:
X	M.TTY_FLAGS = (unsigned long) *u.argc;
X	break;
X
X     case TIOCSBRK:
X     case TIOCCBRK:
X     case TIOCSDTR:
X     case TIOCCDTR:
X     case TIOCSMLB:
X     case TIOCCMLB:
X     case TIOCSTART:
X     case TIOCSTOP:
X	break;
X
X     default:
X	errno = -(EINVAL);
X	return -1;
X  }
X  return callx(FS, IOCTL);
X}
*-*-END-of-ioctl.c-*-*
echo x - login.c
sed 's/^X//' >login.c <<'*-*-END-of-login.c-*-*'
X/* login - log into the system		Author: Andrew Hannam
X *
X * Modifications:
X * 21/9/88   -	Added wtmp support as in V1.3
X *
X * BUGS:
X * Doesn't handle LCASE detection.
X * Doesn't kill parent process's.
X */
X
X#include <signal.h>
X#include <sgtty.h>
X#include <pwd.h>
X#include <sys/stat.h>
X
X#define NULL (char *) 0
X
X/* default files */
X#define DEFSH		"/bin/sh"
X#define WTMPFILE	"/usr/adm/wtmp"
X
X/* default INT, QUIT, START, STOP, EOF, BRK chars (for the login process) */
Xstruct tchars tchars = {-1, -1, 021, 023, 004, -1};
X#define DEFKILL		'@'
X#define DEFERASE	'\b'
X
X/* The following chars need to be changed before exec'ing the shell */
X#define DEFINT		0177
X#define DEFQUIT		034
X
X/* The following flags are used by login, passwd & the user process */
X#define FLAGMASK	(ANYP|ODDP|EVENP)
X#define LOGINFLAGS	ECHO|XTABS|CRTERA|DECCTQ|CRMOD|CRTKIL
X#define PASSWDFLAGS	CRMOD|DECCTQ
X#define USERFLAGS	ECHO|XTABS|CRTERA|DECCTQ|CRMOD|CRTKIL|CTLECH
X
Xchar Aname[16]	=	"-";
Xchar Epath[]	=	"PATH=:/bin:/usr/bin";
Xchar Ehome[64]	=	"HOME=";
Xchar Euser[24]	=	"USER=";
Xchar Eterm[]	=	"TERM=minix";
Xchar Eshell[64] =	"SHELL=";
X
Xchar *arge[]= { Epath, Ehome, Euser, Eterm, Eshell, (char *) 0 };
Xchar *argp[]= { Aname, (char *)0 };
Xchar ttyname[] = "tty?";
X#define TDIGIT 3
Xchar *wtmpfile = WTMPFILE;
X#define WTMPSIZE 8
X
Xchar *crypt();
Xstruct passwd *getpwnam();
X
Xmain() 
X{
Xstatic	char    buf[30],
X		buf1[30];
X	int     n, n1, bad;
Xstatic	struct stat statbuf;
Xstatic	struct sgttyb args;
Xstatic	struct passwd *pwd;
X
X	/* Make sure the file system is valid (in case we wish to reboot) */
X	sync();
X
X	/* Get current modes and set default chars for login */
X	ioctl(0, TIOCGETP, &args);
X	ioctl(0, TIOCSETC, &tchars);
X	args.sg_kill = DEFKILL;
X	args.sg_erase = DEFERASE;
X
X	/* Set up signals to defaults */
X	for(n = 1; n <= NR_SIGS; ++n) signal(n, SIG_DFL);
X
X	/* Look up /dev/tty number. */
X	fstat(0, &statbuf);
X	ttyname[TDIGIT] = '0' + statbuf.st_rdev & 0377;
X
X	/* Check for login, passwd until sucessful */
X	for (;;) {
X	/* Get login name */
X		bad = 0;
X		args.sg_flags &= FLAGMASK;
X		args.sg_flags |= LOGINFLAGS;
X		ioctl (0, TIOCSETP, &args);
X		do {
X			write(1,"login: ",7);
X			n = read (0, buf, 30);
X		} while (n < 2);
X		buf[n - 1] = 0;
X	/* Look up login/passwd. */
X		if ((pwd = getpwnam (buf)) == 0)
X			bad++;
X	/* Get passwd */
X		if (bad || strlen (pwd->pw_passwd) != 0) {
X			args.sg_flags &= FLAGMASK;
X			args.sg_flags |= CRMOD|DECCTQ;
X			ioctl (0, TIOCSETP, &args);
X			write(1,"Password: ",10);
X			n1 = read (0, buf1, 30);
X			buf1[n1 - 1] = 0;
X			write(1,"\n",1);
X			if (bad) crypt(buf1,"*");
X			if (bad || strcmp (pwd->pw_passwd, crypt(buf1, pwd->pw_passwd))) {
X				write (1,"Login incorrect\n",16);
X				continue;
X			}
X		}
X
X/* Successful login. */
X	/* Creat wmtp entry. */
X		wtmp(ttyname, pwd->pw_name);
X	/* Set up directories and uid,gid */
X		chdir("/");
X		setgid (pwd->pw_gid);
X		setuid (pwd->pw_uid);
X		chdir (pwd->pw_dir);
X	/* Set up environment, params & shell */
X		strcat(Ehome,pwd->pw_dir);
X		strcat(Euser,pwd->pw_name);
X		if (!pwd->pw_shell || !*pwd->pw_shell)
X			pwd->pw_shell = DEFSH;
X		strcat(Eshell,pwd->pw_shell);
X		strcat(Aname,rindex(pwd->pw_shell,'/')+1);
X	/* Set up tty modes */
X		args.sg_flags &= FLAGMASK;
X		args.sg_flags |= USERFLAGS;
X		ioctl(0, TIOCSETP, &args);
X		tchars.t_intrc = DEFINT;
X		tchars.t_quitc = DEFQUIT;
X		ioctl(0, TIOCSETC, &tchars);
X	/* Do the exec */
X		execve(pwd->pw_shell, argp, arge);
X		write(1,"exec failure\n",13);
X	}
X}
X
Xwtmp(tty, name)
X{
X/* Make an entry in wtmp file. */
X
X  int i, fd;
X  long t, time();
X  char ttybuff[WTMPSIZE], namebuff[WTMPSIZE];
X
X  fd = open(wtmpfile, 2);
X  if (fd < 0) return;		/* if wtmp does not exist, no accounting */
X  lseek(fd, 0L, 2);		/* append to file */
X
X  for (i = 0; i < WTMPSIZE; i++) {
X	ttybuff[i] = 0;
X	namebuff[i] = 0;
X  }
X  strncpy(ttybuff, tty, 8);
X  strncpy(namebuff, name, 8);
X  time(&t);
X  write(fd, ttybuff, WTMPSIZE);
X  write(fd, namebuff, WTMPSIZE);
X  write(fd, &t, sizeof(t));
X  close(fd);
X}
*-*-END-of-login.c-*-*
echo x - stty.c
sed 's/^X//' >stty.c <<'*-*-END-of-stty.c-*-*'
X/* stty - set terminal mode  	Author: Andy Tanenbaum
X * Modifications:
X * 21/9/88  -	Added support for new tty driver
X */
X
X#include <sgtty.h>
X
Xchar *on[] = {"-tabs",  "cbreak",  "raw",  "-nl",  "echo"
X		,"prterase", "crtbs", "crterase", "crtkill"
X		,"ctlecho", "decctq", "lcase"};
Xchar *off[]= {"tabs", "", "", "nl", "-echo", "", "", ""
X		,"-crtkill", "-ctlecho", "-decctq", ""};
Xchar *speed[]= {"45.5", "50", "75", "110", "134.5", "150", "200"
X		,"300", "600", "1200", "1800", "2000", "2400"
X		,"4800", "9600", "19.2K", "38.4K", "57.6K", "115.2K"};
Xchar *speed2[]= {"19200", "38400", "57600", "115200"};
X
X#define SPEED2 15
X#define NO_SPEEDS NO_BAUDS
X
X#define match(s1,s2)  (!strcmp(s1,s2))
X
Xstruct sgttyb args;
Xstruct tchars tch;
Xunsigned term_mod;
X
X/* Chars for reset */
X#define KILL	 '@'		/* @ */
X#define ERASE	'\b'		/* CTRL-H */
X#define STARTC	 021		/* CTRL-Q */
X#define STOPC	 023		/* CTRL-S */
X#define QUITC	 034		/* CTRL-\ */
X#define EOFC	 004		/* CTRL-D */
X#define DELC	0177		/* DEL */
X
X#define FD	   0		/* what file descriptor to use */
X
Xint k;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X  /* stty with no arguments just reports on current status. */
X  ioctl(FD, TIOCGETP, &args);
X  ioctl(FD, TIOCGETC, &tch);
X  ioctl(FD, TIOCGETM, &term_mod);
X  if (argc == 1) {
X	report();
X	exit(0);
X  }
X
X  /* Process the options specified. */
X  k = 1;
X  while (k < argc) {
X	option(argv[k], k+1 < argc ? argv[k+1] : "");
X	k++;
X  }
X  ioctl(FD, TIOCSETP, &args);
X  ioctl(FD, TIOCSETC, &tch);
X  ioctl(FD, TIOCSETM, &term_mod);
X  exit(0);
X}
X
X
X
Xreport()
X{
X  int mode;
X
X
X  mode = args.sg_flags;
X  pr(mode&XTABS, 0);
X  pr(mode&CBREAK, 1);
X  pr(mode&RAW, 2);
X  pr(mode&CRMOD,3);
X  pr(mode&ECHO,4);
X  pr(mode&PRTERA,5);
X  pr(mode&CRTBS,6);
X  pr(mode&CRTERA,7);
X  pr(mode&CRTKIL,8);
X  pr(mode&CTLECH,9);
X  pr(mode&DECCTQ,10);
X  pr(mode&LCASE,11);
X  prints("\n");
X  if (term_mod&D_SERIAL)
X  	prints("serial: ");
X  else if (term_mod&D_CONSOLE)
X  	prints("console: ");
X  else	prints("tty type unknown: ");
X  prints(" input @ %s",args.sg_ispeed ? speed[args.sg_ispeed - 1]:"????");
X  if (term_mod&D_SERIAL) {
X  	if (term_mod&RX_XONXOFF)
X  		prints(" %c xonxoff ", '5' + (term_mod&SER_DATABITS));
X  	else
X		prints(" %c hardware", '5' + (term_mod&SER_DATABITS));
X  }
X  prints("\toutput @ %s",args.sg_ispeed ? speed[args.sg_ospeed - 1]:"????");
X  if (term_mod&D_SERIAL) {
X  	if (term_mod&TX_XONXOFF)
X  		prints(" %c xonxoff", '5' + (term_mod&SER_DATABITS));
X  	else
X		prints(" %c hardware", '5' + (term_mod&SER_DATABITS));
X  }
X  prints("\n\nkill = ");prctl(args.sg_kill);
X  prints("\nerase = ");	prctl(args.sg_erase);
X  prints("\nint = "); 	prctl(tch.t_intrc);
X  prints("\nquit = "); 	prctl(tch.t_quitc);
X  prints("\nstop = "); 	prctl(tch.t_stopc);
X  prints("\nstart = "); prctl(tch.t_startc);
X  prints("\neof = "); 	prctl(tch.t_eofc);
X  prints("\n");
X}
X
Xpr(f, n)
Xint f,n;
X{
X  if (f)
X	prints("%s ",on[n]);
X  else
X	prints("%s ",off[n]);
X}
X
Xoption(opt, next)
Xchar *opt, *next;
X{
X	register spe;
X	static char inflag= 0, outflag= 0;
X  if (match(opt, "-tabs"))	{args.sg_flags |= XTABS; return;}
X  if (match(opt, "-raw"))	{args.sg_flags &= ~RAW; return;}
X  if (match(opt, "-cbreak"))	{args.sg_flags &= ~CBREAK; return;}
X  if (match(opt, "-echo"))	{args.sg_flags &= ~ECHO; return;}
X  if (match(opt, "-nl"))	{args.sg_flags |= CRMOD; return;}
X  if (match(opt, "-prterase"))	{args.sg_flags &= ~PRTERA; return;}
X  if (match(opt, "-crtbs"))	{args.sg_flags &= ~CRTBS; return;}
X  if (match(opt, "-crterase"))	{args.sg_flags &= ~CRTERA; return;}
X  if (match(opt, "-crtkill"))	{args.sg_flags &= ~CRTKIL; return;}
X  if (match(opt, "-ctlecho"))	{args.sg_flags &= ~CTLECH; return;}
X  if (match(opt, "-decctq"))	{args.sg_flags &= ~DECCTQ; return;}
X  if (match(opt, "-lcase"))	{args.sg_flags &= ~LCASE; return;}
X  if (match(opt, "tabs"))	{args.sg_flags &= ~XTABS; return;}
X  if (match(opt, "raw"))	{args.sg_flags |= RAW; return;}
X  if (match(opt, "cbreak"))	{args.sg_flags |= CBREAK; return;}
X  if (match(opt, "echo"))	{args.sg_flags |= ECHO; return;}
X  if (match(opt, "nl"))		{args.sg_flags &= ~CRMOD; return;}
X  if (match(opt, "prterase"))	{args.sg_flags &= ~(CRTBS|CRTERA);
X  				 args.sg_flags |= PRTERA; return;}
X  if (match(opt, "crtbs"))	{args.sg_flags &= ~(PRTERA|CRTERA);
X  				 args.sg_flags |= CRTBS; return;}
X  if (match(opt, "crterase"))	{args.sg_flags &= ~(PRTERA|CRTBS);
X  				 args.sg_flags |= CRTERA; return;}
X  if (match(opt, "crtkill"))	{args.sg_flags |= CRTKIL; return;}
X  if (match(opt, "ctlecho"))	{args.sg_flags |= CTLECH; return;}
X  if (match(opt, "decctq"))	{args.sg_flags |= DECCTQ; return;}
X  if (match(opt, "lcase"))	{args.sg_flags |= LCASE; return;}
X  if (match(opt, "kill"))	{args.sg_kill = *next; k++; return;}
X  if (match(opt, "erase"))	{args.sg_erase = *next; k++; return;}
X  if (match(opt, "int"))	{tch.t_intrc = *next; k++; return;}
X  if (match(opt, "quit"))	{tch.t_quitc = *next; k++; return;}
X  if (match(opt, "start"))	{tch.t_startc = *next; k++; return;}
X  if (match(opt, "stop"))	{tch.t_stopc = *next; k++; return;}
X  if (match(opt, "eof"))	{tch.t_eofc = *next; k++; return;}
X
X  if (match(opt, "default") || match(opt,"reset"))	{
X	args.sg_flags = ECHO|CRMOD|XTABS|CRTERA|CTLECH|DECCTQ|CRTKIL;
X	args.sg_kill = KILL;
X	args.sg_erase = ERASE;
X  	tch.t_intrc = DELC;
X  	tch.t_quitc = QUITC;
X  	tch.t_startc = STARTC;
X  	tch.t_stopc = STOPC;
X  	tch.t_eofc = EOFC;
X  	return;
X  }
X
X  if (match(opt,"input")) {inflag++ ; outflag = 0; return;}
X  if (match(opt,"output")) {outflag++; inflag = 0; return;}
X  if (term_mod&D_SERIAL) {
X  	if (atoi(opt) >= 5 && atoi(opt) <= 8) {
X  		term_mod &= ~SER_DATABITS;
X  		term_mod |= atoi(opt) - 5;	return;
X	}
X	if (match(opt,"xonxoff") || match(opt,"-hardware")) {
X		if (!outflag) term_mod |= RX_XONXOFF;
X		if (!inflag)  term_mod |= TX_XONXOFF;
X		return;
X	}
X	if (match(opt,"-xonxoff") || match(opt,"hardware")) {
X		if (!outflag) term_mod &= ~RX_XONXOFF;
X		if (!inflag)  term_mod &= ~TX_XONXOFF;
X		return;
X	}
X  }
X
X  for(spe=0;spe < NO_SPEEDS;spe++)
X  	if (match(opt,speed[spe])) break;
X  if (spe >= NO_SPEEDS)
X  	for (spe=SPEED2;spe < NO_SPEEDS;spe++)
X  		if (match(opt,speed2[spe-SPEED2])) break;
X  if (spe < NO_SPEEDS) {
X  	if (!outflag) args.sg_ispeed= spe+1;
X  	if (!inflag)  args.sg_ospeed= spe+1;
X  	return;
X  }
X
X  std_err("unknown mode: ");
X  std_err(opt);
X  std_err("\n");
X
X}
X
Xprctl(c)
Xchar c;
X{
X  if (c < ' ')
X	prints("^%c", 'A' - 1 + c);
X  else if (c == 0177)
X	prints("DEL");
X  else
X	prints("%c", c);
X}
*-*-END-of-stty.c-*-*
echo x - term.c
sed 's/^X//' >term.c <<'*-*-END-of-term.c-*-*'
X/* term - terminal simulator		Author: Andy Tanenbaum
X * Modififications:
X * 21/9/88  -	Added support for new tty driver
X */
X
X/* This program allows the user to turn a MINIX system into a dumb
X * terminal to communicate with a remote computer over a modem.  It
X * forks into two processes.  The parent sits in a tight loop copying
X * from the keyboard to the modem.  The child sits in a tight loop
X * copying from the modem to the screen.
X *
X * Example usage:
X *	term			: 1200 baud, 8 bits/char, no parity
X *	term 9600 7 even	: 9600 baud, 7 bits/char, even parity
X *	term odd 300 7		:  300 baud, 7 bits/char, odd parity
X */
X
X#include <signal.h>
X#include <sgtty.h>
X
X#define NCHECKS 10
X#define BAD -1
X#define GOOD 1
X#define MODEM "/dev/tty1"	/* special file attached to the modem */
X#define ESC 033			/* character to hit to leave simulator */
X#define LIMIT 3			/* how often do you have to hit  ESC to exit*/
X#define CHUNK 1024		/* how much to read at once */
X
Xint modem, pid;			/* file descriptor for modem */
X
Xchar *speed1[]= {"45.5", "50", "75", "110", "134.5", "150", "200"
X		,"300", "600", "1200", "1800", "2000", "2400"
X		,"4800", "9600", "19.2K", "38.4K", "57.6K", "115.2K"};
Xchar *speed2[]= {"19200", "38400", "57600", "115200"};
X
X#define SPEED2 15
X#define NO_SPEEDS NO_BAUDS
X#define match(s1,s2)	(!strcmp(s1,s2))
X
Xstruct sgttyb sgtty, sgsave1, sgsave2;
Xunsigned modsave1;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X  sync();
X  modem = open(MODEM, 2);
X  if (modem < 0) {
X	printf("Can't open modem on %s\n", MODEM);
X	exit(1);
X  }
X  set_uart(argc, argv);
X
X  /* Main body of the terminal simulator. */
X  if ( (pid = fork()))
X	copy(0, modem, ESC);	/* copy from stdin to modem */
X  else
X	copy(modem, 1, -1);	/* copy from modem to stdout */
X}
X
Xset_uart(argc, argv)
Xint argc;
Xchar *argv[];
X{
X/* Set up the UART parameters. */
X
X  int i, k, modstat
X	, speed, parity, bits, handsh;
X
X  ioctl(modem, TIOCGETM, &modstat);
X  modsave1 = modstat;
X  if (!(modstat&D_SERIAL))
X  	error("term will only run on serial lines\n");
X
X  ioctl(modem, TIOCGETP, &sgtty);
X  sgsave1 = sgtty;		/* modem parameters saved */
X  	/* Get defaults */
X  parity = sgtty.sg_flags & (ODDP|EVENP|ANYP|NONEP);
X  bits = modstat&SER_DATABITS;
X  handsh = modstat&(RX_XONXOFF|TX_XONXOFF);
X  speed = sgtty.sg_ispeed;
X
X  /* Examine all the parameters and check for validity. */
X  for (i = 1; i < argc; i++) {
X	if (match(argv[i], "even")) {parity = EVENP; continue;}
X	if (match(argv[i], "odd"))  {parity = ODDP; continue;}
X	if (match(argv[i], "any"))  {parity = ANYP; continue;}
X	if (match(argv[i], "none")) {parity = NONEP; continue;}
X
X	if (match(argv[i], "xonxoff")) {handsh = TX_XONXOFF|RX_XONXOFF;
X					continue;}
X	if (match(argv[i], "hardware")) {handsh = 0; continue;}
X
X	k = atoi(argv[i]);
X	if (k >= 5 && k <= 8) {
X		bits = k - 5;
X		continue;
X	}
X
X	speed = validity(argv[i]);
X	if (speed == BAD) {
X		printf("Invalid parameter: %s\n", argv[i]);
X		error("Usage: term [baudrate] [data_bits] [parity] [handshaking]\n");
X	}
X  }
X
X  /* Set the modem parameters. */
X  modstat &= ~(SER_DATABITS|TX_XONXOFF|RX_XONXOFF);
X  modstat |= bits | handsh;
X  ioctl(modem, TIOCSETM, &modstat);
X  sgtty.sg_ispeed = sgtty.sg_ospeed = speed;
X  sgtty.sg_flags = RAW | parity;
X  ioctl(modem, TIOCSETP, &sgtty);
X  
X  /* Fetch the keyboard parameters, save them, and set new ones. */
X  ioctl(0, TIOCGETP, &sgtty);
X  sgsave2 = sgtty;		/* modem parameters */
X  sgtty.sg_flags = (sgtty.sg_flags&(ANYP|EVENP|ODDP|NONEP)) | RAW;
X  ioctl(0, TIOCSETP, &sgtty);
X}
X
X
Xint validity(s)
Xchar *s;
X{
X/* Check speed parameter for legality. */
X
X  int i;
X
X  for (i = 0; i < NO_BAUDS; i++) {
X	if (match(s, speed1[i])) return(i+1);
X  }
X  for (i = 0; i < NO_BAUDS - SPEED2 ; i++) {
X  	if (match(s, speed2[i])) return(i+SPEED2+1);
X  }
X  return(BAD);
X}
X 
X
Xcopy(in, out, end)
Xint in, out, end;
X{
X/* Copy from the keyboard to the modem or vice versa. If the end character
X * is seen LIMIT times in a row, quit.  For the traffic from the modem, the
X * end character is -1, which cannot occur since the characters from the
X * modem are unsigned integers in the range 0 to 255.
X */
X
X  int t, count, state = 0;
X  char buf[CHUNK], *p;
X
X  while (1) {
X	if ( (count = read(in, buf, CHUNK)) < 0) {
X		printf("Can't read from modem\r\n");
X		quit();
X	}
X
X	if (end > 0) {
X		for (p = &buf[0]; p < &buf[count]; p++) {
X			t = *p & 0377;		/* t is unsigned int 0 - 255 */
X			if (t == end) {
X				if (++state == LIMIT) quit();
X			} else {
X				state = 0;
X			}
X		}
X	}
X	write(out, buf, count);
X  }
X}
X
Xerror(s)
Xchar *s;
X{
X  printf("%s", s);
X  exit(1);
X}
X
Xquit()
X{
X  ioctl(modem, TIOCSETP, &sgsave1);
X  ioctl(modem, TIOCSETM, &modsave1);
X  ioctl(0, TIOCSETP, &sgsave2);
X  if (getpid() != pid) kill(pid, SIGINT);
X  exit(0);
X}
X
*-*-END-of-term.c-*-*
echo x - xonxoff.c
sed 's/^X//' >xonxoff.c <<'*-*-END-of-xonxoff.c-*-*'
X#include <sgtty.h>
X
Xmain(argc,argv)
Xchar *argv[];
X{
Xint i;
X
X	if (argc > 2 || (argc == 2 && *argv[1] != 't' && *argv[1] != 'r')) {
X		printf("Usage: %s [t|r]\n",*argv);
X		exit(1);
X	}
X	ioctl(0,TIOCGETM, &i);
X	if (!(i&D_SERIAL)) {
X		printf("This is not a serial line: device = 0x%x mode = 0x%x\n"
X			,i>>8, i&0xFF);
X		exit(1);
X	}
X
X	if (argc == 2) {
X		if (*argv[1] == 't')	i |= TX_XONXOFF;
X		else			i |= RX_XONXOFF;
X	} else				i ^= (TX_XONXOFF|RX_XONXOFF);
X
X	ioctl(0,TIOCSETM, &i);
X	ioctl(0,TIOCGETM, &i);
X	if (i&TX_XONXOFF)
X		printf("TX now in XONXOFF handshaking\n");
X	else
X		printf("TX now in HARDWARE handshaking\n");
X	if (i&RX_XONXOFF)
X		printf("RX now in XONXOFF handshaking\n");
X	else
X		printf("RX now in HARDWARE handshaking\n");
X}
*-*-END-of-xonxoff.c-*-*
echo x - tty1.c
sed 's/^X//' >tty1.c <<'*-*-END-of-tty1.c-*-*'
X/* tty1.c - device independant code for tty driver
X *
X * Written by:  A.Hannam	(Feb 1988)
X *
X * Modifications:
X * 21/8/88  -	Modified for MINIX V1.3 on IBM-PC
X */
X
X/* This file contains the high level terminal driver and is device independant.
X * It accepts characters to be printed from programs, process's them and then
X * passes them on to the raw (device dependant) output routines. It also
X * accepts input from raw (device dependant) routines, process's them acording
X * to the modes set by ioctl, and queues it for programs.
X * This file contains 3 main entry points: tty_task(), sigchar() and putc().
X * tty_task - takes messages to do work from readers, writers and interrupt
X *	service routines.
X * sigchar - used to send signals from the keyboard. (Special for F10)
X * putc - used in the printf routine for the kernel.
X *
X * The valid messages and their parameters are:
X *
X *   TTY_CHAR_INT: interrupt routines have produced char(s)
X *   TTY_O_DONE:   interrupt routines need more charactors to output
X *   TTY_READ:     a process wants to read from a terminal
X *   TTY_WRITE:    a process wants to write on a terminal
X *   TTY_IOCTL:    a process wants to change a terminal's parameters
X *   TTY_SETPGRP:  a process wants to change a terminal's process group
X *   CANCEL:       terminate a previous incomplete system call immediately
X *
X *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
X * ---------------------------------------------------------------------------
X * | TTY_CHAR_INT|minor dev|         |         |         |         |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_O_DONE  |minor dev|         |         |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_READ    |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_SETGPRP |minor dev| proc nr |   pgrp  |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | CANCEL      |minor dev| proc nr |         |         |         |         |
X * ---------------------------------------------------------------------------
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/sgtty.h"
X#include "../h/signal.h"
X#include "../h/callnr.h"
X#include "type.h"
X#include "const.h"
X#include "proc.h"
X
X#define HIGH_LEVEL
X#include "tty.h"
X
XPUBLIC tty_entry tty_struct[NR_TTYS];		/* The tty tables */
XPUBLIC void tty_task(), putc();			/* Public routines */
XPUBLIC void do_nothing(), sigchar(), rs_flush();
X
Xextern int lock();
Xextern void restore();
Xextern char get_byte();
X
X
X#define TAB_SIZE	8	/* distance between tabs (must be pwr of 2) */
X
X#define ERASE_CHAR	'\b'	/* default erase character */
X#define KILL_CHAR	'@'	/* default kill character */
X#define INTR_CHAR	0177	/* default interrupt character */
X#define QUIT_CHAR	034	/* default quit characterc (CTRL-\) */
X#define XOFF_CHAR	023	/* default x-off character (CTRL-S) */
X#define XON_CHAR	021	/* default x-on character  (CTRL-Q) */
X#define EOT_CHAR	004	/* default EOF character   (CTRL-D) */
X#define BRK_CHAR	'\n'	/* default delimiter (\n) (not used) */
X#define WORD_MASK     0xFFFF	/* mask for 16 bits */
X#define OFF_MASK      0x000F	/* mask for  4 bits */
X
X		/* Our private routines */
XPRIVATE void tty_bad(), tty_init(), do_charint(), proc_ints()
X		,echo(), do_read(), do_ioctl(), do_cancel(), do_write()
X		,tty_reply(), out_chars(), do_setpgrp();
XPRIVATE bool do_cooked(), in_char();
XPRIVATE unsigned chuck();
XPRIVATE int rd_chars();
X
XPRIVATE charfbuf tty_copy_buf;		/* copy buf used to avoid races */
XPRIVATE message c_mess;			/* used by the clock in flushing */
X
X/*===========================================================================*
X *				tty_task				     *
X *===========================================================================*/
XPUBLIC void tty_task()
X{
X/* Main routine of the terminal task. */
X
X  message tty_mess;		/* buffer for all incoming messages */
X  register tty_entry *tp;
X
X  tty_init();			/* initialize */
X  while (TRUE) {
X	receive(ANY, &tty_mess);
X	if (tty_mess.TTY_LINE < 0 || tty_mess.TTY_LINE > NR_TTYS-1) {
X		tty_bad(&tty_mess);
X		continue;
X		}
X	tp = &tty_struct[tty_mess.TTY_LINE];
X	switch(tty_mess.m_type) {
X
X			/* Hardware Interrupts */
X	    case TTY_CHAR_INT:
X	    case TTY_O_DONE:	proc_ints();			break;
X
X			/* Software Interrupts */
X	    case TTY_READ:	do_read(tp, &tty_mess);		break;
X	    case TTY_WRITE:	do_write(tp, &tty_mess);	break;
X	    case TTY_IOCTL:	do_ioctl(tp, &tty_mess);	break;
X	    case TTY_SETPGRP:	do_setpgrp(tp, &tty_mess);	break;
X	    case CANCEL   :	do_cancel(tp, &tty_mess);	break;
X	    default:		tty_bad(&tty_mess);
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				tty_init				     *
X *===========================================================================*/
XPRIVATE void tty_init()
X{
X/* Initialize all the terminals and tty_tables */
X
X  register tty_entry *tp;
X  register i;
X
X  /* Prepare the clock tasks message (so it is a legal message) */
X  c_mess.TTY_LINE = 0;			/* Has to point to a valid tty (any) */
X  c_mess.m_type = TTY_CHAR_INT;		/* Could also have been TTY_O_DONE */
X
X  /* Initialize the TTY structure */
X  for (tp = &tty_struct[0],i=0; i < NR_TTYS; tp++,i++) {
X	bufinit(tp->tty_inbuf);
X	tp->tty_lfct = 0;
X	tp->tty_writers = 0;
X	tp->tty_state = 0;
X	tp->tty_ddmod = 0;
X	tp->tty_mode = CRMOD|XTABS|ECHO|CRTERA|CTLECH|CRTKIL|DECCTQ;
X	tp->tty_erase = ERASE_CHAR;
X	tp->tty_kill  = KILL_CHAR;
X	tp->tty_intr  = INTR_CHAR;
X	tp->tty_quit  = QUIT_CHAR;
X	tp->tty_xon   = XON_CHAR;
X	tp->tty_xoff  = XOFF_CHAR;
X	tp->tty_eof   = EOT_CHAR;
X	tp->tty_brk   = BRK_CHAR;
X	(*dev_init[i])(tp);
X  }
X}
X
X/*===========================================================================*
X *				tty_bad					     *
X *===========================================================================*/
XPRIVATE void tty_bad(p)
Xmessage *p;
X{
X	/* dump out bad tty messages */
X#ifdef DEBUG
X	register char *q= (char *)p;
X	register x;
X
X	printf("\nIllegal TTY message:\n");
X#ifdef DEBUG2
X	for(x=1; x <= sizeof(*p); x++) {
X		printf("0x%x ", (*q++) & 0xFF);
X		if( x%8 == 0) printf("\n");
X		}
X	printf("\n");
X	printf("m_type= %d, source= %d, TTY_LINE= %d, PROC_NR= %d\n"
X		,p->m_type,p->m_source,p->TTY_LINE,p->PROC_NR);
X	printf("COUNT= %d, ADDRESS= 0x%x\n",p->COUNT,p->ADDRESS);
X	printf("\tor ...\n");
X#endif DEBUG2
X	printf("m_type= %d, dest= %d, PROC_NR= %d, STATUS= %d\n"
X		,p->m_type,p->m_source,p->REP_PROC_NR,p->REP_STATUS);
X	printf("flags= %D, spek= %D\n",p->TTY_FLAGS,p->TTY_SPEK);
X#else
X	printf("m_type = %d\n",p->m_type);
X	panic("TTY",p->TTY_LINE);
X#endif DEBUG
X}
X
X/*===========================================================================*
X *				rs_flush				     *
X *===========================================================================*/
XPUBLIC void rs_flush()
X{
X/* The clock task has recieved notification that input or output flushing is
X * needed. This is a general routine unlike the one in the original (V1.3)
X * tty which was specific to the rs232 lines. This should probably be
X * renamed to something more meaningful but will suffice at present.
X * Simply send an interrupt message for the tty.
X */
X	interrupt(TTY, &c_mess);
X	flush_flag = 0;
X}
X
X/*===========================================================================*
X *				proc_ints				     *
X *===========================================================================*/
XPRIVATE void proc_ints()
X{
X/* This routine process's hardware interrupts. It is needed as MINIX can only
X * handle one interrupt per task at a time. This means interrupts can be lost.
X * This solution simply says that an interrupt has occured (it doesn't matter
X * whose) and the state of the work needed is stored else where (in the
X * tty_struct). It is a bad problem with a horrible solution. Still it works.
X */
Xregister tty_entry *tp;
Xregister flags;
X
X  /* Some one needs some flushing - find out who and do it. */
X  for(tp= &tty_struct[0]; tp < &tty_struct[NR_TTYS]; tp++) {
X	flags = lock();
X	if (tp->tty_state & IN_FLUSH) {
X		tp->tty_state &= ~IN_FLUSH;
X		restore(flags);
X		do_charint(tp);		/* This tty has some input */
X		flags = lock();
X		}
X	if (tp->tty_state & OUT_FLUSH) {
X		tp->tty_state &= ~OUT_FLUSH;
X		restore(flags);
X		out_chars(tp);		/* This tty needs some output */
X		continue;
X		}
X	restore(flags);
X	}
X}
X
X/*===========================================================================*
X *				do_charint				     *
X *===========================================================================*/
XPRIVATE void do_charint(tp)
Xregister tty_entry *tp;
X{
X/* A character has been typed.  If a character is typed and the tty task is
X * not able to service it immediately, the character is accumulated within
X * the low level tty driver. A call to this routine may thus have to process
X * several characters.
X */
X
X  register unsigned char *count;
X  register char *copy_ptr;
X  int r_val;
X
X  
X/* We have to copy the chars in the device fbuf so we can process them */
X  r_val= lock();			/* prevent races by disabling int's */
X  count = &(tp->tty_fbuf->count);	/* how many chars to transfer */
X  if (*count == 0) {			/* check the count is valid */
X	restore(r_val);
X	return;
X	}
X		/* copy using bcopy(from,to,count) */
X  bcopy(tp->tty_fbuf,&tty_copy_buf, *count);
X  tty_copy_buf.count= *count;		/* copy the no of chars */
X  *count= 0;				/* clear the device fbuf */
X  restore(r_val);			/* re-enable interrupts */
X
X  /* notify the low level routine for flow control reasons */
X  (*tp->tty_devempty)(tp);
X
X  /* Loop on the accumulated characters, processing each in turn. */
X  copy_ptr = tty_copy_buf.b;
X	 /* process the char, queue and echo it */
X  while (tty_copy_buf.count--)
X	if (in_char(tp, *copy_ptr++) && tp->tty_inleft) {
X		/* TTY buffer is full, try transfering to user. */
X		r_val= rd_chars(tp,1);	/* force the reader to accept chars */
X		if (r_val != SUSPEND)	/* reader could be satisfied */
X			tty_reply(REVIVE, (int) tp->tty_incaller
X				, (int) tp->tty_inproc, r_val);
X		tty_copy_buf.count++;	/* try the char again */
X		copy_ptr--;
X	}
X
X	/* See if user can be satisfied. */
X  if (tp->tty_inleft) {
X	r_val= rd_chars(tp,0);		/* don't force reader to take chars */
X	if (r_val != SUSPEND)		/* reader could be satisfied */
X		tty_reply(REVIVE, (int) tp->tty_incaller
X			, (int) tp->tty_inproc, r_val);
X  }
X}
X
X
X/*===========================================================================*
X *				in_char					     *
X *===========================================================================*/
XPRIVATE bool in_char(tp, ch)
Xregister tty_entry *tp;		/* tty on which the char arrived */
Xint ch;				/* code for character that arrived */
X{
X/* A character has just been typed in.  Process, save, and echo it.
X	Returns TRUE if buffers full else FALSE */
X
X  register mode;
X  char c;
X  unsigned col;
X  charpos chp;
X
X  ch &= 0xFF;				/* make sure only 8 bits */
X  mode = tp->tty_mode;		/* speed up access to mode bits */
X
X  do {
X    /* The translate routine returns unsigned. The lower byte is the
X	ascii char, the upper byte (except for the MARKER (top) bit)
X	may be used for the translate routines use.
X	If the top byte == 0 then this is a single char,
X		else it is the start of a sequence.
X	The next call of a sequence is passed the previous result
X	as a parameter. The first call to translate always has the
X	top byte set to 0.
X	If the MARKER is set then this char is to be ignored and
X	if in a sequence then the sequence ends.
X    */
X    if (tp->tty_state & TRANSLATE)	/* Translate the char to ascii */
X	if( (ch = (*tp->tty_devtrans)(ch))&MARKER) break;
X
X    c= ch & 0xFF;			/* We now have an 8-bit ascii char */
X
X	/* From now on the MARKER bit is used to indicate EOF */
X
X
X    /* Processing for COOKED and CBREAK mode contains special checks. */
X    if (!(mode&RAW)) {
X
X	/* 7-bit chars except in raw mode or if an 8 bit terminal */
X	if (!(tp->tty_state&COK8BIT)) c &= 0177;
X
X		/* LCASE processing must come first */
X	if ((mode&LCASE) && c >= 'A' && c <= 'Z') c += 'a'-'A';
X
X	/* Handle erase, kill and escape processing etc. (cooked mode only) */
X	if (!(mode&CBREAK)) {
X
X	/* See if the last char was escaped */
X	    if (tp->tty_state&ESCAPED) {
X
X		/* Previous character was backslash. */
X		tp->tty_state &= ~ESCAPED;	/* turn escaping off */
X
X		/* If necessary store the escape previously skipped over */
X		if (c != tp->tty_erase && c != tp->tty_kill && c != '\\' &&
X		    c != tp->tty_eof && bufnfull(tp->tty_inbuf)) {
X			chp.ch= '\\'; chp.col= tp->tty_column-1;
X			putobj(tp->tty_inbuf, chp);
X			}
X
X	/* Last char wasn't escaped - do erase, kill etc processing ...
X	 * Care must be taken as whether to use echo() or do_cooked()
X	 * as they have different results in the CTLECH case. Where it
X	 * doesn't matter use echo() as it can be considered safer.
X	 */
X	    } else {
X
X		/* ERASE processing (rub out of last character). */
X		if (c == tp->tty_erase) {
X			/* del last char, doing echo if possible */
X			if ((col=chuck(tp)) != 0xFFFF && mode&ECHO) {
X			    if (mode&(CRTBS|CRTERA)) {
X				col= col >>8; /* get column */
X				do {
X				    do_cooked(tp,'\b',ECHO_OUT);
X				    if (mode&CRTERA) {
X					echo(tp, ' ');
X					do_cooked(tp, '\b', ECHO_OUT);
X				    }
X				} while(tp->tty_column > col);
X			    } else if (tp->tty_mode&PRTERA) {
X				echo(tp,'\\');
X				echo(tp,(char)ch);
X				echo(tp,'/');
X			    } else echo(tp,tp->tty_erase);
X			}
X			continue;	/* Don't store a char */
X		} else			/* End of ERASE processing */
X
X		/* KILL processing (remove current line). */
X		if (c == tp->tty_kill) {
X			/* Only do fancy kill if echo on */
X			if (tp->tty_mode&CRTKIL && mode&ECHO) {
X				while((col= chuck(tp)) != 0xFFFF) {
X					col= col >>8;
X					do {
X						do_cooked(tp,'\b',ECHO_OUT);
X						echo(tp,' ');
X						do_cooked(tp,'\b',ECHO_OUT);
X					} while(tp->tty_column > col);
X				}
X			} else {	/* Simple kill */
X				while(chuck(tp) != 0xFFFF);
X				echo(tp, tp->tty_kill);
X				echo (tp, '\n');
X			}
X			continue;	/* Don't store a char */
X		} else			/* End of KILL processing */
X
X		/* ESCAPE processing (backslash). */
X		if (c == '\\') {
X			tp->tty_state |= ESCAPED;
X			echo(tp, c);
X			continue;	/* Don't store the '\' */
X		} else			/* End of ESCAPE processing */
X
X		/* EOF processing.
X		 * It is stored in the text as MARKER, and counts as a
X		 * line feed in terms of knowing whether a full line
X		 * has been typed already.
X		 */
X		if (c == tp->tty_eof)
X			ch |= MARKER;	/* End of EOF processing */
X
X	    }		/* End of Escape processing */
X	}		/* End of Cooked processing */
X
X	/* Both COOKED and CBREAK modes come here; first map CR to LF. */
X	if (c == '\r' && (mode&CRMOD)) c = '\n';
X
X	/* Check for interrupt character. */
X	if (c == tp->tty_intr) {
X		sigchar(tp, SIGINT);
X		continue;		/* Don't store a char */
X	}
X
X	/* Check for quit character. */
X	if (c == tp->tty_quit) {
X		sigchar(tp, SIGQUIT);
X		continue;		/* Don't store a char */
X	}
X
X	/* Check for and process CTRL-Q (terminal start). */
X	if (c == tp->tty_xon
X	    || (tp->tty_state&INHIBITED && !(mode&DECCTQ))) {
X		tp->tty_state &= ~INHIBITED;
X		out_chars(tp);		/* resume output */
X		continue;		/* Don't store a char */
X	}
X
X	/* Check for and process CTRL-S (terminal stop). */
X	if (c == tp->tty_xoff) {
X		tp->tty_state |= INHIBITED;
X		continue;		/* Don't store a char */
X	}
X    }			/* End of Cooked, Cbreak processing */
X
X  /* All 3 modes come here. */
X    if (bufnfull(tp->tty_inbuf)) {	/* discard char if buffer full */
X	if (c == '\n' || (ch&MARKER))	/* count line feeds */
X		tp->tty_lfct++;
X		/* save the character in the input queue */
X	if (ch&MARKER) {
X  		chp.ch= chp.col= 0xFF;
X	  	putobj(tp->tty_inbuf,chp);
X	} else {
X		chp.ch= c; chp.col= tp->tty_column;
X		putobj(tp->tty_inbuf,chp);
X		echo(tp, c);
X	}
X    }
X	
X  /* Continue with macro type keys (translate on) */
X  } while( (ch &= ~MARKER) & 0xFF00 );
X  return buffull(tp->tty_inbuf);
X}
X
X/*===========================================================================*
X *				sigchar					     *
X *===========================================================================*/
XPUBLIC void sigchar(tp, sig)
Xregister tty_entry *tp;		/* pointer to tty_struct */
Xint sig;				/* SIGNAL to send */
X{
X/* Process a signal generated by the tty (key or otherwise) */
X
X	tp->tty_state &= ~INHIBITED;		/* do implied CRTL-Q */
X	bufinit(tp->tty_inbuf);			/* discard input */
X	tp->tty_lfct = 0;
X	(*tp->tty_devclr)(tp);			/* discard output */
X
X	/* Send signal if the process group is valid - (or console KILL all) */
X	/* At the moment tty_pgrp stores a slot num, not a proc group num. */
X	if (tp->tty_pgrp || sig == SIGKILL)
X		cause_sig(tp->tty_pgrp, sig);
X}
X
X
X/*===========================================================================*
X *				echo					     *
X *===========================================================================*/
XPRIVATE void echo(tp, c)
Xregister tty_entry *tp;	/* terminal on which to echo */
Xregister char c;		/* character to echo */
X{
X/* Echo a character on the terminal. */
X
X  if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
X
X  if ((tp->tty_mode&(CTLECH|RAW))==CTLECH) {
X	if (c&128) {
X		echo(tp,'|');
X		c -= 128;
X	}
X	if (c<' ' && c!='\n' && c!='\t' && c!='\r') {
X		echo(tp,'^');
X		c += '@';
X	} else if (c==127) {
X		echo(tp,'^');
X		c= '?';
X	}
X  }
X  do_cooked(tp,(char) c,ECHO_OUT);
X}
X
X
X/*===========================================================================*
X *				chuck					     *
X *===========================================================================*/
XPRIVATE unsigned chuck(tp)
Xregister tty_entry *tp;	/* from which tty should chars be removed */
X{
X/* Delete one character from the input queue.  Used for erase and kill.
X * Return 0xFFFF if there are no more chars to return
X *	else return char in lower byte and its screen column in upper byte.
X */
X
X  int prev;
X  charpos val;
X
X  /* If input queue is empty, don't delete anything. */
X  if (bufempty(tp->tty_inbuf))
X	return 0xFFFF;
X
X  /* Don't delete '\n' or MARKER (eof). */
X  prev = (tp->tty_inbuf.in ? tp->tty_inbuf.in-1 : bufsize(tp->tty_inbuf)-1);
X  val= tp->tty_inbuf.b[prev];
X  if (val.ch == '\n' || (val.ch== 0xFF && val.col== 0xFF))
X	return 0xFFFF;
X
X		/* char erasure was possible */
X  tp->tty_inbuf.in = prev;
X  tp->tty_inbuf.count--;
X  return( (unsigned)val.ch | (((unsigned)val.col)<<8));
X}
X
X
X/*===========================================================================*
X *				do_read					     *
X *===========================================================================*/
XPRIVATE void do_read(tp, m_ptr)
Xregister tty_entry *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to the task */
X{
X/* A process wants to read from a terminal. */
X
Xphys_bytes phys_add;
Xextern phys_bytes umap();
X
X	  /* Perform Validity checks on the read request */
X
X  /* Must have between 1 and MAXINT chars */
X  if (m_ptr->COUNT & 0x8000 || m_ptr->COUNT == 0) {
X  	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_BAD_ADDR);
X  	return;
X  	}
X
X  /* Check the address given to see if it is valid */
X  if ( (phys_add= umap(proc_addr(m_ptr->PROC_NR),D,(vir_bytes) m_ptr->ADDRESS
X  		,(vir_bytes) m_ptr->COUNT)) == 0) {
X  	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_BAD_ADDR);
X	return;
X  }
X
X  /* if someone else is hanging, give up */
X  if (tp->tty_inleft > 0) {
X	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN);
X	return;
X  }
X
X	/* Read is valid - Set up the read */
X
X  /* Copy information from the message to the tty struct. */
X  tp->tty_incaller = m_ptr->m_source;
X  tp->tty_inproc = m_ptr->PROC_NR;
X  tp->tty_inleft = m_ptr->COUNT;
X  tp->tty_inoffset = phys_add & OFF_MASK;
X  tp->tty_inseg = (phys_add >> 4) & WORD_MASK;
X  tp->tty_incum = 0;
X
X  /* Flush any chars in the output routine buffers */
X  (*tp->tty_devflush)(tp);
X
X  /* Try to get chars.  This call either gets enough, or gets nothing. */
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, rd_chars(tp,0));
X}
X
X
X/*===========================================================================*
X *				rd_chars				     *
X *===========================================================================*/
XPRIVATE int rd_chars(tp,force)
Xregister tty_entry *tp;	/* pointer to terminal to read from */
Xint force;		/* the user must accept as many chars as he can */
X{
X/* Try to send some data from the tty buffers to the user.
X *	Returns SUSPEND if more chars have to be read to complete the
X *	read request else returns the total number of chars transfered to the
X *	user.
X */
X
X  register buf_ct;
X  unsigned char enough;
X  bool cooked;
X  charpos chp;
X
X  if (bufempty(tp->tty_inbuf))		/* Only put chars if there are some */
X  	return(SUSPEND);
X
X  cooked = !(tp->tty_mode & (RAW|CBREAK));	/* TRUE iff COOKED mode */
X
X  if (!force && !tp->tty_lfct && cooked)	/* Only transfer chars if */
X  	return(SUSPEND);			/* read finishable or forced */
X
X	/* We can try to complete this read request now */
X
X  enough = 0;
X
X  /* What is the maximum chars we can transfer at the moment */
X  buf_ct = MIN(tp->tty_inleft, bufcount(tp->tty_inbuf));
X
X  while(buf_ct--) {
X  		/* Get a char from the buffer */
X	chp = getobj(tp->tty_inbuf);
X	advgetobj(tp->tty_inbuf);
X		/* Check for EOF or lf char */
X	if (chp.ch == '\n' || (chp.ch==0xFF && chp.col==0xFF)) {
X		tp->tty_lfct--;
X			/* Finish looping if not nl in uncooked mode */
X		if (cooked || chp.ch == 0xFF) {
X			enough = chp.ch;
X			buf_ct= 0;
X			}
X	}
X
X		/* Send it if it isn't an EOF */
X	if (enough != 0xFF) {
X		put_byte(tp->tty_inseg,tp->tty_inoffset++,chp.ch);
X		tp->tty_inleft--;
X		tp->tty_incum++;
X	}
X  }
X
X		/* Does that satisfy the read request ? */
X  if (enough || !cooked || tp->tty_inleft==0) {
X  	tp->tty_inleft= 0;		/* No more chars needed */
X  	return tp->tty_incum;
X  	}
X  return(SUSPEND);
X}
X
X/*===========================================================================*
X *				do_write				     *
X *===========================================================================*/
XPRIVATE void do_write(tp, m_ptr)
Xregister tty_entry *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to the task */
X{
X/* A process wants to write on a terminal. */
X
X  register struct writers *tpw;
X  phys_bytes phys_add;
X  int wr;
X  extern phys_bytes umap();
X
X  /* Check the address given to see if it is valid */
X  if ( (phys_add= umap(proc_addr(m_ptr->PROC_NR),D,(vir_bytes) m_ptr->ADDRESS
X  		,(vir_bytes) m_ptr->COUNT)) == 0) {
X  	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_BAD_ADDR);
X	return;
X  }
X
X  /* Check that we have room for more writers */
X  if ( (wr=tp->tty_writers) >= MAX_WRITERS) {
X  	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_TRY_AGAIN);
X	return;
X  }
X
X  /* Copy message parameters to the tty structure. */
X  tpw= &tp->w[tp->tty_writers++];
X  tpw->otcaller = m_ptr->m_source;
X  tpw->outproc = m_ptr->PROC_NR;
X  tpw->offset = phys_add & OFF_MASK;
X  tpw->seg = (phys_add >> 4) & WORD_MASK;
X  tpw->outleft = m_ptr->COUNT;
X  if (wr == 0) {
X  	tp->tty_state |= WAITING;	/* a new writer always needs a reply */
X  	tp->tty_cum= 0;
X  }
X
X  /* O/S writes are already suspended waiting for reply, so don't
X   *  send message telling them to suspend.
X   */
X  if (tpw->outproc >= LOW_USER)
X	tty_reply(TASK_REPLY,tpw->otcaller,tpw->outproc,SUSPEND);
X  if (wr == 0) out_chars(tp);
X}
X
Xtypedef union {
X	long				l;
X	struct {int i0, i1;}		i;
X	struct {char c0,c1,c2,c3;}	c;
X	} olong;
X
X/*===========================================================================*
X *				do_ioctl				     *
X *===========================================================================*/
XPRIVATE void do_ioctl(tp, m_ptr)
Xregister tty_entry *tp;		/* pointer to tty_struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* Perform IOCTL on this terminal.
X * The V1.3 ioctl was inconsistant in the way it got and put fields,
X * particularly with sg_i/ospeed. The new is consistant.
X * Programs that used the old ioctl will not work as the ioctl calls have
X * different values for TIOCSETP etc. The old calls will return EINVAL.
X * Any programs that set the number of bits in V1.3 will have to be
X * rewritten (not just recompiled) as those fields are being used for other
X * purposes and this function has been shifted to the TIOC(SET/GET)M call.
X */
X
X  olong flags, erki;
X  register r = m_ptr->TTY_REQUEST;
X  int stat = OK;
X
X  if (r&IOC_IN) {
X    flags.l = m_ptr->TTY_FLAGS;
X    erki.l  = m_ptr->TTY_SPEK;
X    switch(r) {
X    	case TIOCSETP:		/* Set erase, kill, and flags. */
X	case TIOCSETN:
X		tp->tty_mode  = flags.i.i0;	/* 16 bit flags at present */
X			/* Take care when setting speed fields */
X		if (erki.c.c3)
X			tp->tty_ospeed = erki.c.c3;
X		if (erki.c.c2)
X			tp->tty_ispeed = erki.c.c2;
X		tp->tty_erase = erki.c.c1;
X		tp->tty_kill  = erki.c.c0;
X			/* Any device dependant stuff */
X		(*tp->tty_devioctl)(tp,m_ptr);
X		break;
X
X	case TIOCSETC:	/* Set intr, quit, xon, xoff, eof (brk not used). */
X		tp->tty_intr = erki.c.c3;
X		tp->tty_quit = erki.c.c2;
X		tp->tty_xon  = erki.c.c1;
X		tp->tty_xoff = erki.c.c0;
X		tp->tty_eof  = flags.c.c1;
X		tp->tty_brk  = flags.c.c0;
X		break;
X
X	case TIOCSETM:	/* Set device dependant flags */
X		tp->tty_ddmod = flags.i.i0;
X			/* Any device dependant stuff */
X		(*tp->tty_devioctl)(tp, m_ptr);
X		break;
X
X	case TIOCSTI:		/* Simulate terminal input */
X		erki.c.c0 = tp->tty_state & TRANSLATE;	/* save trns flag */
X		tp->tty_state &= ~TRANSLATE;		/* turn off inp trns */
X		in_char(tp, flags.c.c0);		/* put char in the Q */
X		tp->tty_state |= erki.c.c0;		/* restore trns flag */
X		break;
X
X	case TIOCMODS:		/* raw device hanles these */
X		(*tp->tty_devioctl)(tp, m_ptr);
X		break;
X
X	default:
X		stat = EINVAL;
X		break;
X    }
X  }
X
X  if (r&IOC_OUT) {
X    flags.l = erki.l = 0;
X    switch(r) {
X	case TIOCGETP:		/* Get erase, kill, and flags. */
X		flags.i.i0 = tp->tty_mode;
X		erki.c.c3  = tp->tty_ospeed;
X		erki.c.c2  = tp->tty_ispeed;
X		erki.c.c1  = tp->tty_erase;
X		erki.c.c0  = tp->tty_kill;
X		break;
X
X	case TIOCGETC:		/* Get intr, quit, xon, xoff, eof. */
X		erki.c.c3 = tp->tty_intr;
X		erki.c.c2 = tp->tty_quit;
X		erki.c.c1 = tp->tty_xon;
X		erki.c.c0 = tp->tty_xoff;
X		flags.c.c1 = tp->tty_eof;
X		flags.c.c0 = tp->tty_brk;
X		break;
X
X	case TIOCGETM:		/* Set device dependant flags */
X		flags.i.i0 = tp->tty_ddmod;
X		break;
X
X	case FIONREAD:		/* Returns number of chars to read */
X		flags.i.i0 = (unsigned) tp->tty_inbuf.count;
X		break;
X
X	case TIOCMODG:		/* raw device handles these */
X		(*tp->tty_devioctl)(tp, &m_ptr);
X		flags.l = m_ptr->TTY_FLAGS;
X		erki.l = m_ptr->TTY_SPEK;
X		break;
X
X	default:
X		/* Check for device dependant handling */
X		stat = EINVAL;
X		break;
X    }
X  }
X
X  if ((r&(IOC_IN|IOC_OUT)) == IOC_VOID)
X    switch (r) {
X	case TIOCSTOP:		/* stop output, like ^S */
X		tp->tty_state |= INHIBITED;
X		break;
X
X	case TIOCSTART:		/* start output, like ^Q */
X		tp->tty_state &= ~INHIBITED;
X		out_chars(tp);			/* restart output */
X		break;
X
X	case TIOCSBRK:		/* the raw devices handle these */
X	case TIOCCBRK:
X	case TIOCSDTR:
X	case TIOCCDTR:
X	case TIOCSMLB:
X	case TIOCCMLB:
X		(*tp->tty_devioctl)(tp, m_ptr);
X		break;
X
X	default:
X		stat = EINVAL;
X		break;
X    }
X
X  /* Send a reply */
X  tty_reply(TASK_REPLY,m_ptr->m_source, m_ptr->PROC_NR, stat, flags.l, erki.l);
X}
X
X
X/*===========================================================================*
X *				do_cancel				     *
X *===========================================================================*/
XPRIVATE void do_cancel(tp, m_ptr)
Xregister tty_entry *tp;	/* pointer to tty_struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* A signal has been sent to a process that is hanging trying to read or write.
X * The pending read or write must be finished off immediately.
X */
X	register writer,reader;
X
X  /* Find out if it is trying to write */
X
X  for(writer=0; writer<tp->tty_writers ; writer++)
X	if (m_ptr->PROC_NR == tp->w[writer].outproc) break;
X
X  /* Find out if it is the current reader */
X  reader= tp->tty_inproc==m_ptr->PROC_NR && tp->tty_inleft != 0;
X
X  /* First check to see if the process is a reader or writer with an unfinished
X   * request.  If it is not, don't reply (to avoid race conditions).
X   */
X  if ( !reader && writer>=tp->tty_writers ) return;
X
X	/* If it is a reader then ... */
X  if (reader) {
X  	bufinit(tp->tty_inbuf);		/* discard all input */
X  	tp->tty_inleft= 0;
X  	}
X
X	/* If it the current writer then discard output & complete IO */
X  if (writer == 0) {
X  	(*tp->tty_devclr)(tp);			/* clear the output stream */
X	tp->w[0].outleft = 0;			/* simulate end of write */
X	tp->tty_state &= ~WAITING;		/*   but don't reply. */
X	tp->tty_state &= ~INHIBITED;		/* do an implied ^Q */
X			/* now send real reply */
X	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR);
X	out_chars(tp);				/* restart output */
X	return;
X  }
X	/* If a writer, but not current then just dequeue it */
X  if (writer < tp->tty_writers)
X	for(tp->tty_writers-- ; writer < tp->tty_writers ; writer++)
X		tp->w[writer]=tp->w[writer+1];
X  		
X  			/* send EINTR responce to writer */
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR);
X}
X
X
X/*===========================================================================*
X *				out_chars				     *
X *===========================================================================*/
XPRIVATE void out_chars(tp)
Xregister tty_entry *tp;
X{
X/* Get chars from a process and insert into the cooked stream.
X *  Also arrange for next writer when this one completes.
X */
X	register i;
X
X		/* Safety line: check that there are writers */
X  if (tp->tty_writers == 0) return;
X		/* While there are writers remaining ... */
X  while(TRUE) {
X  	/* Try to send all the chars if the terminal is not inhibited */
X	if (!(tp->tty_state&INHIBITED)) while(tp->w[0].outleft) {
X		tp->w[0].outleft--;
X		tp->tty_cum++;
X		/* Stop when raw devices have enough chars - ^S processing
X		 * is in the low level output routines so the stop occurs
X		 * immediately and not when its buffer finally empties.
X		 */
X		if (do_cooked(tp
X		   ,(char) get_byte(tp->w[0].seg,tp->w[0].offset++),WRITE_OUT))
X			break;
X	}
X
X		/* Return if there is nothing more to do at present */
X	if (tp->w[0].outleft) return;
X
X		/* Write is finished. Flush output buffers. */
X	(*tp->tty_devflush)(tp);
X
X		/* Wake up this process */
X	if (tp->tty_state & WAITING)		/* send reply if needed */
X	    tty_reply(REVIVE,tp->w[0].otcaller,tp->w[0].outproc,tp->tty_cum);
X
X		/* Start next writer (if any) */
X	for(i=1; i < tp->tty_writers ; i++)
X		tp->w[i-1]= tp->w[i];
X	if (--tp->tty_writers == 0) {
X		tp->tty_state &= ~WAITING;		/* no more writers */
X		return;
X	}
X	tp->tty_state |= WAITING;		/* new writer wants reply */
X    }
X}
X
X/*===========================================================================*
X *				do_cooked				     *
X *===========================================================================*/
XPRIVATE bool do_cooked(tp,c,prio)
Xregister tty_entry *tp;
Xchar c;
X{
X/* Process a char according to COOKED flags etc.
X * 	prio = ECHO_OUT for non stopable stream & WRITE_OUT for normal IO.
X * Returns status as given by the low level routine.
X */
Xregister val;
X
X  /* Maintain some estimation of the current column (for XTAB,CTLECH etc).
X   * Do XTAB, CRMOD, LCASE output processing (if not in RAW mode).
X   * The current column must be estimated even in RAW mode as the console
X   * uses this estimation to calculate real locations.
X   * Set a special flag so the console can tell when to do backspace wrap.
X   */
X  if (c < ' ')
X	switch(c) {
X 	case '\t':		/* TAB - do XTAB processing */
X		if ((tp->tty_mode&(XTABS|RAW))==XTABS) {
X			do {
X				val= do_cooked(tp,' ',prio);
X			} while (tp->tty_column & (TAB_SIZE-1));
X			return val;
X		}
X			/* Assume the terminal does tabs of TAB_SIZE */
X		tp->tty_column = (tp->tty_column + TAB_SIZE) & ~(TAB_SIZE-1);
X		break;
X	case '\n':		/* LINEFEED - do CRMOD processing */
X		if ((tp->tty_mode&(CRMOD|RAW))==CRMOD)
X			do_cooked(tp,'\r',prio);
X		break;
X	case '\r':		/* CR - set column = 0 */
X		tp->tty_column = 0;
X		break;
X	case '\b':		/* BS - decr column if valid, check BS wrap */
X		if (tp->tty_column) tp->tty_column--;
X		else tp->tty_state |= BS_WRAP;
X		break;
X	}
X  else {			/* Normal char (incr column) */
X	tp->tty_column++;
X				/* LCASE processing */
X	if ((tp->tty_mode&(LCASE|RAW))==LCASE && c >= 'a' && c <= 'z')
X		c -= 'a' - 'A';
X  }
X
X	/* Now do raw device output */
X  return (*tp->tty_devraw)(tp,c,prio);
X}
X
X/*===========================================================================*
X *				tty_reply				     *
X *===========================================================================*/
XPRIVATE void tty_reply(code, replyee, proc_nr, status, extra, other)
Xint code;			/* TASK_REPLY or REVIVE */
Xint replyee;			/* destination address for the reply */
Xint proc_nr;			/* to whom should the reply go? */
Xint status;			/* reply code */
Xlong extra;			/* extra value */
Xlong other;			/* used for IOCTL replies */
X{
X/* Send a reply to a process that wanted to read or write data. */
X
X  message tty_mess;
X
X  tty_mess.m_type = code;
X  tty_mess.REP_PROC_NR = proc_nr;
X  tty_mess.REP_STATUS = status;
X  tty_mess.TTY_FLAGS = extra;	/* used by IOCTL for flags (mode) */
X  tty_mess.TTY_SPEK = other;	/* used by IOCTL for erase and kill chars */
X  send(replyee, &tty_mess);
X}
X
X
X/*===========================================================================*
X *				do_nothing				     *
X *===========================================================================*/
XPUBLIC void do_nothing()
X{
X}
X
X
X/*===========================================================================*
X *				putc					     *
X *===========================================================================*/
XPUBLIC void putc(c)
Xchar c;				/* character to print */
X{
X/* This procedure is used by the version of printf() that is linked with
X * the kernel itself.  The one in the library sends a message to FS, which is
X * not what is needed for printing within the kernel.  This version just queues
X * the character and starts the output.
X */
X
X  do_cooked(&tty_struct[0], c, WRITE_OUT);
X}
X
X/*===========================================================================*
X *				do_setpgrp				     *
X *===========================================================================*/
XPRIVATE void do_setpgrp(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* A control process group has changed.
X * At the moment this is really a slot number not a process number */
X
X   tp->tty_pgrp = m_ptr->TTY_PGRP;
X   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
X}
*-*-END-of-tty1.c-*-*
exit

marks@elec.uq.oz (Mark Schulz) (09/22/88)

echo x - tty2.c
sed 's/^X//' >tty2.c <<'*-*-END-of-tty2.c-*-*'
X/* tty2.c - device dependant code for console tty driver (IBM-PC)
X *
X * Written by:  A.Hannam	(Feb 1988)
X *
X * Modifications:
X * 28/8/88  -	Modified for MINIX V1.3 on IBM-PC
X *			Added scan-code translation & macro sequences
X * 5/9/88   -	Added a significant portion of ANSI sequences
X *			Fixed EGA code
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/******************************* CONSOLE DRIVER ******************************/
X/*****************************************************************************/
X
XPUBLIC int scan_code;		/* scancode for '=' to test if olivetti */
XPUBLIC int color;		/* 1 if console is color, 0 if it is mono */
XPUBLIC int vid_mask;		/* 037777 for color (16K) or 07777 for mono */
XPUBLIC int vid_retrace;		/* how many words to display per burst */
XPUBLIC unsigned vid_base;	/* base of video ram (0xB000 or 0xB800) */
X
XPUBLIC void int_con(), init_con();
X
Xextern	int pc_at;
Xextern	int lock();
Xextern  void do_nothing(), sigchar(), reboot(), wreboot(), restore()
X	, vid_write(), vid_fill(), vid_fmove(), vid_bmove();
X
XPRIVATE bool rout_con();
XPRIVATE unsigned trans_con();
XPRIVATE void ofl_con(), scroll_screen(), move_to(), do_escape()
X	, set_6845(), beep_on(), dset_con(), parse_escape(), set_leds()
X	, beep_off(), check_reboot();
X
X
X/* Definitions used by the console driver. */
X#define COLOR_BASE    0xB800	/* video ram paragraph for color display */
X#define MONO_BASE     0xB000	/* video ram address for mono display */
X#define C_VID_MASK    0x3FFF	/* mask for 16K video RAM */
X#define M_VID_MASK    0x0FFF	/* mask for  4K video RAM */
X#define C_RETRACE     0x0180	/* maximum words to display at once (cga) */
X#define M_RETRACE     0x7FFF	/* maximum words to display at once (mono) */
X#define BEEP_FREQ     0x0533	/* value to put into timer to set beep freq */
X#define B_TIME             3	/* length of CTRL-G beep in ticks */
X#define BLANK         0x0700	/* default blank color */
X#define GO_FORWARD         0	/* scroll forward */
X#define GO_BACKWARD        1	/* scroll backward */
X#define TIMER2          0x42	/* I/O port for timer channel 2 */
X#define TIMER3          0x43	/* I/O port for timer channel 3 */
X#define KEYBD           0x60	/* I/O port for keyboard data */
X#define PORT_B          0x61	/* I/O port for 8255 port B */
X#define KBIT            0x80	/* bit used to ack characters to keyboard */
X#define LED_CODE        0xED	/* command to keyboard to set LEDs */
X#define LED_DELAY       0x80	/* device dependent delay needed */
X#define MAX_ESC_PARMS      2	/* no. of escape sequence parameters allowed */
X#define FAST_BAUD    B115200	/* console looks like a term at this speed */
X#define BEEPING	    DD_FLAG1	/* flag in tty struct when console beeping */
X#define REBOOT	    DD_FLAG2	/* flag in tty struct when about to reboot */
X
X#define LINE_WIDTH        80	/* # characters on a line */
X#define SCR_LINES         25	/* # lines on the screen */
X
X#define ESC		 033	/* ESC for use in ansi term sequences */
X#define XOFF_CHAR	0x13	/* xoff char that these routines can decode */
X
X#define OLIVETTI_EQUAL  12	/* scan code for '=' on olivetti (13 on IBM) */
X#define CTRL_S          31	/* scan code for letter S (for CRTL-S) */
X#define DEL_CODE        83	/* code for DEL for in CTRL-ALT-DEL reboot */
X#define FUNC_KEY	58	/* codes above this belong to function keys */
X#define F10		68	/* scan code for function key F10 */
X#define TOP_ROW		14	/* codes below this are shifted if CTRL */
X#define NUM_PAD		70	/* codes above this belong to the number pad */
X#define NUM_PGDN	81	/* code for pgdn key on number pad */
X
X/* Constants relating to the video RAM and 6845. */
X#define M_6845         0x3B0	/* port for 6845 mono */
X#define C_6845         0x3D0	/* port for 6845 color */
X#define EGA            0x3C0	/* port for EGA card */
X#define INDEX              4	/* 6845's index register */
X#define DATA               5	/* 6845's data register */
X#define CUR_SIZE          10	/* 6845's cursor size register */
X#define VID_ORG           12	/* 6845's origin register */
X#define CURSOR            14	/* 6845's cursor register */
X
X/* Global variables used by the console driver. */
XPRIVATE message c_mess;		/* message used for console input chars */
X
XPRIVATE bool shift1, shift2;		/* keep track of key statii */
XPRIVATE bool capslock, numlock;
XPRIVATE bool control, alt;
X
XPRIVATE char	c_estate;		/* 0=normal, 1=ESC, 2=ESC[ etc */
XPRIVATE int	c_enum[MAX_ESC_PARMS];	/* list of escape parameters */
XPRIVATE int *	c_p_enum;		/* pointer to current escape param */
XPRIVATE int	c_row;			/* the current row for the console */
XPRIVATE int	c_attr;			/* the current character atrribute */
XPRIVATE unsigned c_blank;		/* blanking character and attribute */
XPRIVATE int	c_org;			/* origin of the screen in video ram */
XPRIVATE int	c_vid;			/* current cursor pos in video ram */
XPRIVATE int	c_port;			/* I/O port for accessing 6845 */
XPRIVATE char *	c_key_sh;		/* translation tables - shifted keys */
XPRIVATE char *	c_key_ush;		/* 		- unshifted keys */
XPRIVATE char	c_s_col;		/* saved cursor column */
XPRIVATE char	c_s_row;		/* saved cursor row */
X
X/* Scan codes to ASCII for unshifted keys */
XPRIVATE char unsh[] = {
X 0,ESC,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
X 'q','w','e','r','t','y','u','i','o','p','[',']',015,0202,'a','s',
X 'd','f','g','h','j','k','l',';',047,0140,0200,0134,'z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',0203,' ',0204,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,0205,0210,0267,0270,0271,0211,0264,0265,0266,0214,
X 0261,0262,0263,0260,0177
X};
X
X/* Scan codes to ASCII for shifted keys */
XPRIVATE char sh[] = {
X 0,ESC,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
X 'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0202,'A','S',
X 'D','F','G','H','J','K','L',':',042,'~',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0204,0213,'7','8','9','-','4','5','6','+','1',
X '2','3','0','.'
X};
X
X/* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
XPRIVATE char unm24[] = {
X 0,ESC,'1','2','3','4','5','6','7','8','9','0','-','^','\b','\t',
X 'q','w','e','r','t','y','u','i','o','p','@','[','\r',0202,'a','s',
X 'd','f','g','h','j','k','l',';',':',']',0200,'\\','z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',0203,' ',0204,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
X 0262,0263,0207,0177,0271,014,0212,'\r',0264,0262,0266,0270,032,0213,0274,'/',
X 0253,0254,0255,0256,0257,0215,0216,0217
X};
X
X/* Scan codes to ASCII for Olivetti M24 for shifted keys. */
XPRIVATE char m24[] = {
X 0,ESC,'!','"','#','$','%','&',047,'(',')','_','=','~','\b','\t',
X 'Q','W','E','R' ,'T','Y','U','I','O','P',0140,'{','\r',0202,'A','S',
X 'D','F','G','H','J','K','L','+','*','}',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0270,023,'7','8','9',0211,'4','5','6',0214,'1',
X '2','3','0','.',' ',014,0272,'\r','\b','\n','\f',036,032,0273,' ','/',
X 0233,0234,0235,0236,0237,0275,0276,0277
X};
X
XPRIVATE char *fn_macros[4][10]= {
X	{		/* no shift, control or alt - ANSI Fn Keys */
X	"\033OS","\033OT","\033OU","\033OV","\033OW",
X	"\033OP","\033OQ","\033OR","\033OX","\033OY"
X	},{		/* shift, no control or alt - (empty) */
X	0,0,0,0,0,0,0,0,0,0
X	},{		/* control, no shift or alt - (empty) */
X	0,0,0,0,0,0,0,0,0,0
X	},{		/* control & shift, no alt  - (empty) */
X	0,0,0,0,0,0,0,0,0,0
X}};
X
XPRIVATE char *fn_a_macros[2][10]= {
X	{		/* alt, no shift or control - Useful Strings */
X	"ls -al ","ls -al\n","mount /dev/","umount /dev/",
X	"dosdir -l ","dosdir -l 1\n","doswrite -a 1 ","doswrite 1 ",
X	"dosread -a 1 ","dosread 1 "
X	},{		/* alt & shift, no control  - Useful Strings */
X	0,0,0,0,0,0,0,0,0,"\nexit\n"
X}};
X
XPRIVATE char *arrow_macros[]= {
X	"[H","[A","[V","[S","[D","[G","[C","[T","[Y","[B","[U"
X	};
X
XPRIVATE charfbuf con_inbuf;
X
X#define CONS_RAM_WORDS 256
XPRIVATE int cons_ramqueue[CONS_RAM_WORDS];
XPRIVATE int cons_rwords;
X
X/*===========================================================================*
X *				init_con				     *
X *===========================================================================*/
XPUBLIC void init_con(tp)
Xregister tty_entry *tp;
X{
X
X  c_mess.TTY_LINE= CON1;		/* The interrupt message */
X  c_mess.m_type= TTY_CHAR_INT;		/* Could have been TTY_O_DONE */
X
X  /* Tell the EGA card, if any, to simulate a 16K CGA card. */
X  port_out(EGA + INDEX, 4);	/* register select */
X  port_out(EGA + DATA, 1);	/* no extended memory to be used */
X
X
X  tp->tty_devraw= rout_con;
X  tp->tty_devclr= ofl_con;
X  tp->tty_devflush= ofl_con;
X  tp->tty_devioctl= dset_con;
X  tp->tty_devtrans= trans_con;
X  tp->tty_devempty= check_reboot;
X
X		/* console requires translation and always gives 8 bits */
X  tp->tty_state |= TRANSLATE|COK8BIT;
X  tp->tty_ddmod |= CON_COOK8|CON_WRAP|D_CONSOLE;
X  tp->tty_ispeed= tp->tty_ospeed = FAST_BAUD;
X
X  tp->tty_fbuf = &con_inbuf;
X  fbufinit(con_inbuf);
X
X		/* Set parameters based on this particular machine */
X  if (color&1) {		/* What mode is the console in ? */
X	vid_base = COLOR_BASE;
X	vid_mask = C_VID_MASK;
X	c_port = C_6845;
X	vid_retrace = C_RETRACE;
X  } else {
X	vid_base = MONO_BASE;
X	vid_mask = M_VID_MASK;
X	c_port = M_6845;
X	vid_retrace = M_RETRACE;
X  }
X  if (scan_code == OLIVETTI_EQUAL) {
X  	c_key_sh= m24;
X  	c_key_ush= unm24;
X  } else {
X  	c_key_sh= sh;
X  	c_key_ush = unsh;
X  }
X
X  c_blank = c_attr = BLANK;		/* attribute byte for screen */
X  cons_rwords = 0;			/* initialize buffer */
X  c_estate = 0;				/* ESC state is 0 */
X  c_s_col = c_s_row = 0;		/* The saved cursor pos is home */
X  set_6845(CUR_SIZE, 23);		/* set cursor shape (old = 31) */
X  set_6845(VID_ORG, c_org = 0);		/* use page 0 of video ram */
X  move_to(0,SCR_LINES-1);		/* move cursor to bottom left corner */
X}
X
X
X/*===========================================================================*
X *				int_con					     *
X *===========================================================================*/
XPUBLIC void int_con()
X{
X/* A keyboard interrupt has occurred.  Process it. (Interrupts are off) */
X
X  int val, c;
X
X  /* Fetch the character from the keyboard hardware and acknowledge it. */
X  port_in(KEYBD, &c);		/* get the scan code for the key struck */
X  port_in(PORT_B, &val);	/* strobe the keyboard to ack the char */
X  port_out(PORT_B, val | KBIT);	/* strobe the bit high */
X  port_out(PORT_B, val);	/* now strobe it low */
X
X  /* If Keyboard Locked then discard char */
X  if (tty_struct[CON1].tty_ddmod&CON_LOCK) {
X	port_out(INT_CTL, ENABLE);
X 	return;
X  }
X
X  /* The IBM keyboard interrupts twice per key, once when depressed, once when
X   * released.  Filter out the latter, ignoring all but the shift-type keys.
X   * The shift-type keys, 29, 42, 54, 56, 58, and 69 must be processed normally.
X   */
X  if (c > 0200)
X	switch(c) {
X		case 29 + 0200:		case 42 + 0200:
X		case 54 + 0200:		case 56 + 0200:
X		case 58 + 0200:		case 69 + 0200:
X			break;
X		default:			/* re-enable interrupts */
X			port_out(INT_CTL, ENABLE);
X		 	return;			/* don't call tty_task() */
X	}
X
X  /* Check for CTRL-ALT-DEL, and if found set a flag. */
X  if (control && alt && c == DEL_CODE)
X	tty_struct[CON1].tty_state |= REBOOT;
X
X/* Check to see if character is CTRL-S, to stop output. Setting xoff
X * to anything other than CTRL-S will not be detected here, but will
X * be detected later, in the driver.  A general routine to detect any
X * xoff character here would be complicated since we only have the
X * scan code here, not the ASCII character. This is just done to
X * improve responce.
X */
X  if ( !(tty_struct[CON1].tty_mode & RAW)
X	&& tty_struct[CON1].tty_xoff == XOFF_CHAR
X	&& control && c == CTRL_S ) {
X		tty_struct[CON1].tty_state |= INHIBITED;
X		port_out(INT_CTL, ENABLE);
X		return;
X  }
X
X
X  /* Store the character in memory so the task can get at it later. */
X  if ( bufnfull(con_inbuf) ) {
X	putfobj(con_inbuf,c);	/* Enough room so store the char */
X	}
X
X  /* Inform other routines that we have chars available */
X  tty_struct[CON1].tty_state |= IN_FLUSH;
X  flush_flag |= IN_FLUSH;
X
X  /* Build and send the int message to tty task only if absolutly necessary */
X  if (bufcount(con_inbuf) >= CHAR_BUF_THRESHOLD) {
X	interrupt(TTY, &c_mess);
X	}
X
X  port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X}
X
X/*===========================================================================*
X *				dset_con				     *
X *===========================================================================*/
XPRIVATE void dset_con(tp, m)
Xregister tty_entry *tp;
Xregister message *m;
X{
X  switch (m->TTY_REQUEST) {
X	case TIOCSETN:
X	case TIOCSETP:
X			/* Console baud rate is always fast */
X		tp->tty_ispeed= tp->tty_ospeed= FAST_BAUD;
X		break;
X
X	case TIOCSETM:
X			/* Ensure modes are valid - if something looks
X			 * suspicious then don't allow keyboard lock.
X			 */
X		if (!(tp->tty_ddmod & D_CONSOLE))
X			tp->tty_ddmod &= ~CON_LOCK;
X		tp->tty_ddmod &= (CON_COOK8|CON_LOCK|CON_WRAP|CON_INSERT);
X		tp->tty_ddmod |= D_CONSOLE;
X			/* Process the device dependant modes */
X		if (tp->tty_ddmod & CON_COOK8)
X			tp->tty_state |= COK8BIT;
X		else
X			tp->tty_state &= ~COK8BIT;
X		break;
X
X	case TIOCMODG:
X			/* This looks like an operating terminal */
X		m->TTY_FLAGS = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS
X				|TIOCM_CAR|TIOCM_DSR;
X		m->TTY_SPEK  = 0;
X		break;
X
X	/* Ignore all other ioctl calls */
X  }
X}
X
X
X/*===========================================================================*
X *				rout_con				     *
X *===========================================================================*/
XPRIVATE bool rout_con(tp, c, prio)
Xregister tty_entry *tp;		/* pointer to tty struct */
Xchar c;				/* character to be output */
X{
X/* Output a character on the console. Priority order is ...
X *	Handle control codes,
X *	Handle escape sequences
X *	Handle normal chars
X *
X * This allows control code processing to occur without disturbing
X * escape sequences.
X */
X
X  if (c < ' ') switch(c) {		/* Handle control codes */
X
X		/* Cancel a escape sequence and beep */
X	case 0x18:					/* CAN & SUB */
X	case 0x1A:
X		if (!c_estate) break;
X		c_estate = 0;
X
X		/* ring the bell */
X	case 007:					/* BEL */
X		ofl_con();
X		beep_on(BEEP_FREQ,B_TIME);
X		break;
X
X		/* BackSpace - with EOL wrap - (left) */
X	case '\b':					/* BS */
X		if (tp->tty_state & BS_WRAP) {
X			tp->tty_state &= ~BS_WRAP;
X			if (c_row != 0 && tp->tty_ddmod&CON_WRAP) {
X				c_row--;
X				tp->tty_column= LINE_WIDTH - 1;
X			}
X		}
X		move_to(tp->tty_column, c_row);
X		break;
X
X		/* Tab Handling - don't bother clearing space */
X	case '\t':					/* HT */
X		move_to(tp->tty_column, c_row);
X		break;
X
X		/* line feed (down) */
X	case '\n':					/* NL */
X		if (c_row >= SCR_LINES-1) 
X			scroll_screen(GO_FORWARD);
X		else
X			c_row++;
X		move_to(tp->tty_column, c_row);
X		break;
X
X		/* vertical tab - (up) */
X	case 0x0B:					/* VT */
X		c_row--;
X		move_to(tp->tty_column, c_row);
X		break;
X
X		/* form feed - (right) */
X	case 0x0C:					/* FF */
X		move_to(tp->tty_column+1, c_row);
X		break;
X
X		/* carriage return */
X	case '\r':					/* CR */
X		move_to(0, c_row);
X		break;
X
X		/* ESC - start of an escape sequence */
X	case ESC:					/* ESC */
X		c_estate = 0;
X		parse_escape(c);
X		break;
X
X		/* All other control codes are ignored */
X
X  } else if (c_estate != 0) {		/* Handle Escape Sequences */
X	parse_escape(c);
X  } else {				/* Normal Chars */
X		/* printable chars are stored in outqueue */
X		/* They are being used as words (not bytes) */
X	if (cons_rwords >= CONS_RAM_WORDS) ofl_con();
X
X	if (tp->tty_column < LINE_WIDTH)
X		cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X	else if (tp->tty_ddmod&CON_WRAP) {	/* Long Lines */
X		cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X		move_to(0, c_row);		/* Implied \r */
X		rout_con(tp,'\n',prio);		/* Implied \n */
X	}
X  }
X
X  	/* Handle ^S processing and ECHO_OUT priority */
X  if (tp->tty_state&INHIBITED || prio==ECHO_OUT) ofl_con();
X  return (tp->tty_state&INHIBITED);
X}
X
X/*===========================================================================*
X *				scroll_screen				     *
X *===========================================================================*/
XPRIVATE void scroll_screen(dir)
Xint dir;			/* GO_FORWARD or GO_BACKWARD */
X{
X  register offset;
X
X  /* Hardware Scrolling. It is up to the video routines to ensure the screen is
X   * written in such a way that scrolling over the ram boundary works on
X   * both CGA,MONO (which support ram wrap) and EGA (which may not support
X   * ram wrap).
X   */
X  ofl_con();				/* Flush the output stream */
X  if (dir == GO_FORWARD) {		/* Calculate the new video origin */
X	c_org += 2 * LINE_WIDTH;
X	c_org &= vid_mask;
X	offset = c_org + 2*(SCR_LINES-1)*LINE_WIDTH;
X  } else {
X	c_org -= 2 * LINE_WIDTH;
X	c_org &= vid_mask;
X	offset = c_org;
X  }
X
X  /* Blank the new line at top or bottom. */
X  vid_fill(c_blank, offset, LINE_WIDTH);
X  set_6845(VID_ORG, c_org >> 1);		/* 6845 thinks in words */
X}
X
X/*===========================================================================*
X *				ofl_con					     *
X *===========================================================================*/
XPRIVATE void ofl_con()
X{
X/* Have the characters in 'outqueue' transferred to the screen. */
Xregister unsigned i;
X
X  if (cons_rwords == 0) return;
X
X	/* Do insert mode processing */
X  if (tty_struct[CON1].tty_ddmod&CON_INSERT) {
X	i = c_org + c_row*2*LINE_WIDTH + (2*LINE_WIDTH-2); /* end of line */
X	vid_bmove(i - cons_rwords*2, i
X		, LINE_WIDTH - MIN(tty_struct[CON1].tty_column,LINE_WIDTH));
X  }
X
X	/* Write the chars to the screen */
X  vid_write(cons_ramqueue, c_vid, cons_rwords);
X
X  /* Update the video parameters and cursor. */
X  c_vid += 2*cons_rwords;
X  set_6845(CURSOR, c_vid >> 1);	/* cursor counts in words */
X  cons_rwords = 0;
X}
X
X
X/*===========================================================================*
X *				move_to					     *
X *===========================================================================*/
XPRIVATE void move_to(x, y)
Xint x;				/* column (0 <= x <= 79) */
Xint y;				/* c_row (0 <= y <= 24, 0 at top) */
X{
X/* Move the cursor to (x, y). */
X
X  ofl_con();				/* flush any pending characters */
X  x = between(0, x, LINE_WIDTH-1);	/* ensure x & y are valid */
X  y = between(0, y, SCR_LINES -1);
X  tty_struct[CON1].tty_column = x;	/* set x co-ordinate */
X  c_row = y;				/* set y co-ordinate */
X  c_vid = c_org + y*2*LINE_WIDTH + 2*x;
X  set_6845(CURSOR, c_vid >> 1);	/* cursor counts in words */
X}
X
X/*===========================================================================*
X *				set_6845				     *
X *===========================================================================*/
XPRIVATE void set_6845(reg, val)
Xregister reg;			/* which register pair to set */
Xregister val;			/* 16-bit value to set it to */
X{
X/* Set a register pair inside the 6845.  
X * Registers 10-11 control the format of the cursor (how high it is, etc).
X * Registers 12-13 tell the 6845 where in video ram to start (in WORDS)
X * Registers 14-15 tell the 6845 where to put the cursor (in WORDS)
X *
X * Note that registers 12-15 work in words, i.e. 0x0000 is the top left
X * character, but 0x0001 (not 0x0002) is the next character.  This addressing
X * is different from the way the 8088 addresses the video ram, where 0x0002
X * is the address of the next character.
X */
X  port_out(c_port + INDEX, reg);		/* set the index register */
X  port_out(c_port + DATA, (val>>8) & BYTE);	/* output high byte */
X  port_out(c_port + INDEX, reg + 1);		/* again */
X  port_out(c_port + DATA, val&BYTE);		/* output low byte */
X}
X
X
X/*===========================================================================*
X *				beep_on					     *
X *===========================================================================*/
XPRIVATE void beep_on(f,d)
Xregister f;			/* this value determines beep frequency */
Xregister d;			/* this value is the time to sound in ticks */
X{
X/* Making a beeping sound on the speaker (output for CRTL-G). This routine
X * works by turning on the bits in port B of the 8255 chip that drive the
X * speaker and sending a clock message to time the beep.
X */
X  int x, s;
X  message m;
X
X  if (tty_struct[CON1].tty_state & BEEPING) return;
X  s = lock();			/* disable interrupts */
X  port_out(TIMER3,0xB6);	/* set up timer channel 2 mode */
X  port_out(TIMER2, f&BYTE);	/* load low-order bits of frequency in timer */
X  port_out(TIMER2,(f>>8)&BYTE);	/* now high-order bits of frequency in timer */
X  port_in(PORT_B,&x);		/* acquire status of port B */
X  port_out(PORT_B, x|3);	/* turn bits 0 and 1 on to beep */
X  tty_struct[CON1].tty_state |= BEEPING;
X  restore(s);			/* re-enable interrupts */
X
X  m.m_type = SET_ALARM;		/* set up the duration */
X  m.CLOCK_PROC_NR = TTY;
X  m.DELTA_TICKS = d;		/* beep for d ticks */
X  m.FUNC_TO_CALL = (int (*)()) beep_off;	/* func to switch off beep */
X  sendrec(CLOCK, &m);
X}
X
X/*===========================================================================*
X *				beep_off				     *
X *===========================================================================*/
XPRIVATE void beep_off()
X{
X/* Turn off the beep on the speaker (output for CRTL-G). This routine
X * is called only by the CLOCK task.
X */
Xint s,x;
X
X  s = lock();			/* disable interrupts */
X  port_in(PORT_B, &x);		/* get status of port B */
X  port_out(PORT_B, x & 0xFFFC);	/* turn bits 0 and 1 off to stop beep */
X  tty_struct[CON1].tty_state &= ~BEEPING;
X  restore(s);			/* restore interrupts */
X}
X
X
X/*===========================================================================*
X *				func_key				     *
X *===========================================================================*/
XPRIVATE func_key(ch)
Xchar ch;			/* scan code for a function key */
X{
X/* This procedure traps function keys for debugging purposes.  When MINIX is
X * fully debugged, it should be removed.
X */
X
X  switch (ch) {
X
X	case FUNC_KEY+1:		/* print process table */
X		p_dmp();
X		break;
X
X	case FUNC_KEY+2:		/* print memory map */
X		map_dmp();
X		break;
X
X	case FUNC_KEY+3:		/* Switch between EGA (with no     */
X		color ^= 2;		/* retrace checking) and CGA/MONO. */
X		printf("\n\rVideo Card = %s\n\r"
X		    ,(color&2 ? "EGA": (color&1 ? "CGA":"MONO")));
X		break;			/* This is useful to control the   */
X					/* scrolling speed of EGA cards.   */
X
X#ifdef AM_KERNEL
X#ifndef NONET
X	case FUNC_KEY+4:		/* re-initialise the ethernet card */
X		net_init();
X		break;
X#endif NONET
X#endif AM_KERNEL
X
X	case FUNC_KEY+9:		/* kill all process */
X		sigchar(&tty_struct[CON1], SIGKILL);
X		break;
X  }
X}
X
X/*===========================================================================*
X *				trans_con				     *
X *===========================================================================*/
XPRIVATE unsigned trans_con(c)
Xunsigned c;			/* scan code of key just struck or released */
X{
X/* This routine handles the console keyboard scan-code to ascii conversion.
X * It has some ANSI sequences and various macros hardwired to certain keys.
X *	E.g. Arrow keys and Function Keys. At the moment there is no way to
X *	change the macros at run-time but lator the console output routines
X *	may define ANSI sequences to do this.
X * This is a general translation routine with no hardware dependancies
X *	except for keyboard leds (on an AT).
X * Note: The type of scan-code translation (Olivetti or IBM) is determined
X *	during initialization (not here).
X */
X
X  unsigned char code;
X  bool make;
X  static char *seq_str= "";
X
X		/* Do Macro Key Sequences (including ANSI keys) */
X  switch (c>>8) {
X  	case 0:			/* Non Macro Key */
X  		break;
X  	case 1:			/* Macro String */
X  		if (*seq_str)
X  			return *seq_str++ | 0x100;
X  		return MARKER;
X  	default:		/* Unknown - ignore */
X  		return MARKER;
X  	}
X
X		/* Start a Arrow Key ANSI macro */
X  if (c > NUM_PAD && c <= NUM_PGDN && !((shift1|shift2)^numlock)) {
X	seq_str= arrow_macros[c - (NUM_PAD+1)];
X	return ESC | 0x100;			/* Send the escape */
X	}
X
X		/* Start a Funtion Key macro */
X  if(c > FUNC_KEY && c <= F10) {
X  	if (control && alt) {		/* Special CONSOLE DEBUG routines */
X		func_key(c);
X		return MARKER;
X		}
X
X		/* Handle other combinations of shift, control & alt */
X		/* There is no possiblility of control when alt is on */
X	seq_str= (alt ? fn_a_macros[shift1|shift2]
X		: fn_macros[shift1|shift2|(control<<1)]) [c - (FUNC_KEY+1)];
X	if (*seq_str)
X		return *seq_str++ | 0x100;
X	return MARKER;
X	}
X
X  make = !(c & 0200);		/* 1 when key depressed, 0 when key released */
X  c &= 0177;			/* high-order bit set on key release */
X
X	/* Standard IBM keyboard. Do shift processing */
X  code = ((shift1 | shift2)^ (
X  			/* Check capslock for alpha */
X  		(capslock && c_key_ush[c] >= 'a' && c_key_ush[c] <= 'z') ||
X  			/* Check numlock for number pad */
X  		(c > NUM_PAD && numlock) ))
X			? c_key_sh[c] : c_key_ush[c];
X  if (control && c < TOP_ROW) code = c_key_sh[c];	/* CTRL-(top row) */
X
X	/* Process ordinary keys, i.e. not shift, control, alt, etc. */
X  if (code < 0200 || code > 0205) {
X	if (!make)	return MARKER;	/* key release */
X	if (control)	code &= 037;
X	if (alt)	code |= 0200;	/* alt key ORs 0200 into code */
X	return code;
X  }
X
X  /* Table entries 0200 - 0205 denote special actions. */
X  switch(code - 0200) {
X    case 0:	shift1 = make;			break;	/* shift key on left */
X    case 1:	shift2 = make;			break;	/* shift key on right*/
X    case 2:	control = make;			break;	/* control */
X    case 3:	alt = make;			break;	/* alt key */
X    case 4:	if (make) capslock = 1-capslock;
X    		set_leds();			break;	/* caps lock */
X    case 5:	if (make) numlock  = 1-numlock;
X    		set_leds();			break;	/* num lock */
X  }
X  return MARKER;	/* No high level processing to do */
X}
X
X/*===========================================================================*
X *				escape					     *
X *===========================================================================*/
XPRIVATE void parse_escape(c)
Xchar c;				/* next character in escape sequence */
X{
X/* Parse and build an escape sequence.
X * Formats understood ...
X *
X *	ESC char					: state = 0x01
X *	ESC '[' [num] char				: state = 0x02
X *
X * where num is from 1 to MAX_ESC_PARMS decimal strings seperated by ';'s.
X *	more than MAX_ESC_PARMS decimal strings are ignored.
X */
Xregister i;
X
X  /* This char is not printable but the column has been incremented */
X		/* fix this by decrementing it */
X  tty_struct[CON1].tty_column--;
X
X  if (c_estate == 0) {			/* ESC seen - initialize sequence */
X		c_estate = 1;
X		c_p_enum = c_enum;
X		for(i=0; i<MAX_ESC_PARMS ; i++)
X			c_enum[i] = 0;
X		return;
X  }
X
X  if (c_estate == 2) {			/* Only allow numbers in "ESC [" seq */
X	if (c >= '0' && c <= '9') {
X		if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X			*c_p_enum = *c_p_enum * 10 + (c - '0');
X		return;
X	}
X				/* Start a new number in sequence */
X	if (c == ';') {
X		if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X			c_p_enum++;
X		return;
X	}
X  }
X
X				/* A char has arrived - process it */
X  switch (c_estate) {
X	case 0x01: 		/* "ESC char" sequence */
X		if (c == '[') {		/* "ESC '['" sequence is starting */
X			c_estate = 0x02; 
X			return;
X		}
X		break;
X
X	case 0x02: 		/* "ESC '[' [num] char" sequence */
X		break;
X
X	default:		/* illegal state */
X		c_estate = 0;
X		return;
X  }
X
X  /* A syntacticly valid ESC sequence has arrived - process it */
X  do_escape(c);
X  c_estate = 0;			/* The sequence is finished */
X}
X
X
X/*===========================================================================*
X *				do_escape				     *
X *===========================================================================*/
XPRIVATE void do_escape(c)
Xchar c;				/* next character in escape sequence */
X{
X/* The following ANSI escape sequences are currently supported:
X *   ESC D		index the screen
X *   ESC M		reverse index the screen
X *   ESC E		next line
X *   ESC 7		save cursor position
X *   ESC 8		restore cursor position
X *   ESC [ n A		Cursor Up			[default 1]
X *   ESC [ n B		Cursor Down			[default 1]
X *   ESC [ n C		Cursor Right			[default 1]
X *   ESC [ n D		Cursor Left			[default 1]
X *   ESC [ y ; x f	move cursor to (x, y)		[default (1,1)]
X *   ESC [ y ; x H	move cursor to (x, y)		[default (1,1)]
X *   ESC [ n J		clear a section of screen	[default 0]
X *			n: 0 = cursor to bottom of screen
X *			   1 = cursor to top of screen
X *			   2 = top to bottom of screen
X *   ESC [ n K		clear a section of line		[default 0]
X *			n: 0 = cursor to end of line
X *			   1 = cursor to start of line
X *			   2 = start to end of line
X *   ESC [ n L		insert n lines at cursor	[default 1]
X *   ESC [ n M		delete n lines at cursor	[default 1]
X *   ESC [ n @		insert n chars at cursor	[default 1]
X *   ESC [ n P		delete n chars at cursor	[default 1]
X *   ESC [ n h		set mode			[default 0]
X *   ESC [ n l		reset mode			[default 0]
X *			n: 2 = Keyboard Lock [pwr up Off]
X *			   4 = Insert Mode   [pwr up Off]
X *			   7 = Auto Wrap     [pwr up ON]
X *   ESC [ n m		set the screen rendition	[default 0]
X *			n: 0 = normal
X *			   1 = bold
X *			   4 = underline
X *			   5 = blink
X *			   7 = reverse
X */
Xregister unsigned i, j;
X
X  switch (c_estate) {
X	case 0x01:			/* ESC char */
X	    switch (c) {
X		case 'M':		/* Reverse Index */
X			if (c_row == 0)
X				scroll_screen(GO_BACKWARD);
X			else {
X				c_row--;
X				move_to(tty_struct[CON1].tty_column, c_row);
X			}
X			return;
X
X		case '7':
X			c_s_row = c_row;
X			c_s_col = tty_struct[CON1].tty_column;
X			return;
X
X		case '8':
X			move_to(c_s_col, c_s_row);
X			return;
X
X		case 'E':
X			move_to(0, c_row);
X		case 'D':
X			rout_con(&tty_struct[CON1],'\n',ECHO_OUT);
X			return;
X
X		default:		/* Illegal ESC char sequence */
X		    return;
X	    }
X
X	case 0x02:			/* ESC '[' [num] char */
X	    switch (c) {
X		case 'A':		/* Cursor Up */
X		    move_to(tty_struct[CON1].tty_column
X			, c_row - MAX(1,c_enum[0]));
X		    return;
X		case 'B':		/* Cursor Down */
X		    move_to(tty_struct[CON1].tty_column
X			, c_row + MAX(1,c_enum[0]));
X		    return;
X		case 'C':		/* Cursor Right */
X		    move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X			, c_row);
X		    return;
X		case 'D':		/* Cursor Left */
X		    move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X			, c_row);
X		    return;
X
X		case 'f':		/* Position cursor */
X		case 'H':
X		    move_to(c_enum[1]-1, c_enum[0]-1);
X		    return;
X
X		case 'J':
X		    ofl_con();		/* Flush pending chars */
X		    switch (c_enum[0]) {
X			case 1:		/* Clear start of screen to cursor */
X			    vid_fill(c_blank, c_org
X				, c_row * LINE_WIDTH
X				  + tty_struct[CON1].tty_column + 1);
X			    return;
X			case 2:		/* Clear entire screen */
X			    vid_fill(c_blank, c_org, SCR_LINES*LINE_WIDTH);
X			    return;
X			case 0:		/* Clear cursor to end of screen*/
X			    vid_fill(c_blank, c_vid
X				, (SCR_LINES - c_row) * LINE_WIDTH
X				  - tty_struct[CON1].tty_column);
X			    return;
X		    }
X		    return;
X
X		case 'K':
X		    ofl_con();		/* Flush pending chars */
X		    switch(c_enum[0]) {
X			case 0:		/* Clear cursor to end of line */
X			    vid_fill(c_blank, c_vid
X				,LINE_WIDTH - tty_struct[CON1].tty_column);
X			    return;
X			case 1:		/* Clear start of line to cursor */
X			    vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X				, tty_struct[CON1].tty_column + 1);
X			    return;
X			case 2:		/* Clear entire line */
X			    vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X				, LINE_WIDTH);
X			    return;
X		    }
X		    return;
X
X		case 'L':			/* Insert Lines */
X		    ofl_con();		/* Flush pending chars */
X
X		    i = between(1,c_enum[0],SCR_LINES - c_row);	/* No. lines */
X		    j = c_org + (SCR_LINES*LINE_WIDTH*2-2); /* end of screen */
X
X				/* Do the line moving */
X		    vid_bmove(j - i*2*LINE_WIDTH, j
X			, (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X				/* Clear the inserted lines */
X		    vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X			, i*LINE_WIDTH);
X		    return;
X
X		case 'M':			/* Delete Lines */
X		    ofl_con();		/* Flush pending chars */
X
X		    i = between(1,c_enum[0],SCR_LINES - c_row);	/* No. lines */
X		    j = c_org + c_row*2*LINE_WIDTH;	/* Destination */
X
X				/* Do the line moving */
X		    vid_fmove(j + i*2*LINE_WIDTH, j
X			, (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X				/* Clear the new lines */
X		    vid_fill(c_blank, c_org + (SCR_LINES - i)*LINE_WIDTH*2
X			, i*LINE_WIDTH);
X		    return;
X
X		case '@':			/* Insert Chars */
X		    ofl_con();		/* Flush pending chars */
X
X		    i = between(1,c_enum[0]		/* No. chars */
X		    	,LINE_WIDTH - tty_struct[CON1].tty_column);
X		    j = c_org + c_row*2*LINE_WIDTH	/* end of line */
X			+ (2*LINE_WIDTH-2);
X
X				/* Do the char moving */
X		    vid_bmove(j - i*2, j
X			, LINE_WIDTH - tty_struct[CON1].tty_column);
X
X				/* Clear the new chars */
X		    vid_fill(c_blank, c_vid, i);
X		    return;
X
X		case 'P':			/* Delete Chars */
X		    ofl_con();		/* Flush pending chars */
X
X		    i = between(1,c_enum[0]		/* No. chars */
X			,LINE_WIDTH - tty_struct[CON1].tty_column);
X		    j = c_org + c_row*2*LINE_WIDTH	/* Destination */
X			+ tty_struct[CON1].tty_column;
X
X				/* Do the char moving */
X		    vid_fmove(j + i*2, j
X			, LINE_WIDTH - tty_struct[CON1].tty_column - i);
X
X				/* Clear the new chars */
X		    vid_fill(c_blank, c_org + (c_row+1)*LINE_WIDTH*2 - i*2, i);
X		    return;
X
X		case 'h':		/* Set mode */
X 		    switch (c_enum[0]) {
X 			case 2:		/* Keyboard Lock */
X 			    tty_struct[CON1].tty_ddmod |= CON_LOCK;
X 			    return;
X 			case 4:		/* Insert Mode */
X 			    tty_struct[CON1].tty_ddmod |= CON_INSERT;
X 			    return;
X 			case 7:		/* Auto Wrap */
X 			    tty_struct[CON1].tty_ddmod |= CON_WRAP;
X 			    return;
X 		    }
X 		    return;
X
X		case 'l':		/* Reset mode */
X 		    switch (c_enum[0]) {
X 			case 2:		/* Keybaord Unlock */
X 			    tty_struct[CON1].tty_ddmod &= ~CON_LOCK;
X 			    return;
X 			case 4:		/* Overwrite Mode */
X 			    tty_struct[CON1].tty_ddmod &= ~CON_INSERT;
X 			    return;
X 			case 7:		/* No Auto Wrap */
X 			    tty_struct[CON1].tty_ddmod &= ~CON_WRAP;
X 			    return;
X 		    }
X 		    return;
X
X		case 'm':		/* Set graphic rendition */
X 		    switch (c_enum[0]) {
X 			case 1: /*  BOLD  (light green on black)  */
X 				c_attr = 0x0A00;
X 				return;
X 
X 			case 4: /*  UNDERLINE  (blue on red)  */
X 				c_attr = 0x4100;
X 				return;
X 
X 			case 5: /*  BLINKING  (light grey on black)  */
X				c_attr = 0x8700;
X 				return;
X 
X 			case 7: /*  REVERSE  (black on light grey)  */
X 				c_attr = 0x7000;
X  				return;
X
X 			default: c_attr = 0x0700;
X 				return;
X 		    }
X
X		default:	/* Illegal ESC [ sequence */
X		    return;
X	    }
X
X	default:		/* Illegal state */
X	    return;
X  }
X}
X
X/*===========================================================================*
X *				set_leds				     *
X *===========================================================================*/
XPRIVATE void set_leds()
X{
X/* Set the LEDs on the caps lock and num lock keys */
X
X  int leds, dummy, i;
X
X  if (pc_at == 0) return;	/* PC/XT doesn't have LEDs */
X  leds = (numlock<<1) | (capslock<<2);	/* encode LED bits */
X  port_out(KEYBD, LED_CODE);	/* prepare keyboard to accept LED values */
X  port_in(KEYBD, &dummy);	/* keyboard sends ack; accept it */
X  for (i = 0; i < LED_DELAY; i++) ;	/* delay needed */
X  port_out(KEYBD, leds);	/* give keyboard LED values */
X  port_in(KEYBD, &dummy);	/* keyboard sends ack; accept it */
X}
X
X/*===========================================================================*
X *				check_reboot				     *
X *===========================================================================*/
XPRIVATE void check_reboot()
X{
X/* High Level Reboot (Here because int routines can't print) */
X
X  if (tty_struct[CON1].tty_state & REBOOT) {
X	printf("\r\n\033[H\033[J\033[12;27HPress any key to Reboot :");
X	ofl_con();		/* Flush the string */
X	wreboot();
X	}
X}
*-*-END-of-tty2.c-*-*
echo x - tty3.c
sed 's/^X//' >tty3.c <<'*-*-END-of-tty3.c-*-*'
X/* tty3.c - device dependant code for RS232 tty driver (using 8250)
X *
X * Written by:  A.Hannam	(Feb 1988)
X *
X * Modifications:
X * 7/9/88   -	Modified for MINIX V1.3 on IBM-PC
X *			Improved interrupt handling
X *			Improved efficiency of compiled code
X * 19/9/88  -	Added flow control (handshaking) & many ioctl calls
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/**************************** 8250 SERIAL DRIVER *****************************/
X/*****************************************************************************/
X
X#if NR_8250S < 1
XError:- 8250 Driver: "NR_8250S" < 1
X#endif
X
XPUBLIC void int_8250(), init_8250();
X
Xextern void do_nothing(), restore();
Xextern int lock();
X
XPRIVATE bool rout_8250();
XPRIVATE void dset_8250(), oclr_8250(), iflow_8250();
X
X  /* Some space and variables for the raw Output routines */
XGEN_S_BUF_TYPE(char,128)
XGEN_S_BUF_TYPE(char,32)
X
X#define BUSY		DD_FLAG1	/* 1 when tty busy on output */
X#define RX_FLOW		DD_FLAG2	/* 1 when input doing flow cntrl */
X#define TX_FLOW		DD_FLAG3	/* 1 when output doing flow cntrl */
X
X#define WOUT_THRESHOLD	4	/* when to start trying to get more chars */
X#define XONCHAR		17	/* ^Q to restart with XONXOFF control */
X#define XOFFCHAR	19	/* ^S to stop with XONXOFF control */
X
X	/* interrupt identification register bits */
X#define IPENDING	1	/* 1 when no interrupt pending */
X#define ITYPEMASK	6	/* mask to isolate interrupt causes */
X#define RXREADY		4	/* reciever is ready interrupt */
X#define TXREADY		2	/* transmitter ready interrupt */
X#define LSTATUS		6	/* line status event interrupt */
X#define MSTATUS		0	/* modem status event interrupt */
X	/* line control register bits */
X/* bits 0,1 are number of databits as defined in sgtty.h */
X/* bit 2 is the number of stopbits as defined in sgtty.h */
X#define P_ENABLE	8	/* enable parity bit */
X#define P_EVEN		16	/* even parity bit */
X#define P_STICK		32	/* the parity sticks to 1 on P_EVEN else 0 */
X#define P_BRK		64	/* break enable bit */
X#define P_BAUD		128	/* set up for baud divisor input */
X	/* line status register bits */
X#define L_DR		1	/* data recieved status bit */
X#define L_OE		2	/* overrun error status bit */
X#define L_PE		4	/* parity error status bit */
X#define L_FE		8	/* framing error status bit */
X#define L_BI		16	/* break detected status bit */
X#define L_HRE		32	/* holding reg empty status bit */
X#define L_TE		64	/* transmitter empty status bit */
X	/* interrupt enable register bits */
X#define I_DR		1	/* enable recieved data interrupt */
X#define I_TE		2	/* enable transmit reg empty interrupt */
X#define I_LS		4	/* reciever line status interrupt */
X#define I_MS		8	/* modem status interrupt */
X	/* modem control register bits */
X#define M_DTR		1	/* DTR output bit */
X#define M_RTS		2	/* RTS output bit */
X#define M_OUT1		4	/* OUT1 output bit */
X#define M_OUT2		8	/* OUT2 output bit */
X#define M_LOOP		16	/* enable loopback mode bit */
X	/* modem status register bits */
X#define M_CTSC		1	/* CTS input has changed bit */
X#define M_DSRC		2	/* DSR input has changed bit */
X#define M_RIT		4	/* RI input (low to high transition) bit */
X#define M_DCDC		8	/* DCD input has changed bit */
X#define M_CTS		16	/* CTS input bit */
X#define M_DSR		32	/* DSR input bit */
X#define M_RI		64	/* RI input bit */
X#define M_DCD		128	/* DCD input bit */
X
XPRIVATE message mess_8250;	/* our message buffer */
XPRIVATE char modem_bits;	/* bits for RTS, CTS status etc. */
X
XPRIVATE struct rs_struct {
X	int ldata;		/* Tx/Rx data register */
X	int lreg;		/* Line control register */
X	int intreg;		/* Interrupt control register */
X	int intid;		/* Interrupt status register */
X	int baud;		/* Register (& +1) for baud */
X	int lstat;		/* Line status register */
X	int modreg;		/* Modem line control register */
X	int mstat;		/* Modem status register */
X	char32 eout;		/* Pointer to the echo out buffer */
X	char128 wout;		/* Pointer to the write out buffer */
X	charfbuf in;		/* Pointer to the input buffer */
X	} rs[NR_8250S] = {{
X	0x3F8, 0x3FB, 0x3F9, 0x3FA, 0x3F8, 0x3FD, 0x3FC, 0x3FE
X		, {"",0,0,0}, {"",0,0,0}, {"",0}
X#if NR_8250S >= 2
X	},{
X	0x2F8, 0x2FB, 0x2F9, 0x2FA, 0x2F8, 0x2FD, 0x2FC, 0x2FE
X		, {"",0,0,0}, {"",0,0,0}, {"",0}
X#endif
X#if NR_8250S >= 3
XError:- Need Extra port tables for COM3 ...
X#endif
X	}};
X
X/*===========================================================================*
X *				init_8250				     *
X *===========================================================================*/
XPUBLIC void init_8250(tp)
Xregister tty_entry *tp;
X{
Xregister i = tp - &tty_struct[COM1];
X
X  mess_8250.TTY_LINE= COM1;		/* The interrupt message */
X  mess_8250.m_type= TTY_CHAR_INT;	/* Could have been TTY_O_DONE */
X
X  tp->tty_devraw= rout_8250;
X  tp->tty_devclr= oclr_8250;
X  tp->tty_devflush= do_nothing;
X  tp->tty_devioctl= dset_8250;
X  tp->tty_devtrans= (unsigned (*)()) do_nothing;
X  tp->tty_devempty= iflow_8250;
X
X#ifdef NXONXOFF
X	/* 8 Data, 1 Stop bits, No Parity, Hardware handshaking */
X  tp->tty_ddmod= D_SERIAL | SER_8DATA;
X#else
X	/* 8 Data, 1 Stop bits, No Parity, XONXOFF  handshaking */
X  tp->tty_ddmod = D_SERIAL | SER_8DATA | TX_XONXOFF | RX_XONXOFF;
X#endif
X  tp->tty_mode &= ~(EVENP|ODDP);
X
X#ifdef SLOW
X  tp->tty_ispeed = tp->tty_ospeed = B1200;
X#else
X  tp->tty_ispeed = tp->tty_ospeed = B4800;
X#endif
X
X  tp->tty_fbuf = &rs[i].in;
X  fbufinit(rs[i].in);
X  bufinit(rs[i].wout);
X  bufinit(rs[i].eout);
X  modem_bits = (M_DTR|M_RTS|M_OUT2);	/* DTR, RTS on, ints enabled */
X
X  dset_8250(tp, 0);
X}
X
X
X
X/*===========================================================================*
X *				int_8250				     *
X *===========================================================================*/
XPUBLIC void int_8250(unit)
X{		/* Interrupts are off */
X	/* Called when an interrupt occurs on the RS232 a port */
Xchar c;
Xregister tty_entry *tp= &tty_struct[COM1+unit];
Xregister struct rs_struct *r = &rs[unit];
X
X  /* Ignore any interrupts on lines we don't know about */
X  if (unit >= NR_8250S) return;
X
X  while(TRUE) {
X	port_in(r->intid, &c);
X
X	if (c&IPENDING) break;		/* no interrupt to process */
X
X	switch (c & ITYPEMASK) {
X	    case RXREADY:			/* Get a character */
X		port_in(r->ldata,&c);
X
X		/* Store the char if possible */
X		if ( bufnfull(r->in) ) {
X  			/* Enough room so store the char */
X			putfobj(r->in,c);
X			}
X
X		/* Tell other routines we have chars available */
X		tp->tty_state |= IN_FLUSH;
X		flush_flag |= IN_FLUSH;
X
X		/* Send the int message to tty task only if abs. needed */
X		if (bufcount(r->in) >= CHAR_BUF_THRESHOLD) {
X			/* Do Flow Control */
X			tp->tty_state |= RX_FLOW;
X			if (tp->tty_ddmod & RX_XONXOFF)
X				/* jam a ^S into the output stream */
X				port_out(r->ldata,XOFFCHAR);
X			else {
X				/* hardware hanshaking */
X				modem_bits &= ~M_DTR;
X				port_out(r->modreg,modem_bits);
X			}
X			interrupt(TTY, &mess_8250);
X		}
X		/* The high level routine must turn back on the flow control */
X		break;
X
X	    case TXREADY:			/* Transmit more data */
X			/* XT and some clones generate spurious ints */
X		port_in(r->lstat,&c);
X		if (!(c&L_HRE)) break;
X
X		tp->tty_state &= ~BUSY;		/* Assume port now free */
X
X		/* Get data from the echo stream */
X		if (bufnempty(r->eout)) {
X			port_out(r->ldata,getobj(r->eout));
X			advgetobj(r->eout);
X			tp->tty_state |= BUSY;
X			break;
X		}
X
X		/* If inhibited don't get data from write stream */
X		if (tp->tty_state&(INHIBITED|TX_FLOW)) break;
X
X		/* get data from write stream */
X		if (bufnempty(r->wout)) {
X		    port_out(r->ldata,getobj(r->wout));
X		    advgetobj(r->wout);
X		    tp->tty_state |= BUSY;
X		    }
X
X		/* If nearly empty make an attempt at getting more */
X		if (bufcount(r->wout) <= WOUT_THRESHOLD
X			&& tp->tty_writers) {
X		    tp->tty_state |= OUT_FLUSH;
X		    flush_flag |= OUT_FLUSH;
X		    }
X
X		/* No more data available, urgently try to get more */
X		if (bufempty(r->wout) && tp->tty_writers) {
X		    tp->tty_state |= OUT_FLUSH;
X		    interrupt(TTY,&mess_8250);
X		}
X		break;
X
X	    case LSTATUS:			/* line status event */
X		port_in(r->lstat, &c);		/* disabled */
X		break;
X
X	    case MSTATUS:			/* modem status event */
X		port_in(r->mstat, &c);
X			/* XONXOFF output flow cntrl in device indep driver */
X		if (tp->tty_ddmod & TX_XONXOFF) break;
X
X		if ((c&(M_CTS|M_DSR)) == (M_CTS|M_DSR))
X			tp->tty_state &= ~TX_FLOW;
X		else
X			tp->tty_state |= TX_FLOW;
X		break;
X	}
X  }
X  port_out(INT_CTL,ENABLE);
X}
X
X
X/*===========================================================================*
X *				rout_8250				     *
X *===========================================================================*/
XPRIVATE bool rout_8250(tp,c,prio)
Xregister tty_entry *tp;
Xchar c;
X{
X/* Fill up the buffers in FIFO manner according to the priority */
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X	save_st = lock();
X		/* If not busy then send echo's straight to the hardware */
X	if (!(tp->tty_state&BUSY) && (prio==ECHO_OUT)) {
X		port_out(r->ldata,c);
X		tp->tty_state |= BUSY;
X		restore(save_st);
X		return 0;
X	}
X
X	/* Transmitter currently busy or char in write stream. Queue it FIFO */
X		/* If ECHO_OUT and not enough space then try in write stream */
X	if (prio==ECHO_OUT && bufnfull(r->eout)) {
X		putobj(r->eout,c);
X		restore(save_st);
X		return 0;
X	}
X
X	/* Place in write stream if there is enough room */
X	if (bufnfull(r->wout)) {
X		putobj(r->wout,c);
X	}
X
X	/* If still not busy try to restart IO.
X	 *  This is subject to characters being writable (^S processing).
X	 */
X	if (!(tp->tty_state&(INHIBITED|BUSY|TX_FLOW)) && bufnempty(r->wout)) {
X		port_out(r->ldata,getobj(r->wout));
X		advgetobj(r->wout);
X		tp->tty_state |= BUSY;
X	}
X
X		/* Warn the user if the stream is filling up */
X	restore(save_st);
X	return (prio==ECHO_OUT
X		|| (int)bufcount(r->wout) >= (int)bufsize(r->wout)*7/8);
X}
X
Xstatic unsigned char SBHigh[]= {0,9,9,6,4,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0}
X		,SBLow[]={0,0xE4,0,0,0x17,0x59,0,0x40,0x80,0xC0
X				,0x60,0x40,0x3A,0x30,0x18,0xC,6,3,2,1};
X
X/*===========================================================================*
X *				dset_8250				     *
X *===========================================================================*/
XPRIVATE void dset_8250(tp, m)
Xregister tty_entry *tp;
Xmessage *m;
X{
Xint c, save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X/* set baud rate, bits/char, etc
X */
X   if (m)
X     switch(m->TTY_REQUEST) {
X 	case TIOCSETN:
X 	case TIOCSETP:
X			/* Don't support split baud */
X		tp->tty_ospeed= tp->tty_ispeed;
X		break;
X
X	case TIOCSETM:
X			/* Only keep Valid Mode bits */
X		tp->tty_ddmod &= SER_2STOP|SER_DATABITS|RX_XONXOFF|TX_XONXOFF;
X		tp->tty_ddmod |= D_SERIAL;
X		break;
X
X	case TIOCMODS:
X		port_in(r->modreg, &c);
X		c &= ~(M_DTR|M_RTS);
X		if (((int)m->TTY_FLAGS) & TIOCM_DTR) c |= M_DTR;
X		if (((int)m->TTY_FLAGS) & TIOCM_RTS) c |= M_RTS;
X		port_out(r->modreg, c);
X		return;
X
X	case TIOCMODG:
X		port_in(r->modreg, &c);
X		m->TTY_FLAGS = (long)((unsigned) TIOCM_LE
X			| ((c&M_DTR) ? TIOCM_DTR : 0)
X			| ((c&M_RTS) ? TIOCM_RTS : 0));
X		port_in(r->mstat, &c);
X		m->TTY_FLAGS |= (long)((unsigned) ((c&M_CTS) ? TIOCM_CTS : 0)
X			| ((c&M_DCD) ? TIOCM_CAR : 0)
X			| ((c&M_DSR) ? TIOCM_DSR : 0)
X			| ((c&M_RI ) ? TIOCM_RNG : 0));
X		m->TTY_SPEK = 0;
X		return;
X
X	case TIOCSBRK:
X		port_in(r->lreg, &c);
X		c |= P_BRK;
X		port_out(r->lreg, c);
X		return;
X
X	case TIOCCBRK:
X		port_in(r->lreg, &c);
X		c &= ~P_BRK;
X		port_out(r->lreg, c);
X		return;
X
X	case TIOCSDTR:
X		port_in(r->modreg, &c);
X		c |= M_DTR;
X		port_out(r->modreg, c);
X		return;
X
X	case TIOCCDTR:
X		port_in(r->modreg, &c);
X		c &= ~M_DTR;
X		port_out(r->modreg, c);
X		return;
X
X	case TIOCSMLB:
X		port_in(r->modreg, &c);
X		c |= M_LOOP;
X		port_out(r->modreg, c);
X		return;
X
X	case TIOCCMLB:
X		port_in(r->modreg, &c);
X		c &= ~M_LOOP;
X		port_out(r->modreg, c);
X		return;
X
X	default:	/* Ignore all other ioctl calls */
X		return;
X    }
X
X	  /* set up c with line control params i.e. data,stop,parity */
X  c = tp->tty_ddmod & (SER_2STOP|SER_DATABITS);
X  if (tp->tty_mode&ANYP) {
X	c |= P_ENABLE;
X	if (tp->tty_mode&EVENP) c |= P_EVEN;
X  }
X
X	/* Now set according to the modes */
X  save_st = lock();
X
X  port_out(r->lreg,P_BAUD);			/* Set up for baud */
X  port_out(r->baud+1,SBHigh[tp->tty_ospeed]);	/* set Baud rate */
X  port_out(r->baud,SBLow[tp->tty_ospeed]);
X
X  port_out(r->lreg,c);			/* set data, stop & parity */
X
X  port_in(r->lstat, &c);		/* Clear any data from controller */
X  if (c & L_DR) port_in(r->ldata,&c);
X
X  port_in(r->mstat,&c);		/* Check output flow control */
X  tp->tty_state &= ~TX_FLOW;
X  if (!(tp->tty_ddmod&TX_XONXOFF) && (c&(M_CTS|M_DSR)) != (M_CTS|M_DSR))
X	tp->tty_state |= TX_FLOW;
X	
X  if (tp->tty_state & RX_FLOW) {		/* cancel input flow control */
X	modem_bits |= M_DTR;			/* set up DTR etc */
X	port_out(r->ldata,XONCHAR);		/* jam ^Q in output */
X	tp->tty_state &= ~RX_FLOW;
X  }
X  port_out(r->modreg,modem_bits);
X  if (tp->tty_ddmod&TX_XONXOFF)
X	port_out(r->intreg, I_DR|I_TE );	/* TX & RX ints */
X  else
X	port_out(r->intreg, I_DR|I_TE|I_MS);	/* TX, RX & MS ints */
X
X  restore(save_st);
X}
X
X/*===========================================================================*
X *				oclr_8250				     *
X *===========================================================================*/
XPRIVATE void oclr_8250(tp)
Xregister tty_entry *tp;
X{
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X	save_st = lock();
X	bufinit(r->eout);
X	bufinit(r->wout);
X	restore(save_st);
X}
X
X/*===========================================================================*
X *				iflow_8250				     *
X *===========================================================================*/
XPRIVATE void iflow_8250(tp)
Xregister tty_entry *tp;
X{
X/* The input buffers have been cleared ...
X * Handle flow control for the input stream
X */
X  if (tp->tty_state & RX_FLOW) {
X	if (tp->tty_ddmod & RX_XONXOFF)		/* XON-XOFF handshaking */
X		rout_8250(tp, XONCHAR, ECHO_OUT);
X	else {				/* Hardware handshaking */
X		modem_bits |= M_DTR;
X		port_out(rs[tp - &tty_struct[COM1]].modreg,modem_bits);
X	}
X	tp->tty_state &= ~RX_FLOW;
X  }
X}
*-*-END-of-tty3.c-*-*
exit