[comp.os.minix] v1.3 compatible RS232 driver for ST MINIX

schreiner@iravcl.ira.uka.de (09/29/89)

This is my RS232 version for the ST. It needs no extra task because it
is *very* similar to those of PC MINIX 1.3. It works with echo up to
9600, but without echo at 9600 it isn't fast enough to get every
incoming character in time. At 4800 this works too. Speed tests are
made with a second ST as source/drain.
Serveral sources which must change outside the kernel are addded too.
E.g. install ioctl.o in libc.a before linking login(1), init(1) and stty(1).
For those without patch there is an additional shar archive at the end
of this posting containing normal diff's instead of cdiffs. Without

	Ralf Wenk,	using a friends account

------------------ Cut here --------------------------------------------
echo x - login.c
sed 's/^X//' > login.c << '/'
X/* login - log into the system		Author: Patrick van Kleef */
X
X/* Peter S. Housel   Jan. 1988
X *  - Set up $USER, $HOME and $TERM.
X *  - Set signals to SIG_DFL.
X *
X * Terrence W. Holm   June 1988
X *  - Allow a username as an optional argument.
X *  - Time out if a password is not typed within 30 seconds.
X *  - Perform a dummy delay after a bad username is entered.
X *  - Cause a failure on bad PW_SHELL fields.
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#define WTMPSIZE	8
X#define DIGIT		3
X
Xextern char *crypt();
Xextern struct passwd *getpwnam();
Xextern long time();
Xextern long lseek();
Xint Time_out();
X
Xint  time_out;
X
Xchar user[ 32 ];
Xchar logname[ 35 ];
Xchar home[ 64 ];
Xchar shell[ 64 ];
X
Xchar *env[] = {
X	      user,
X	      logname,
X	      home,
X	      shell,
X	      NULL
X};
X
X
Xmain( argc, argv ) 
Xint   argc;
Xchar *argv[];
X{
X	char    name[30];
X	char	password[30];
X	int     bad;
X	int	n;
X	int 	ttynr;
X	struct  sgttyb args;
X	struct  passwd *pwd;
X	struct stat statbuf;
X
X	/* Reset some of the line parameters in case they have been mashed */
X	if ( ioctl(0, TIOCGETP, &args) < 0 ) exit( 1 );
X
X	args.sg_kill  = '@';
X	args.sg_erase = '\b';
X	args.sg_flags = (args.sg_flags & 01700) | XTABS | CRMOD | ECHO;
X	ioctl (0, TIOCSETP, &args);
X
X	/* Get login name and passwd. */
X	for (;;) {
X		bad = 0;
X
X		if ( argc > 1 ) {
X		    strcpy( name, argv[1] );
X		    argc = 1;
X		} else {
X		    do {
X			n = read (0, name, 30);
X		    } while (n < 2);
X		    name[n - 1] = 0;
X		}
X
X		/* Look up login/passwd. */
X		if ((pwd = getpwnam (name)) == 0) bad++;
X
X		/* If login name wrong or password exists, ask for pw. */
X		if (bad || strlen (pwd->pw_passwd) != 0) {
X			args.sg_flags &= ~ECHO;
X			ioctl (0, TIOCSETP, &args);
X
X			time_out = 0;
X			signal( SIGALRM, Time_out );
X			alarm( 30 );
X
X			n = read (0, password, 30);
X
X			alarm( 0 );
X			if ( time_out ) {
X				n = 1;
X				bad++;
X			}
X
X			password[n - 1] = 0;
X			write(1,\N,1);
X			args.sg_flags |= ECHO;
X			ioctl (0, TIOCSETP, &args);
X
X			if (bad && crypt(password, AAAA) ||
X			 strcmp (pwd->pw_passwd, crypt(password, pwd->pw_passwd))) {
X				continue;
X			}
X		}
X
X		/*  Check if the system is going down  */
X						strcmp( name, ROOT ) != 0 ) {
X			continue;
X		}
X
X
X		/* Look up /dev/tty number. */
X		fstat(0, &statbuf);
X		ttynr = statbuf.st_rdev & 0377;
X		ttyname[DIGIT] = '0' + ttynr;
X
X		/*  Write login record to /usr/adm/wtmp  */
X		wtmp(ttyname, name);
X
X		setgid( pwd->pw_gid );
X		setuid( pwd->pw_uid );
X
X		if (pwd->pw_shell[0]) sh = pwd->pw_shell;
X
X		/*  Set the environment  */
X		strcat( user,   name );
X		strcat( logname, name );
X		strcat( home,  pwd->pw_dir );
X		strcat( shell, sh );
X
X		chdir( pwd->pw_dir );
X
X		/* Reset signals to default values. */
X
X		for ( n = 1;  n <= NR_SIGS;  ++n )
X		    signal( n, SIG_DFL );
X
X		execle( sh, 
X		exit(1);
X	}
X}
X
X
X
XTime_out( )
X{
X  time_out = 1;
X}
X
Xwtmp(tty, name)
Xchar *tty, *name;
X{
X/* Make an entry in /usr/adm/wtmp. */
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, WTMPSIZE);
X  strncpy(namebuff, name, WTMPSIZE);
X  time(&t);
X  write(fd, ttybuff, WTMPSIZE);
X  write(fd, namebuff, WTMPSIZE);
X  write(fd, &t, sizeof(t));
X  close(fd);
X}
/
echo x - stty.c
sed 's/^X//' > stty.c << '/'
X/* stty - set terminal mode  	Author: Andy Tanenbaum */
X
X#include <sgtty.h>
Xint k;
X
Xstruct sgttyb args;
Xstruct tchars tch;
X
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 speed(s) args.sg_ispeed = s;  args.sg_ospeed = s
X#define clr1 args.sg_flags &= ~(BITS5 | BITS6 | BITS7 | BITS8)
X#define clr2 args.sg_flags &= ~(EVENP | ODDP)
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X  /* stty with no arguments just reports on current status. */
X  ioctl(0, TIOCGETP, &args);
X  ioctl(0, TIOCGETC, &tch);
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(0, TIOCSETP, &args);
X  ioctl(0, TIOCSETC, &tch);
X  exit(0);
X}
X
X
X
Xreport()
X{
X  int mode;
X  char ispeed;
X
X  mode = args.sg_flags;
X  ispeed = args.sg_ispeed;
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  if (ispeed > 0) {
X	/* Print # bits/char and parity */
X
X	/* Print line speed. */
X	switch(ispeed) {
X		case B110 : prints(110);	break;
X		case B300 : prints(300);	break;
X		case B600 : prints(600);	break;
X		case B1200: prints(1200);	break;
X		case B2400: prints(2400);	break;
X		case B4800: prints(4800);	break;
X		case B9600: prints(9600);	break;
X			    (ispeed + '0'):(ispeed + 'A' - 10));
X	}
X  }
X  prints(\N);
X}
X
Xpr(f, n)
Xint f,n;
X{
X  if (f)
X  else
X}
X
Xoption(opt, next)
Xchar *opt, *next;
X{
X
X  if (match(opt, TABS))	{args.sg_flags |= XTABS; return;}
X  if (match(opt, EVEN))	{clr2; args.sg_flags |= EVENP; return;}
X  if (match(opt, ODD))	{clr2; args.sg_flags |= ODDP; 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
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
X  if (match(opt, 5))		{clr1; args.sg_flags |= BITS5; return;}
X  if (match(opt, 6))		{clr1; args.sg_flags |= BITS6; return;}
X  if (match(opt, 7))		{clr1; args.sg_flags |= BITS7; return;}
X  if (match(opt, 8))		{clr1; args.sg_flags |= BITS8; return;}
X
X  if (match(opt, 110))	{speed(B110); return;}
X  if (match(opt, 300))	{speed(B300); return;}
X  if (match(opt, 1200))	{speed(B1200); return;}
X  if (match(opt, 2400))	{speed(B2400); return;}
X  if (match(opt, 4800))	{speed(B4800); return;}
X  if (match(opt, 9600))	{speed(B9600); return;}
X
X  if (match(opt, DEFAULT))	{
X	args.sg_flags = ECHO | CRMOD | XTABS | BITS8;
X	args.sg_ispeed = B1200;
X	args.sg_ospeed = B1200;
X	args.sg_kill = '@';
X	args.sg_erase = '\b';
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  std_err(opt);
X  std_err(\N);
X
X}
X
Xint match(s1, s2)
Xchar *s1, *s2;
X{
X
X  while (1) {
X	if (*s1 == 0 && *s2 == 0) return(1);
X	if (*s1 == 0 || *s2 == 0) return(0);
X	if (*s1 != *s2) return(0);
X	s1++;
X	s2++;
X  }
X}
X
Xprctl(c)
Xchar c;
X{
X  if (c < ' ')
X  else if (c == 0177)
X	prints(DEL);
X  else
X	prints(%C, c);
X}
/
echo x - ioctl.c
sed 's/^X//' > ioctl.c << '/'
X#include <minix/com.h>
X#include <sgtty.h>
X
XPUBLIC int ioctl(fd, request, u)
Xint fd;
Xint request;
Xunion {
X  struct sgttyb *argp;
X  struct tchars *argt;
X} u;
X
X{
X  int n;
X  long erase, kill, intr, quit, xon, xoff, eof, brk;
X
X  M.TTY_REQUEST = request;
X  M.TTY_LINE = fd;
X
X  switch(request) {
X     case TIOCSETP:
X	erase = u.argp->sg_erase & 0377;
X	kill = u.argp->sg_kill & 0377;
X	M.TTY_SPEK = (erase << 8) | kill;
X	M.TTY_FLAGS = u.argp->sg_flags;
X	M.TTY_FLAGS |= (( u.argp->sg_ospeed << 8 ) | u.argp->sg_ispeed ) << 16L;
X	n = callx(FS, IOCTL);
X  	return(n);
X 
X     case TIOCSETC:
X  	intr = u.argt->t_intrc & 0377;
X  	quit = u.argt->t_quitc & 0377;
X  	xon  = u.argt->t_startc & 0377;
X  	xoff = u.argt->t_stopc & 0377;
X  	eof  = u.argt->t_eofc & 0377;
X  	brk  = u.argt->t_brkc & 0377;		/* not used at the moment */
X  	M.TTY_SPEK = (intr<<24) | (quit<<16) | (xon<<8) | (xoff<<0);
X  	M.TTY_FLAGS = (eof<<8) | (brk<<0);
X  	n = callx(FS, IOCTL);
X  	return(n);
X  	
X     case TIOCGETP:
X  	n = callx(FS, IOCTL);
X	u.argp->sg_erase = (M.TTY_SPEK >> 8) & 0377;
X	u.argp->sg_kill  = (M.TTY_SPEK >> 0) & 0377;
X  	u.argp->sg_flags = M.TTY_FLAGS;
X  	u.argp->sg_ospeed = M.TTY_FLAGS >> 24;
X  	u.argp->sg_ispeed = M.TTY_FLAGS >> 16;
X  	return(n);
X
X     case TIOCGETC:
X  	n = callx(FS, IOCTL);
X  	u.argt->t_intrc  = (M.TTY_SPEK >> 24) & 0377;
X  	u.argt->t_quitc  = (M.TTY_SPEK >> 16) & 0377;
X  	u.argt->t_startc = (M.TTY_SPEK >>  8) & 0377;
X  	u.argt->t_stopc  = (M.TTY_SPEK >>  0) & 0377;
X  	u.argt->t_eofc   = (M.TTY_FLAGS >> 8) & 0377;
X  	u.argt->t_brkc   = (M.TTY_FLAGS >> 8) & 0377;
X  	return(n);
X
X     default:
X	n = -1;
X	errno = -(EINVAL);
X	return(n);
X  }
X}
X
/
echo x - init.c
sed 's/^X//' > init.c << '/'
X/* This process is the father (mother) of all MINIX user processes.  When
X * MINIX comes up, this is process 2.  It executes the /etc/rc shell file and
X * then reads the /etc/ttys file to find out which terminals need a login
X * process.  The ttys file consists of 3-character lines as follows:
X *	abc
X * where
X *	a = 0 (line disabled = no shell), 1 (enabled = shell started)
X *	b = a-r defines UART paramers (baud, bits, parity), 0 for console
X *	c = line number
X *
X * The letters a-r correspond to the 18 entries of the uart table below.
X * For example, 'a' is 110 baud, 8 bits, no parity; 'b' is 300 baud, 8 bits,
X * no parity; 'j' is 2400 baud, 7 bits, even parity; etc.
X *
X * If the file /usr/adm/wtmp exists and is writable, init (with help from
X * login) maintains login accounting used by who(1).
X */
X
X
X#define PIDSLOTS          10
X#define NPARAMSETS  	  18
X#define STACKSIZE        256
X#define DIGIT              8
X#define OFFSET             5
X#define SHELL              1
X#define NOPARAMS        -100
X#define WTMPSIZE           8
X
Xextern long time();
Xextern long lseek();
X
Xstruct uart {
X  int baud;
X  int flags;
X} uart[NPARAMSETS] = {
X	B110,   BITS8,		/*  110 baud, 8 bits, no parity */
X	B300,   BITS8,		/*  300 baud, 8 bits, no parity */
X	B1200,  BITS8,		/* 1200 baud, 8 bits, no parity */
X	B2400,  BITS8,		/* 2400 baud, 8 bits, no parity */
X	B4800,  BITS8,		/* 4800 baud, 8 bits, no parity */
X	B9600,  BITS8,		/* 9600 baud, 8 bits, no parity */
X
X	B110,   BITS7 | EVENP,	/*  110 baud, 7 bits, even parity */
X	B300,   BITS7 | EVENP,	/*  300 baud, 7 bits, even parity */
X	B1200,  BITS7 | EVENP,	/* 1200 baud, 7 bits, even parity */
X	B2400,  BITS7 | EVENP,	/* 2400 baud, 7 bits, even parity */
X	B4800,  BITS7 | EVENP,	/* 4800 baud, 7 bits, even parity */
X	B9600,  BITS7 | EVENP,	/* 9600 baud, 7 bits, even parity */
X
X	B110,   BITS7 | ODDP,	/*  110 baud, 7 bits, odd parity */
X	B300,   BITS7 | ODDP,	/*  300 baud, 7 bits, odd parity */
X	B1200,  BITS7 | ODDP,	/* 1200 baud, 7 bits, odd parity */
X	B2400,  BITS7 | ODDP,	/* 2400 baud, 7 bits, odd parity */
X	B4800,  BITS7 | ODDP,	/* 4800 baud, 7 bits, odd parity */
X	B9600,  BITS7 | ODDP	/* 9600 baud, 7 bits, odd parity */
X};
X
Xint pid[PIDSLOTS];		/* pids of init's own children */
Xint save_params[PIDSLOTS];
Xint pidct;
Xextern int errno;
X
Xchar stack[STACKSIZE];
Xchar *stackpt = &stack[STACKSIZE];
X
Xstruct sgttyb args;
X
X
Xmain()
X{
X  char line[10];		/* /etc/ttys lines should be 3 chars */
X  int rc, tty, k, status, ttynr, ct, i, params, shell;
X
X  /* Carry out /etc/rc. */
X  sync();			/* force buffers out onto RAM disk */
X
X  /* Execute the /etc/rc file. */
X  if (fork()) {
X	/* Parent just waits. */
X	wait(&k);
X  } else {
X	/* Child exec's the shell to do the work. */
X	exit(-2);		/* impossible */
X  }
X
X  /* Make the /usr/adm/wtmp entry. */
X  wtmp(~,");			/* log system reboot */
X
X  /* Read the /etc/ttys file and fork off login processes. */
X	/* Process /etc/ttys file. */
X	while ( (ct = read(0, line, 4)) == 4) {
X		/* Extract and check the 3 characters on each line. */
X		shell = line[0] - '0';	/* 0, 1, 2 for disabled, sh, no sh */
X		params = line[1] - 'a';	/* selects UART parameters */
X		ttynr = line[2] - '0';	/* line number */
X		if (shell <= 0 || shell > 1) continue;
X		if (line[1] == '0') params = NOPARAMS;
X		else if (params < 0 || params > NPARAMSETS) continue;
X		if (ttynr < 0 || ttynr > PIDSLOTS) continue;
X
X		save_params[ttynr] = params;
X		startup(ttynr, params);
X	}
X  } else {
X	while (1) ;		/* just hang -- system cannot be started */
X  }
X  close(tty);
X
X  /* All the children have been forked off.  Wait for someone to terminate.
X   * Note that it might be a child, in which case a new login process must be
X   * spawned off, or it might be somebody's orphan, in which case ignore it.
X   * First ignore all signals.
X   */
X  for (i = 1; i <= NR_SIGS; i++) signal(i, SIG_IGN);
X
X  while (1) {
X	sync();
X	k = wait(&status);
X	pidct--;
X
X	/* Search to see which line terminated. */
X	for (i = 0; i < PIDSLOTS; i++) {
X		if (pid[i] == k) {
X			name[DIGIT] = '0' + i;
X			wtmp(&name[OFFSET], ");
X			startup(i, save_params[i]);
X		}
X	}
X  }
X}
X
X
Xstartup(linenr, params)
Xint linenr, params;
X{
X/* Fork off a process for the indicated line. */
X
X  int k, n;
X
X  if ( (k = fork()) != 0) {
X	/* Parent */
X	pid[linenr] = k;
X	pidct++;
X  } else {
X	/* Child */
X	close(0);		/* /etc/ttys may be open */
X	name[DIGIT] = '0' + linenr;
X	if (open(name, 2) != 0) exit(-3);	/* standard input */
X	if (open(name, 2) != 1) exit(-3);	/* standard output */
X	if (open(name, 2) != 2) exit(-3);	/* standard error */
X
X
X	/* Set line parameters. */
X  	if (params != NOPARAMS) {
X		n = ioctl(0, TIOCGETP, &args);	/* get parameters */
X		args.sg_ispeed = uart[params].baud;
X		args.sg_ospeed = uart[params].baud;
X		args.sg_flags = CRMOD | XTABS | ECHO | uart[params].flags;
X		n = ioctl(0, TIOCSETP, &args);
X	}
X
X	/* Try to exec login, or in an emergency, exec the shell. */
X	return;			/* impossible */
X  }
X}
X
Xwtmp(tty, name)
Xchar *tty, *name;
X{
X/* Make an entry in /usr/adm/wtmp. */
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, WTMPSIZE );
X  strncpy(namebuff, name, WTMPSIZE );
X  time(&t);
X  write(fd, ttybuff, WTMPSIZE);
X  write(fd, namebuff, WTMPSIZE);
X  write(fd, &t, sizeof(t));
X  close(fd);
X}
/
echo x - strs232.c
sed 's/^X//' > strs232.c << '/'
X#ifdef ATARI_ST
X/* The ST MINIX RS232 driver code.
X * Ralf Wenk		last update:	Fri Sep 29 13:04:22 1989
X *
X * Supports 5 to 8 data bits, even, odd, or none parity and several speeds
X * between 50 and 19200 baud. Character translation is done according to
X * the given mode. SIGHUP generated if BREAK detected.
X * Dummy iob interrupt handler.
X *
X * Synchronous mode and hardware hand-shake are not suported.
X * Speeds over 4800 are only usefull as login tty.
X */
X
X/* The MFP interrupts, it values and handlers:
X *
X *	00	01	02	03	03	02	0	0
X *	pia	iob	iob	iob	tim	clk	acia	dma
X *	BUSY	DCD	CTS	GPUDONE	T-D	SYS-CLK	KBD	FDC/ACIA
X *
X *	01	03	02	01	00	00	06	07
X *	tim	sia	sia	sia	sia	tim	iob	iob
X *	T-B	TERR	TRDY	RERR	RRDY	T-A	RI	MONO
X */
X
X
X
X/* The siaint() interrupt handler values */
X#define RRDY	0		/* serial Receiver ReaDY (=Full) */
X#define RERR	1		/* serial Receiver ERRor */
X#define TRDY	2		/* serial Transmitter ReaDY (=Empty) */
X#define TERR	3		/* serial Transmitter ERRor Int */
X
X/* some values used by the code */
X#define OUT_SIZE	256	/* size of output translation buffer */
X#define SPARE		32	/* room for echo, must be greater one tabsize */
X#define IN_SIZE		(2*MAX_OVERRUN+2) /* size of interrupt input buffer */
X#define OFLOW		5	/* # of chars to allow little buffer overflow */
X#define TRESHOLD	((IN_SIZE-2*OFLOW-2)/2)
X				/* # of chars to accumulate before msg */
X#define DATA_LEN	8	/* how much to shift sg_mode for len */
X#define SYN		0x16	/* The sync character */
X#define NONE		0	/* parity */
X#define ODD		1	/* or ... */
X#define EVEN		2	/* or ... */
X#define DEF_BAUD	B1200	/* default baud rate */
X
X#define DEBUG(x)	/* x */
X
X
XEXTERN struct tty_struct tty_struct[];
XPRIVATE char baud_table[] = {
X				3,  96,	/*    50 bd #  0 */
X				3,  64,	/*    75 bd #  1 */
X				1, 175,	/*   110 bd #  2 */
X				1, 143,	/*   134 bd #  3 */
X				1, 128,	/*   150 bd #  4 */
X				1,  64,	/*   300 bd #  5 */
X				1,  96,	/*   200 bd #  6 */
X				1,  32,	/*   600 bd #  7 */
X				1,  16,	/*  1200 bd #  8 */
X				1,  11,	/*  1800 bd #  9 */
X				1,  10,	/*  2000 bd # 10 */
X				1,   8,	/*  2400 bd # 11 */
X				1,   5,	/*  3600 bd # 12 */
X				1,   4,	/*  4800 bd # 13 */
X				1,   2,	/*  9600 bd # 14 */
X				1,   1,	/* 19200 bd # 15 */
X			    };
XPRIVATE struct tty_struct *tp;
XPRIVATE message rs232_rm;		/* used when chars arrived */
XPRIVATE message rs232_wm;		/* used when output done */
XPRIVATE int  t_err_ok;			/* the next tx-error is legal */
XPRIVATE int  t_state;			/* transmitter state */
XPRIVATE int  rs_busy;			/* RS232 output is ... */
XPRIVATE char rs_translate[OUT_SIZE];	/* translation buffer for output */
XPRIVATE char *rs_next;			/* next char to output */
XPRIVATE char *rs_ulimit;		/* max fill pos. of transl. buffer */
XPRIVATE int  rs_left;			/* # of chars left in buffer */
XPRIVATE int  rs_column;			/* column on tty */
XPRIVATE char rsbuf[IN_SIZE];		/* input interrupt buffer */
X
XPUBLIC int output_done;
X
X
X/*===========================================================================*
X *				tx_err					     *
X *===========================================================================*/
X/* A transmitter error occured */
XPRIVATE void tx_err ()
X{
X  register int val;
X
X  t_state = MFP->mf_tsr;
X  val = MFP->mf_udr;
X}	/* tx_err */
X
X
X/*===========================================================================*
X *				rx_err					     *
X *===========================================================================*/
X/* A receiver error occured */
XPRIVATE void rx_err ()
X{
X  register int val;
X  register int r_state;
X  void RxD();
X
X  r_state = MFP->mf_rsr;		/* why ? */
X  RxD();				/* get the char, possible garbage */
X  if ( r_state & R_BREAK )		/* break seen ? */
X    sigchar( tp, SIGHUP );		/* the other side has hung up */
X}	/* rx_err */
X
X
X/*===========================================================================*
X *				rs_flush				     *
X *===========================================================================*/
X/* Flush the tty_driver_buf by sending a message to TTY. This procedure can
X * be triggered locally, when a character arrives, or by the clock task.
X * The interrupt message is build by rs232init().
X */
XPUBLIC void rs_flush ()
X{
X  if ( rsbuf[0] )			/* something to flush ? */
X    interrupt( TTY, &rs232_rm );	/* send a message to the tty task */
X}	/* rs_flush */
X
X
X/*===========================================================================*
X *				RxD					     *
X *===========================================================================*/
X/* Fetch the data from the UART and store it so the TTY task can get at it
X * later. Before the buffer overflows the data is thrown away.
X */
XPRIVATE void RxD ()
X{
X  register int  r0;
X  register char c;
X
X  c = MFP->mf_udr;			/* get data from MFP */
X  r0 = rsbuf[0];
X  if ( r0 < rsbuf[1] )			/* room enough to store it ? */
X  {
X    rsbuf[0] = ++r0;			/* increment counter */
X    r0 <<= 1;				/* each entry contains two bytes */
X    rsbuf[r0] = c;			/* store the data */
X    if ( r0 >= TRESHOLD )		/* must we send a message ? */
X      rs_flush();			/* send TTY task a message */
X  }
X}	/* RxD */
X
X
X/*===========================================================================*
X *				rs_write_int				     *
X *===========================================================================*/
X/* An output ready interrupt has occurred, or a write has been done to an idle
X * line.  In both cases, start the output.
X */
XPRIVATE void rs_write_int ()
X{
X  while ( rs_left > 0 )			/* some char to output ? */
X  {
X    MFP->mf_udr = *rs_next++;		/* write it to UART */
X    rs_left--;				/* decrement counter */
X    if ( ~MFP->mf_tsr & T_EMPTY)	/* char in process ? */
X      return;				/* yes, return */
X  }
X  if ( rs_left == 0 )
X  {
X    t_err_ok = TRUE;			/* causes an legal error */
X    rs_busy = FALSE;			/* nothing more to do */
X    rs_next = rs_translate;		/* prepare data pointer */
X    if ( tp->tty_outleft > 0 )
X      rs_write( tp );			/* fill the translation buffer again */
X    else if ( tp->tty_waiting == WAITING )	/* tell tty only if neccesary */
X    {
X      tp->tty_waiting = COMPLETED;	/* mark this line as done */
X      output_done++;			/* prepare for fs-msg problems */
X      interrupt( TTY, &rs232_wm );	/* send TTY task a message */
X    }
X  }
X}	/* rs_write_int */
X
X
X/*===========================================================================*
X *				siaint					     *
X *===========================================================================*/
X/* If some data arrives or has been send the MFP generates an interrupt which
X * calls this function. Receiver and transmitter errors also came here.
X */
XPUBLIC void siaint ( which )
Xint which;
X{
X  /*
X   * The next statements should e something like switch() {...}
X   * but ACK produces so slow code for this and so i decide ...
X   */
X  if ( which == RRDY )			/* receiver ready ? */
X  {
X    RxD();
X  }
X  else if ( which == TRDY )		/* transmitter ready ? */
X  {
X    rs_write_int();
X  }
X  else if ( which == RERR )		/* receiver error ? */
X  {
X    rx_err();
X  }
X  else if ( ! t_err_ok )		/* unexpected transmitter error ? */
X  {
X    tx_err();
X  }
X}	/* siaint */
X
X
X/*===========================================================================*
X *				translate				     *
X *===========================================================================*/
X/* Some characters output to RS-232 lines need special processing, such as
X * tab expansion and LF to CR+CF mapping.  These things are done here.
X */
XPRIVATE void translate ( mode, c )
Xint mode;
Xregister char c;
X{
X  register char *cptr;
X
X  cptr = rs_next + rs_left;
X  if ( c == '\b' )		/* ack's switch() is too slow so i decided... */
X    rs_column -= 2;			/* it's incremented below */
X  else if ( c == '\r' )
X    rs_column = -1;			/* it's incremented below */
X  else if ( c == '\n' && ( mode & CRMOD ))
X  {					/* has LF to be mapped to CR + LF ? */
X    *cptr++ = '\r';
X    rs_left++;
X    rs_column = -1;			/* it's incremented below */
X  }
X  else if ( c == '\t' )
X  {
X    if ( mode & XTABS )
X    {
X      c = ' ';				/* Tabs must be expanded */
X      do
X      {
X        *cptr++ = c;
X        rs_left++;
X      }
X      while ((++rs_column & 7 ) != 7 );	/* on Tabs the lower 3 bits are 0 */
X    }
X    else			/* Tabs are send to the terminal hardware */
X    {
X      rs_column &= ~7;		/* force to mod 8 */
X      rs_column += 7;		/* next tab position minus 1 */
X    }
X  }
X  *cptr = c;			/* copy char to translation buffer */
X  rs_left++;			/* one more to output */
X  rs_column++;			/* update column */
X}	/* translate */
X
X
X/*===========================================================================*
X *				rs_write				     *
X *===========================================================================*/
X/* Copy as much data as possible to the output queue, then start I/O if
X * necessary.
X */
XPRIVATE rs_write ( tp )
Xregister struct tty_struct *tp;
X{
X  register char c;
X
X  if ( tp->tty_inhibited == RUNNING )
X  {
X  /* While there is still data to output and there is still room in buf, copy*/
X    while ( tp->tty_outleft > 0 && rs_next + rs_left < rs_ulimit )
X    {
X      tp->tty_outleft--;
X      tp->tty_cum++;			/* update cumulative total */
X      c = *(( char *)tp->tty_phys)++;	/* get one byte */
X      if ( c < ' ' )
X        translate( tp->tty_mode, c );	/* insert in output buffer */
X      else
X      {					/* avoid function call */
X        *( rs_next + rs_left ) = c;	/* direct insertion */
X        rs_left++;
X        rs_column++;
X      }
X    }
X    if ( ! rs_busy )			/* is the terminal idle ? */
X    {
X      rs_busy = TRUE;			/* mark it as busy */
X      rs_write_int();			/* and start it */
X    }
X  }
X}	/* rs_write */
X
X
X/*===========================================================================*
X *				rs_echo					     *
X *===========================================================================*/
X/* Only called if tty mode is echo */
XPRIVATE rs_echo ( tp, c )
Xregister struct tty_struct *tp;
Xchar c;
X{
X  register int s;
X
X/* See if there is room to store a character, and if so, do it. */
X  if ( rs_next + rs_left < &rs_translate[OUT_SIZE] )
X  {
X    s = lock();
X    translate( tp->tty_mode, c );
X    restore( s );
X    if ( ! rs_busy )			/* is the terminal idle ? */
X    {
X      rs_busy = TRUE;			/* mark it as busy */
X      rs_write_int();			/* and start it */
X    }
X  }
X}	/* rs_echo */
X
X
X/*===========================================================================*
X *				start_rs232				     *
X *===========================================================================*/
XPRIVATE int start_rs232 ( tp )
Xstruct tty_struct *tp;
X{
X  t_state = OK;
X  rs_write( tp );
X  return( 0 );
X}	/* start_rs232 */
X
X
X/*===========================================================================*
X *				rs232_sig				     *
X *===========================================================================*/
X/* called at SIGINT, SIGQUIT or SIGKILL. It resets the RS232 output and is
X * only necessary because RS232 uses his own (translation) buffer for output.
X */
XPUBLIC void rs232_sig ()
X{
X  rs_left = 0;
X  rs_busy = FALSE;
X  rs_next = rs_translate;
X}	/* rs232_sig */
X
X
X/*===========================================================================*
X *				set_speed				     *
X *===========================================================================*/
XPRIVATE void set_speed ( in_baud, out_baud, data_bits, parity, stop_bits )
Xint in_baud;	/* input speed: index into baud_table */
Xint out_baud;	/* must be same as input speed here => ignored */
Xint data_bits;	/* 5, 6, 7 or 8 */
Xint parity;	/* EVEN, ODD or NONE */
Xint stop_bits;	/* 1 or 2 */
X{
X  register int s;
X  register int line_ctrl;
X
X
X  line_ctrl = 0;
X  s = lock();
X  rs_left = 0;				/* it makes no sense to output */
X  rs_busy = FALSE;			/* something old after changeing */
X  rs_next = rs_translate;		/* the RS232 parameters, right ? */
X  t_err_ok = TRUE;			/* disabeling transmitter causes it */
X  MFP->mf_rsr &= ( ~R_ENA );		/* disable receiver */
X  MFP->mf_tsr = ( T_TRI & ~T_ENA );	/* disable & quiet output tristate */
X  MFP->mf_tcdcr &= ( 0xf0 | T_STOP );	/* stop timer D only */
X  in_baud <<= 1;			/* each value uses two entries */
X  MFP->mf_tcdcr |= 0x0f & baud_table[in_baud];	/* set new delay */
X  in_baud++;
X  MFP->mf_tddr = baud_table[in_baud];	/* set new count */
X  if ( parity != NONE )
X  {
X    line_ctrl = U_PAR;
X    if ( parity == EVEN )
X      line_ctrl |= U_EVEN;
X  }
X  switch ( stop_bits )
X  {
X    case 2  :
X      line_ctrl |= U_ST2;
X      break;
X    case 1  :
X    default :
X      line_ctrl |= U_ST1;
X      break;
X  }
X  switch ( data_bits )
X  {
X    case 5  :
X      line_ctrl |= U_D5;
X      break;
X    case 6  :
X      line_ctrl |= U_D6;
X      break;
X    case 7  :
X      line_ctrl |= U_D7;
X      break;
X    case 8  :
X    default :
X      line_ctrl |= U_D8;
X      break;
X  }
X  line_ctrl |= U_Q16;
X  MFP->mf_ucr = line_ctrl;
X  MFP->mf_rsr |= R_ENA;			/* enable receiver */
X  MFP->mf_tsr |= T_ENA;			/* enable transmitter */
X  restore( s );
X}	/* set_speed */
X
X
X/*===========================================================================*
X *				set_uart				     *
X *===========================================================================*/
XPUBLIC void set_uart ( mode, speed )
Xint mode;			/* sgtty.h sg_mode word */
Xint speed;			/* low byte is input speed, high is output */
X{
X  /*
X   * prepare the UART parameters
X   * on ATARI ST the input and output speeds are always the same
X   * so we use always the input speed
X   */
X  register int parity, data_bits;
X
X  speed &= 0xff;
X  if ( speed == B0 )		/* B0 means BREAK */
X  {
X    MFP->mf_tsr |= T_BREAK;	/* send BREAK when udr is empty */
X  }
X  else
X  {
X    if ( speed < B50 )
X      speed = B50;
X    else if ( speed > B19200 )
X      speed = B19200;
X    speed--;			/* the index is one to high, correct it */
X    parity = NONE;
X    if ( mode & EVENP )
X      parity = EVEN;
X    else if ( mode & ODDP )
X      parity = ODD;
X    data_bits = 5 + (( mode >> DATA_LEN ) & 0x3 );
X    set_speed( speed, speed, data_bits, parity, 1 );
X  }
X}	/* set_uart */
X
X
X/*===========================================================================*
X *				rs232init				     *
X *===========================================================================*/
XPUBLIC void rs232init()
X{
X  register int index;
X
X  output_done = 0;			/* line is idle */
X  tp = &tty_struct[RS232];		/* set the Rs232 tty_struct pointer */
X  tp->tty_start = start_rs232;
X  tp->tty_echo = rs_echo;
X/*  tp->tty_mode |= BITS8;		/* CRMOD | XTABS | ECHO | BITS8 */
X  tp->tty_mode = RAW | BITS8;
X  tp->tty_speed = ( DEF_BAUD << 8 ) | DEF_BAUD;
X  for ( index = 3; index < IN_SIZE; index += 2 )
X    rsbuf[index] = RS232;		/* prefill the originating line no */
X  rsbuf[0] = 0;				/* buffer is empty */
X  rsbuf[1] = TRESHOLD + OFLOW;		/* max filling size */
X  rs_ulimit = &rs_translate[OUT_SIZE-SPARE];	/* set upper filling limit */
X  rs_column = 0;			/* first column */
X  rs232_rm.m_type = TTY_CHAR_INT;	/* receiver message is always */
X  rs232_rm.ADDRESS = rsbuf;		/* the same, so set it up here */
X  rs232_wm.m_type = TTY_O_DONE;		/* sender message is always */
X  rs232_wm.TTY_LINE = RS232;		/* same, (which line is finished) */
X/*  MFP->mf_scr = SYN;			/* just for fun : sync char */
X/*  MFP->mf_rsr = R_STRIP;		/* strip enable */
X  set_uart( tp->tty_mode, tp->tty_speed );
X}	/* rs232init */
X
X
X/* The iob() interrupt handler values */
X#define DCD	1		/* serial Data Carrier Detected */
X#define CTS	2		/* serial Clear To Send */
X#define RI	6		/* serial Ring Indicator */
X#define GPUDONE	3		/* Grafic Process Unit DONE ( blitter ) */
X#define MONO	7		/* MONOchrome monitor detect */
X
X/*===========================================================================*
X *				iob					     *
X *===========================================================================*/
XPUBLIC void iob ( which )
Xint which;
X{
X  register char *cptr;
X
X  /* ack's switch is too slow so i decided ... */
X  if ( which == RI )			/* ring indicator ? */
X  {
X    cptr = RI;
X  }
X  else if ( which == CTS )		/* clear to send ? */
X  {
X    cptr = CTS;
X  }
X  else if ( which == DCD )		/* data carrier detected ? */
X  {
X    cptr = DCD;
X  }
X  else if ( which == MONO )		/* monitor changed ? */
X  {
X    cptr = MONO;
X  }
X  else					/* must be GPU */
X    cptr = GPU;
X}	/* iob */
X
X#endif ATARI_ST
/
echo x - sgtty.h
sed 's/^X//' > sgtty.h << '/'
X/* Data structures for IOCTL. */
X
Xstruct sgttyb {
X  char sg_ispeed;		/* input speed */
X  char sg_ospeed;		/* output speed */
X  char sg_erase;		/* erase character */
X  char sg_kill;			/* kill character */
X  int  sg_flags;		/* mode flags */
X};
X
Xstruct tchars {
X  char t_intrc;			/* SIGINT char */
X  char t_quitc;			/* SIGQUIT char */
X  char t_startc;		/* start output (initially CTRL-Q) */
X  char t_stopc;			/* stop output	(initially CTRL-S) */
X  char t_eofc;			/* EOF (initially CTRL-D) */
X  char t_brkc;			/* input delimiter (like nl) */
X};
X
X/* Field names */
X#define XTABS	     0006000	/* do tab expansion */
X#define BITS8        0001400	/* 8 bits/char */
X#define BITS7        0001000	/* 7 bits/char */
X#define BITS6        0000400	/* 6 bits/char */
X#define BITS5        0000000	/* 5 bits/char */
X#define EVENP        0000200	/* even parity */
X#define ODDP         0000100	/* odd  parity */
X#define RAW	     0000040	/* enable raw mode */
X#define CRMOD	     0000020	/* map lf to cr + lf */
X#define ECHO	     0000010	/* echo input */
X#define CBREAK	     0000002	/* enable cbreak mode */
X#define COOKED       0000000	/* neither CBREAK nor RAW */
X
X/* Line speeds */
X#define B0	0xff		/* sends BREAK */
X#define B50	0x01
X#define B75	0x02
X#define B110	0x03
X#define B134	0x04
X#define B150	0x05
X#define B200	0x06
X#define B300	0x07
X#define B600	0x08
X#define B1200	0x09
X#define B1800	0x0a
X#define B2000	0x0b
X#define B2400	0x0c
X#define B3600	0x0d
X#define B4800	0x0e
X#define B9600	0x0f
X#define B19200	0x10
X#define EXTA	B19200
X#define EXTB	0x00
X
X#define TIOCGETP (('t'<<8) | 8)
X#define TIOCSETP (('t'<<8) | 9)
X#define TIOCGETC (('t'<<8) | 18)
X#define TIOCSETC (('t'<<8) | 17)
/
echo x - Makefile.cdif
sed 's/^X//' > Makefile.cdif << '/'
X*** /usr/src/sys/kernel/Makefile	Fri Sep 29 13:09:53 1989
X--- Makefile	Wed Sep 20 23:10:24 1989
X***************
X*** 8,14 ****
X  OBJ	= stmpx.o stmain.o proc.o system.o stshadow.o \
X  	  tty.o clock.o memory.o stdma.o stfloppy.o stwini.o \
X  	  stcon.o stkbd.o stvdu.o stfnt.o stprint.o \
X! 	  table.o stdmp.o
X  HDR	= ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \
X  	  ../h/sgtty.h ../h/signal.h ../h/type.h \
X  	  const.h glo.h proc.h tty.h type.h \
X--- 8,14 ----
X  OBJ	= stmpx.o stmain.o proc.o system.o stshadow.o \
X  	  tty.o clock.o memory.o stdma.o stfloppy.o stwini.o \
X  	  stcon.o stkbd.o stvdu.o stfnt.o stprint.o \
X! 	  table.o stdmp.o strs232.o
X  HDR	= ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \
X  	  ../h/sgtty.h ../h/signal.h ../h/type.h \
X  	  const.h glo.h proc.h tty.h type.h \
/
echo x - clock.c.cdif
sed 's/^X//' > clock.c.cdif << '/'
X*** /usr/src/sys/kernel/clock.c	Fri Sep 29 13:09:54 1989
X--- clock.c	Sun May 28 23:01:32 1989
X***************
X*** 199,204 ****
X--- 199,206 ----
X  
X  #ifdef ATARI_ST
X    kb_timer();			/* keyboard repeat */
X+   if ((( int )realtime & 3 ) == 0 )		/* call only every 4th tick */
X+     rs_flush();					/* flush RS232 buffer */
X  #endif ATARI_ST
X  
X    /* If a user process has been running too long, pick another one. */
/
echo x - stmain.c.cdif
sed 's/^X//' > stmain.c.cdif << '/'
X*** /usr/src/sys/kernel/stmain.c	Fri Sep 29 13:10:06 1989
X--- stmain.c	Fri Sep 22 22:16:30 1989
X***************
X*** 226,233 ****
X    /*
X     * initialize MFP
X     */
X!   MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY);
X!   MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY);
X    /*
X     * interrupts to vectors 0x40 to 0x4F
X     * automatic end-of-interrupt mode
X--- 226,235 ----
X    /*
X     * initialize MFP
X     */
X!   MFP->mf_iera |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
X!   MFP->mf_imra |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
X!   MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY);
X!   MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY);
X    /*
X     * interrupts to vectors 0x40 to 0x4F
X     * automatic end-of-interrupt mode
X***************
X*** 259,267 ****
X   *				temporary stuff				     *
X   *===========================================================================*/
X  timint(t)	{fake_int(TIMINT, t);}
X! siaint(t)	{fake_int(SIAINT, t);}
X! mdiint(t)	{fake_int(MDIINT, t);}
X! iob(t)		{fake_int(IOB, t);}
X  
X  fake_int(s, t) char *s; {
X--- 261,267 ----
X   *				temporary stuff				     *
X   *===========================================================================*/
X  timint(t)	{fake_int(TIMINT, t);}
X! mdiint(t)	{fake_int(MDIINT, t);}
X  
X  fake_int(s, t) char *s; {
/
echo x - tty.c.cdif
sed 's/^X//' > tty.c.cdif << '/'
X*** /usr/src/sys/kernel/tty.c	Fri Sep 29 13:10:18 1989
X--- tty.c	Sat Sep 23 01:45:19 1989
X***************
X*** 47,52 ****
X--- 47,53 ----
X  
X+ EXTERN int output_done;
X  PUBLIC struct tty_struct tty_struct[NR_TTYS];
X  
X  /*===========================================================================*
X***************
X*** 64,76 ****
X  	receive(ANY, &tty_mess);
X  	tp = &tty_struct[tty_mess.TTY_LINE];
X  	switch(tty_mess.m_type) {
X! 	    case TTY_CHAR_INT:	do_charint(&tty_mess);		break;
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- 	    case TTY_O_DONE:	/* reserved for future use (RS-232 terminals)*/
X  	    default:		tty_reply(TASK_REPLY, tty_mess.m_source, 
X  					tty_mess.PROC_NR, EINVAL, 0L, 0L);
X  	}
X--- 65,129 ----
X  	receive(ANY, &tty_mess);
X  	tp = &tty_struct[tty_mess.TTY_LINE];
X  	switch(tty_mess.m_type) {
X! 	    case TTY_O_DONE:
X! 	    case TTY_CHAR_INT:
X! 		/* The TTY task can generate two kinds of interrupts:
X! 		 *	- a character has been typed on the console or an
X! 		 *		RS232 line
X! 		 *	- an RS232 line has completed a write request (on
X! 		 *		behalf of a user)
X! 		 * If either interrupt happens and the TTY task is idle,
X! 		 * the task gets the interrupt message immediately and
X! 		 * processes it. However, if the TTY task is busy, a bit
X! 		 * is set in 'busy_map' and the message pointer stored.
X! 		 * If multiple messages happen, the bit is only set once.
X! 		 * No input data is lost even if this happens because all
X! 		 * the input messages say is that there is some input.
X! 		 * The actual input is in the tty_driver_buf array, so
X! 		 * losing a message just means that when the one interrupt-
X! 		 * generated message is given to the TTY task, it will find
X! 		 * multiple characters in tty_driver_buf.
X! 		 *
X! 		 * The introduction of RS232 lines has complicated this
X! 		 * situation somewhat. Now a message can mean that some
X! 		 * RS232 line has finished transmitting all the output
X! 		 * given to it. If a character is typed at the instant
X! 		 * an RS232 line finishes, one of the two messages may be
X! 		 * overwritten because MINIX only provides single buffering
X! 		 * for interrupt messages (in proc.c). To avoid losing
X! 		 * information, whenever an RS232 line finishes, the flag
X! 		 * tty_waiting is set to COMPLETED and kept that way until
X! 		 * its completion is processed and a message sent to FS
X! 		 * saying that output is done. The number of RS232 lines in
X! 		 * COMPLETED state is kept in output_done, which is checked
X! 		 * on each interrupt, so that a lost TTY_O_DONE line
X! 		 * completion interrupt will be quickly recovered.
X! 		 *
X! 		 * In short, when this procedure is called, it can check
X! 		 * for RS232 line done  by inspecting output_done and it
X! 		 * can check for characters in the input buffer by
X! 		 * inspecting tty_driver_buf[0]. Thus losing a message to
X! 		 * the TTY task is not serious because the underlying
X! 		 * conditions are explicitly checked for on each interrupt.
X! 		 */
X! 
X! 		/* First check to see if the RS232 line has completed. */
X! 				if ( output_done > 0 )
X! 					/* If a message is sent to FS for
X! 					 * RS232 done, don't process any
X! 					 * input characters now for fear
X! 					 * of sending a second message to
X! 					 * FS, which would be lost.
X! 					 */
X! 					do_o_done(tp);
X! 				else
X! 					do_charint( &tty_mess );
X! 				break;
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_reply(TASK_REPLY, tty_mess.m_source, 
X  					tty_mess.PROC_NR, EINVAL, 0L, 0L);
X  	}
X***************
X*** 100,106 ****
X    copy_ptr = tty_copy_buf;	/* ptr to shadow array where chars copied */
X    n = *ptr;			/* how many chars have been accumulated */
X    count = n;			/* save the character count */
X!   n = n + n;			/* each char occupies 2 bytes */
X    ptr += 2;			/* skip count field at start of array */
X    while (n-- > 0)
X  	*copy_ptr++ = *ptr++;	/* copy the array to safety */
X--- 153,159 ----
X    copy_ptr = tty_copy_buf;	/* ptr to shadow array where chars copied */
X    n = *ptr;			/* how many chars have been accumulated */
X    count = n;			/* save the character count */
X!   n <<= 1;			/* each char occupies 2 bytes */
X    ptr += 2;			/* skip count field at start of array */
X    while (n-- > 0)
X  	*copy_ptr++ = *ptr++;	/* copy the array to safety */
X***************
X*** 292,298 ****
X    int code, caller;
X  
X    if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
X! 	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L);
X  	return;
X    }
X  
X--- 345,351 ----
X    int code, caller;
X  
X    if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
X! 	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
X  	return;
X    }
X  
X***************
X*** 390,405 ****
X  {
X  /* A command has terminated (possibly due to DEL).  Tell caller. */
X  
X!   int replyee, caller;
X  
X    tp->tty_outleft = 0;
X  #ifdef ATARI_ST
X    (proc_addr(tp->tty_outproc))->p_physio = 0;	/* enable (un)shadowing */
X  #endif
X    if (tp->tty_waiting == NOT_WAITING) return;
X!   replyee = (int) tp->tty_otcaller;
X!   caller = (int) tp->tty_outproc;
X!   tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L);
X    tp->tty_waiting = NOT_WAITING;
X  }
X  
X--- 443,459 ----
X  {
X  /* A command has terminated (possibly due to DEL).  Tell caller. */
X  
X!   int result, replyee, caller;
X  
X    tp->tty_outleft = 0;
X  #ifdef ATARI_ST
X    (proc_addr(tp->tty_outproc))->p_physio = 0;	/* enable (un)shadowing */
X  #endif
X    if (tp->tty_waiting == NOT_WAITING) return;
X!   result = ( tp == &tty_struct[RS232] ? REVIVE : TASK_REPLY );
X!   replyee = (int) tp->tty_otcaller;
X!   caller = (int) tp->tty_outproc;
X!   tty_reply(result, replyee, caller, code, 0L, 0L);
X    tp->tty_waiting = NOT_WAITING;
X  }
X  
X***************
X*** 416,421 ****
X--- 470,482 ----
X    vir_bytes out_vir, out_left;
X    struct proc *rp;
X    extern phys_bytes umap();
X+   int caller, replyee;
X+ 
X+   /* If the slot is already in use, better return an error than mess it up. */
X+ /*  if (tp->tty_outleft > 0) {	/* if someone else is hanging, give up */
X+ /*	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
X+ 	return;
X+   }*/
X  
X    /* Copy message parameters to the tty structure. */
X    tp->tty_otcaller = m_ptr->m_source;
X***************
X*** 441,446 ****
X--- 502,517 ----
X    /* Copy characters from the user process to the terminal. */
X    if ((*tp->tty_start)(tp))	/* copy data to queue and start I/O */
X  	finish(tp, tp->tty_cum);
X+ 
X+   /* If output is for a bitmapped terminal as the ATARI ST console, the output-
X+    * routine will return at once so there is no need to suspend the caller,
X+    * on ascii terminals however, the call is suspended and later revived.
X+    */
X+   if (m_ptr->TTY_LINE == RS232) {
X+ 	caller = (int) tp->tty_outproc;
X+ 	replyee = (int) tp->tty_otcaller;
X+ 	tty_reply(TASK_REPLY, replyee, caller, SUSPEND, 0L, 0L);
X+   }
X  }
X  
X  
X***************
X*** 465,470 ****
X--- 536,548 ----
X  	tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE);	/* erase  */
X  	tp->tty_kill  = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE);	/* kill  */
X  	tp->tty_mode  = (int) m_ptr->TTY_FLAGS;	/* mode word */
X+ 	if ( m_ptr->TTY_LINE == RS232 )
X+ 	{	/* set the new speed only if it's legal, store it temp here */
X+ 		int new_speed;
X+ 		new_speed = ( int )( m_ptr->TTY_FLAGS >>  16 );
X+ 		if ( new_speed ) tp->tty_speed = new_speed;
X+ 		set_uart( tp->tty_mode, tp->tty_speed );
X+ 	}
X  	break;
X  
X       case TIOCSETC:
X***************
X*** 481,487 ****
X  	erase = ((long) tp->tty_erase) & BYTE;
X  	kill  = ((long) tp->tty_kill) & BYTE;
X  	erki  = (erase << 8) | kill;
X! 	flags = (long) tp->tty_mode;
X  	break;
X  
X       case TIOCGETC:
X--- 559,565 ----
X  	erase = ((long) tp->tty_erase) & BYTE;
X  	kill  = ((long) tp->tty_kill) & BYTE;
X  	erki  = (erase << 8) | kill;
X! 	flags = ((long) tp->tty_speed << 16 ) | (long) tp->tty_mode;
X  	break;
X  
X       case TIOCGETC:
X***************
X*** 585,590 ****
X--- 663,669 ----
X    tp->tty_intail = tp->tty_inqueue;
X    tp->tty_incount = 0;
X    tp->tty_lfct = 0;
X+   if ( tp == &tty_struct[RS232] ) rs232_sig();	/* only RS232 */
X    if (tp->tty_pgrp)
X  	cause_sig(tp->tty_pgrp, sig);
X  }
X***************
X*** 616,623 ****
X--- 695,721 ----
X  	case CONSOLE:
X  		coninit();
X  		break;
X+ 	case RS232:
X+ 		rs232init();
X+ 		break;
X  	default:
X  	}
X    }
X  }
X+ 
X+ 
X+ /*===========================================================================*
X+  *				do_o_done				     *
X+  *===========================================================================*/
X+ PRIVATE do_o_done( tp )
X+ register struct tty_struct *tp;	/* pointer to tty struct */
X+ {
X+ /* A write request on the RS232 line has completed. Send FS a message. */
X+ 
X+   if ( tp->tty_waiting == COMPLETED )
X+   {
X+     finish( tp, tp->tty_cum );
X+     output_done--;
X+   }
X+ }
/
echo x - tty.h.cdif
sed 's/^X//' > tty.h.cdif << '/'
X*** /usr/src/sys/kernel/tty.h	Fri Sep 29 13:10:20 1989
X--- tty.h	Tue May 30 23:19:21 1989
X***************
X*** 1,11 ****
X! #define NR_TTYS            1	/* how many terminals can system handle */
X! #define CONSOLE            0	/* line number for console */
X  #define OPERATOR        (-1)	/* handle CTRL-ALT-PFX sequences */
X  
X  #define TTY_IN_BYTES     200	/* input queue size */
X  #define TAB_SIZE           8	/* distance between tabs */
X  #define TAB_MASK          07	/* mask for tty_column when tabbing */
X! #define MAX_OVERRUN       16	/* size of overrun input buffer */
X  
X  #define ERASE_CHAR      '\b'	/* default erase character */
X  #define KILL_CHAR        '@'	/* default kill character */
X--- 1,12 ----
X! #define NR_TTYS            2	/* how many terminals can system handle */
X! #define CONSOLE            0	/* line number for console */
X! #define RS232		   1	/* line number for serial-io */
X  #define OPERATOR        (-1)	/* handle CTRL-ALT-PFX sequences */
X  
X  #define TTY_IN_BYTES     200	/* input queue size */
X  #define TAB_SIZE           8	/* distance between tabs */
X  #define TAB_MASK          07	/* mask for tty_column when tabbing */
X! #define MAX_OVERRUN      126	/* size of overrun input buffer */
X  
X  #define ERASE_CHAR      '\b'	/* default erase character */
X  #define KILL_CHAR        '@'	/* default kill character */
X***************
X*** 30,35 ****
X--- 31,37 ----
X  
X    /* Terminal parameters and status. */
X    int tty_mode;			/* terminal mode set by IOCTL */
X+   int tty_speed;		/* low_byte is ispeed; high byte is ospeed */
X    char tty_escaped;		/* 1 when '\' just seen, else 0 */
X    char tty_inhibited;		/* 1 when CTRL-S just seen (stops output) */
X    char tty_waiting;		/* 1 when output process waiting for reply */
X***************
X*** 64,68 ****
X  #define STOPPED            1	/* CTRL-S has been typed to stop the tty */
X  #define NOT_WAITING        0	/* no output process is hanging */
X  #define WAITING            1	/* an output process is waiting for a reply */
X! 
X! EXTERN struct tty_struct tty_struct[];
X--- 66,71 ----
X  #define STOPPED            1	/* CTRL-S has been typed to stop the tty */
X  #define NOT_WAITING        0	/* no output process is hanging */
X  #define WAITING            1	/* an output process is waiting for a reply */
X! #define COMPLETED	   2	/* output done; send completion message */
X! 
X! EXTERN struct tty_struct tty_struct[];
/
echo x - diffs.shar
sed 's/^X//' > diffs.shar << '/'
Xecho x - Makefile.diff
Xsed 's/^X//' > Makefile.diff << '/'
XX11c11
XX< 	  table.o stdmp.o
XX---
XX> 	  table.o stdmp.o strs232.o
X/
Xecho x - clock.c.diff
Xsed 's/^X//' > clock.c.diff << '/'
XX201a202,203
XX>   if ((( int )realtime & 3 ) == 0 )		/* call only every 4th tick */
XX>     rs_flush();					/* flush RS232 buffer */
X/
Xecho x - stmain.c.diff
Xsed 's/^X//' > stmain.c.diff << '/'
XX229,230c229,232
XX<   MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY);
XX<   MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY);
XX---
XX>   MFP->mf_iera |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
XX>   MFP->mf_imra |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
XX>   MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY);
XX>   MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY);
XX262,264c264
XX< siaint(t)	{fake_int(SIAINT, t);}
XX< mdiint(t)	{fake_int(MDIINT, t);}
XX< iob(t)		{fake_int(IOB, t);}
XX---
XX> mdiint(t)	{fake_int(MDIINT, t);}
X/
Xecho x - tty.c.diff
Xsed 's/^X//' > tty.c.diff << '/'
XX49a50
XX> EXTERN int output_done;
XX67c68,121
XX< 	    case TTY_CHAR_INT:	do_charint(&tty_mess);		break;
XX---
XX> 	    case TTY_O_DONE:
XX> 	    case TTY_CHAR_INT:
XX> 		/* The TTY task can generate two kinds of interrupts:
XX> 		 *	- a character has been typed on the console or an
XX> 		 *		RS232 line
XX> 		 *	- an RS232 line has completed a write request (on
XX> 		 *		behalf of a user)
XX> 		 * If either interrupt happens and the TTY task is idle,
XX> 		 * the task gets the interrupt message immediately and
XX> 		 * processes it. However, if the TTY task is busy, a bit
XX> 		 * is set in 'busy_map' and the message pointer stored.
XX> 		 * If multiple messages happen, the bit is only set once.
XX> 		 * No input data is lost even if this happens because all
XX> 		 * the input messages say is that there is some input.
XX> 		 * The actual input is in the tty_driver_buf array, so
XX> 		 * losing a message just means that when the one interrupt-
XX> 		 * generated message is given to the TTY task, it will find
XX> 		 * multiple characters in tty_driver_buf.
XX> 		 *
XX> 		 * The introduction of RS232 lines has complicated this
XX> 		 * situation somewhat. Now a message can mean that some
XX> 		 * RS232 line has finished transmitting all the output
XX> 		 * given to it. If a character is typed at the instant
XX> 		 * an RS232 line finishes, one of the two messages may be
XX> 		 * overwritten because MINIX only provides single buffering
XX> 		 * for interrupt messages (in proc.c). To avoid losing
XX> 		 * information, whenever an RS232 line finishes, the flag
XX> 		 * tty_waiting is set to COMPLETED and kept that way until
XX> 		 * its completion is processed and a message sent to FS
XX> 		 * saying that output is done. The number of RS232 lines in
XX> 		 * COMPLETED state is kept in output_done, which is checked
XX> 		 * on each interrupt, so that a lost TTY_O_DONE line
XX> 		 * completion interrupt will be quickly recovered.
XX> 		 *
XX> 		 * In short, when this procedure is called, it can check
XX> 		 * for RS232 line done  by inspecting output_done and it
XX> 		 * can check for characters in the input buffer by
XX> 		 * inspecting tty_driver_buf[0]. Thus losing a message to
XX> 		 * the TTY task is not serious because the underlying
XX> 		 * conditions are explicitly checked for on each interrupt.
XX> 		 */
XX> 
XX> 		/* First check to see if the RS232 line has completed. */
XX> 				if ( output_done > 0 )
XX> 					/* If a message is sent to FS for
XX> 					 * RS232 done, don't process any
XX> 					 * input characters now for fear
XX> 					 * of sending a second message to
XX> 					 * FS, which would be lost.
XX> 					 */
XX> 					do_o_done(tp);
XX> 				else
XX> 					do_charint( &tty_mess );
XX> 				break;
XX73d126
XX< 	    case TTY_O_DONE:	/* reserved for future use (RS-232 terminals)*/
XX103c156
XX<   n = n + n;			/* each char occupies 2 bytes */
XX---
XX>   n <<= 1;			/* each char occupies 2 bytes */
XX295c348
XX< 	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L);
XX---
XX> 	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
XX393c446
XX<   int replyee, caller;
XX---
XX>   int result, replyee, caller;
XX400,402c453,456
XX<   replyee = (int) tp->tty_otcaller;
XX<   caller = (int) tp->tty_outproc;
XX<   tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L);
XX---
XX>   result = ( tp == &tty_struct[RS232] ? REVIVE : TASK_REPLY );
XX>   replyee = (int) tp->tty_otcaller;
XX>   caller = (int) tp->tty_outproc;
XX>   tty_reply(result, replyee, caller, code, 0L, 0L);
XX418a473,479
XX>   int caller, replyee;
XX> 
XX>   /* If the slot is already in use, better return an error than mess it up. */
XX> /*  if (tp->tty_outleft > 0) {	/* if someone else is hanging, give up */
XX> /*	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
XX> 	return;
XX>   }*/
XX443a505,514
XX> 
XX>   /* If output is for a bitmapped terminal as the ATARI ST console, the output-
XX>    * routine will return at once so there is no need to suspend the caller,
XX>    * on ascii terminals however, the call is suspended and later revived.
XX>    */
XX>   if (m_ptr->TTY_LINE == RS232) {
XX> 	caller = (int) tp->tty_outproc;
XX> 	replyee = (int) tp->tty_otcaller;
XX> 	tty_reply(TASK_REPLY, replyee, caller, SUSPEND, 0L, 0L);
XX>   }
XX467a539,545
XX> 	if ( m_ptr->TTY_LINE == RS232 )
XX> 	{	/* set the new speed only if it's legal, store it temp here */
XX> 		int new_speed;
XX> 		new_speed = ( int )( m_ptr->TTY_FLAGS >>  16 );
XX> 		if ( new_speed ) tp->tty_speed = new_speed;
XX> 		set_uart( tp->tty_mode, tp->tty_speed );
XX> 	}
XX484c562
XX< 	flags = (long) tp->tty_mode;
XX---
XX> 	flags = ((long) tp->tty_speed << 16 ) | (long) tp->tty_mode;
XX587a666
XX>   if ( tp == &tty_struct[RS232] ) rs232_sig();	/* only RS232 */
XX618a698,700
XX> 	case RS232:
XX> 		rs232init();
XX> 		break;
XX623a706,721
XX> 
XX> 
XX> /*===========================================================================*
XX>  *				do_o_done				     *
XX>  *===========================================================================*/
XX> PRIVATE do_o_done( tp )
XX> register struct tty_struct *tp;	/* pointer to tty struct */
XX> {
XX> /* A write request on the RS232 line has completed. Send FS a message. */
XX> 
XX>   if ( tp->tty_waiting == COMPLETED )
XX>   {
XX>     finish( tp, tp->tty_cum );
XX>     output_done--;
XX>   }
XX> }
X/
Xecho x - tty.h.diff
Xsed 's/^X//' > tty.h.diff << '/'
XX1,2c1,3
XX< #define NR_TTYS            1	/* how many terminals can system handle */
XX< #define CONSOLE            0	/* line number for console */
XX---
XX> #define NR_TTYS            2	/* how many terminals can system handle */
XX> #define CONSOLE            0	/* line number for console */
XX> #define RS232		   1	/* line number for serial-io */
XX8c9
XX< #define MAX_OVERRUN       16	/* size of overrun input buffer */
XX---
XX> #define MAX_OVERRUN      126	/* size of overrun input buffer */
XX32a34
XX>   int tty_speed;		/* low_byte is ispeed; high byte is ospeed */
XX67,68c69,71
XX< 
XX< EXTERN struct tty_struct tty_struct[];
XX---
XX> #define COMPLETED	   2	/* output done; send completion message */
XX> 
XX> EXTERN struct tty_struct tty_struct[];
X/
/
exit 0