[comp.os.minix] minix/ST add rs232

hcj@lzaz.ATT.COM (HC Johnson) (01/04/89)

This is rs232.shar, the new rs232 files for adding rs232 and midi to
minix-st.
==============================================================
echo extracting 'README'
sed -e 's/^X//' >README <<'SHAR_EOF'
X
XNew files for rs232:
X
Xkernel/rstty.c
Xkernel/rs232.c
Xkernel/rs232s.s
Xkernel/ring.h
X
XChanged files for rs232
X
Xkernel/Makefile
Xkernel/stacia.h
Xkernel/stcon.c
Xkernel/stdmp.c
Xkernel/stmain.c
Xkernel/stvdu.c
Xkernel/table.c
Xkernel/tty.h
Xfs/table.c
Xh/com.h
Xh/const.h
Xh/sgtty.h
X
XNew files for Midi:
X
Xkernel/miditty.c
Xkernel/midi.c
Xkernel/midis.s
X
SHAR_EOF
echo extracting 'rstty.c'
sed -e 's/^X//' >rstty.c <<'SHAR_EOF'
X/*
X * This file contains the device-independent part of the terminal driver.
X * The device-independent part accepts characters to be printed from
X * programs and queues them in a standard way for device-dependent output.
X * It also accepts input and queues it for programs.
X * This file contains one entry point: rs232_task().
X * It accepts not only messages about typed input, but
X * also requests to read and write from terminals, etc. 
X *
X * The valid messages and their parameters are:
X *
X *   RS232_CHAR_INT: a character has been typed on a terminal (input interrupt)
X *   RS232_O_DONE:   a character has been output (output completed interrupt)
X *   RS232_READ:     a process wants to read from a terminal
X *   RS232_WRITE:    a process wants to write on a terminal
X *   RS232_IOCTL:    a process wants to change a terminal's parameters
X *   RS232_SETPGRP:  indicate a change in a control terminal
X *   CANCEL:       terminate a previous incomplete system call immediately
X *
X *    m_type      RS232_LINE   PROC_NR    COUNT   RS232_SPEK  RS232_FLAGS  ADDRESS
X * ---------------------------------------------------------------------------
X * | RS232_CHAR_INT|         |         |         |         |         |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | RS232_O_DONE  |minor dev|         |         |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | RS232_READ    |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | RS232_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | RS232_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | RS232_SETPGRP |minor dev| proc nr |         |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | CANCEL      |minor dev| proc nr |         |         |         |         |
X * ---------------------------------------------------------------------------
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/sgtty.h"
X#include "../h/signal.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X#include "tty.h"
X#include "ring.h"
X
X/* IN_CANON will be dis-asserted when set, noop if == 0 */
X
XPRIVATE int Rs_blocked = 0;
XPUBLIC struct tty_struct rstty_struct[1];
X
X#define DBG(x) printf(x);
X
X
X/*===========================================================================*
X *				rs232_task				     *
X *===========================================================================*/
XPUBLIC rs232_task()
X{
X/* Main routine of the terminal task. */
X
X  message rstty_mess;		/* buffer for all incoming messages */
X  register struct tty_struct *tp;
X
X  rstty_init();			/* initialize */
X  while (TRUE) {
X	receive(ANY, &rstty_mess);
X/* we would rather be general here, but not enough info is avail USE 0 */
X	tp = &rstty_struct[0];
X	if(tp->tty_incount == 0 && Rs_blocked) {
X	    do_charint(&rstty_mess);
X	    if(rstty_mess.m_type == RS232_CHAR_INT) /* might be fake */
X		continue;
X	}
X#ifdef CANT_BE
X	tp = &rstty_struct[rstty_mess.TTY_LINE];
X#endif
X	if(rstty_mess.m_type != RS232_CHAR_INT && rstty_mess.TTY_LINE != 0) {
X		printf("\r\nInvalid rs232 minor:type=%d LINE=%d PROCNR=%d ADDRESS=%lx COUNT=%d\n\r",
X		  rstty_mess.m_type,
X		  rstty_mess.TTY_LINE,
X		  rstty_mess.PROC_NR,
X		  rstty_mess.ADDRESS,
X		  rstty_mess.COUNT,
X		  rstty_mess.m_source);
X		continue; /* ignore or do something ?? */
X	}
X
X	switch(rstty_mess.m_type) {
X	    case RS232_CHAR_INT:	do_charint(&rstty_mess);		break;
X	    case RS232_READ:	do_read(tp, &rstty_mess);		break;
X	    case RS232_WRITE:	do_write(tp, &rstty_mess);	break;
X	    case RS232_IOCTL:	do_ioctl(tp, &rstty_mess);	break;
X	    case RS232_SETPGRP:   do_setpgrp(tp, &rstty_mess);	break;
X	    case RS232_OPEN:      do_open(tp, &rstty_mess);	break;
X	    case RS232_CLOSE:     do_close(tp, &rstty_mess);	break;
X	    case CANCEL   :	do_cancel(tp, &rstty_mess);	break;
X	    case RS232_O_DONE:	break; /* reserved for future use (RS-232 terminals)*/
X	    default:		tty_reply(TASK_REPLY, rstty_mess.m_source, 
X					rstty_mess.PROC_NR, EINVAL, 0L, 0L);
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				do_close					     *
X *===========================================================================*/
XPRIVATE do_close(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* message containing pointer to char(s) */
X{
X	int minor;
X	minor = m_ptr->DEVICE;
X	(*tp->tty_close)(tp);
X	tty_reply(TASK_REPLY, m_ptr->m_source, 
X		m_ptr->PROC_NR, OK, 0L, 0L);
X}
X
X/*===========================================================================*
X *				do_open					     *
X *===========================================================================*/
XPRIVATE do_open(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* message containing pointer to char(s) */
X{
X	int minor;
X	return; /* we do not know how to handle this and set pgrp also */
X}
X
X/*===========================================================================*
X *				do_odone				     *
X *===========================================================================*/
XPUBLIC int Rs232_wempty = 0;
XPRIVATE do_odone(tp)
Xstruct tty_struct *tp;
X{
X	unsigned char *ptr;
X
X	Rs232_wempty = 0;
X/* there may be more to send */
X  if ((*tp->tty_start)(tp))	/* copy data to queue and start I/O */
X	finish(tp, tp->tty_cum);
X}
X
X/*===========================================================================*
X *				do_charint				     *
X *===========================================================================*/
Xstatic cnt_max = 0;
XPRIVATE do_charint(m_ptr)
Xmessage *m_ptr;			/* message containing pointer to char(s) */
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 tty driver.  Thus multiple chars may be accumulated.  A single message
X * to the tty task may have to process several characters.
X */
X
X  int m, n, count, replyee, caller, s;
X  char   ch;
X  struct tty_struct *tp;
X  struct ring *ptr;
X
X  if(Rs232_wempty)
X	  do_odone(rstty_struct);
X  Rs_blocked = 0;
X  for( ;; ) {
X
X	tp = &rstty_struct[0];	/* pointer to struct for this character */
X	if (tp->tty_incount >= TTY_IN_BYTES-4) {
X		Rs_blocked |= 1;
X		break;
X	}
X	
X	m = rs232get();
X 	if((m & 0x100))
X		break;
X	ch = m ;
X	n = COM0;	/* get the line number it came in on */
X
X	m= in_char(n, ch&0377);	/* queue the char and echo it */
X
X	/* See if a previously blocked reader can now be satisfied. */
X	if (tp->tty_inleft > 0 ) {	/* does anybody want input? */
X		m = tp->tty_mode & (CBREAK | RAW);
X		if (tp->tty_lfct > 0 ||
X		    (m != 0 && tp->tty_incount > 0) ||
X		    (((tp->tty_mode & IN_CANON) ) &&
X			 tp->tty_incount >= tp->tty_eof)
X		    ) {
X
X
X			m = rd_chars(tp);
X
X			/* Tell hanging reader that chars have arrived. */
X			replyee = (int) tp->tty_incaller;
X			caller = (int) tp->tty_inproc;
X			tty_reply(REVIVE, replyee, caller, m, 0L, 0L);
X		}
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				in_char					     *
X *===========================================================================*/
XPRIVATE in_char(line, ch)
Xint line;			/* line number on which char arrived */
Xint ch;				/* code for character that arrived */
X{
X/* A character has just been typed in.  Process, save, and echo it. */
X
X  register struct tty_struct *tp;
X  int mode;
X
X  tp = &rstty_struct[line];	/* set 'tp' to point to proper struct */
X  if (tp->tty_incount >= TTY_IN_BYTES) {
X	return(0);	/* no room, discard char */
X}
X  mode = tp->tty_mode & (RAW | CBREAK);
X  if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
X
Xif((tp->tty_mode & IN_CANON) == 0) { /* bit set means not CANON */
X  /* Processing for COOKED and CBREAK mode contains special checks. */
X  if (mode == COOKED || mode == CBREAK) {
X	/* Handle erase, kill and escape processing. */
X	if (mode == COOKED) {
X		/* First erase processing (rub out of last character). */
X		if (ch == tp->tty_erase && tp->tty_escaped == NOT_ESCAPED) {
X			if (chuck(tp) != -1) {	/* remove last char entered */
X				echo(tp, '\b');	/* remove it from the screen */
X				echo(tp, ' ');
X				echo(tp, '\b');
X			}
X			return(1);
X		}
X
X		/* Now do kill processing (remove current line). */
X		if (ch == tp->tty_kill && tp->tty_escaped == NOT_ESCAPED) {
X			while ( chuck(tp) == OK) /* keep looping */ ;
X			echo(tp, tp->tty_kill);
X			echo (tp, '\n');
X			return(1);
X		}
X
X		/* Handle EOT and the escape symbol (backslash). */
X		if (tp->tty_escaped == NOT_ESCAPED) {
X			/* Normal case: previous char was not backslash. */
X			if (ch == '\\') {
X				/* An escaped symbol has just been typed. */
X				tp->tty_escaped = ESCAPED;
X				echo(tp, ch);
X				return(1);	/* do not store the '\' */
X			}
X			/* CTRL-D means end-of-file, unless it is escaped. It
X			 * 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 (ch == tp->tty_eof) ch = MARKER;
X		} else {
X			/* Previous character was backslash. */
X			tp->tty_escaped = NOT_ESCAPED;	/* turn escaping off */
X			if (ch != tp->tty_erase && ch != tp->tty_kill &&
X						   ch != tp->tty_eof) {
X				/* Store the escape previously skipped over */
X				*tp->tty_inhead++ = '\\';
X				tp->tty_incount++;
X				if (tp->tty_inhead ==
X						&tp->tty_inqueue[TTY_IN_BYTES])
X					tp->tty_inhead = tp->tty_inqueue;
X			}
X		}
X	}
X	/* Both COOKED and CBREAK modes come here; first map CR to LF. */
X	if (ch == '\r' && (tp->tty_mode & CRMOD)) ch = '\n';
X
X	/* Check for interrupt and quit characters. */
X	if (ch == tp->tty_intr) {
X		sigchar(tp, SIGINT);
X		return(1);
X	}
X	if (ch == tp->tty_quit) {
X		sigchar(tp, SIGQUIT);
X		return(1);
X	}
X
X	/* Check for and process CTRL-S (terminal stop). */
X	if (ch == tp->tty_xoff) {
X		tp->tty_inhibited |= STOPPED;
X		return(1);
X	}
X
X	/* Check for stopped output (any key including CTRL-Q) */
X	if (tp->tty_inhibited & STOPPED) {
X		tp->tty_inhibited &= ~STOPPED;
X		if ((*tp->tty_start)(tp))	/* resume output */
X			finish(tp, tp->tty_cum);
X		return(1);
X	}
X  }
X
X  /* All 3 modes come here. */
X  if (ch == '\n' || ch == MARKER) tp->tty_lfct++;	/* count line feeds */
X } else {
X/* AT LEAST WE CAN USE THE RETURN KEY */
X  if (ch == '\n' || ch == '\r') tp->tty_lfct++;
X }
X  *tp->tty_inhead++ = ch;	/* save the character in the input queue */
X  if (tp->tty_inhead == &tp->tty_inqueue[TTY_IN_BYTES])
X	tp->tty_inhead = tp->tty_inqueue;	/* handle wraparound */
X  tp->tty_incount++;
X  echo(tp, ch);
X  return(1);
X}
X
X
X/*===========================================================================*
X *				echo					     *
X *===========================================================================*/
XPRIVATE echo(tp, c)
Xregister struct tty_struct *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  if ((c != MARKER) || (tp->tty_mode & RAW))
X	  (*tp->tty_echo)(tp, c);
X}
X
X
X/*===========================================================================*
X *				chuck					     *
X *===========================================================================*/
XPRIVATE int chuck(tp)
Xregister struct tty_struct *tp;	/* from which tty should chars be removed */
X{
X/* Delete one character from the input queue.  Used for erase and kill. */
X
X  char *prev;
X
X  /* If input queue is empty, don't delete anything. */
X  if (tp->tty_incount == 0) return(-1);
X
X  /* Don't delete '\n' or '\r'. */
X  prev = (tp->tty_inhead != tp->tty_inqueue ? tp->tty_inhead - 1 :
X					     &tp->tty_inqueue[TTY_IN_BYTES-1]);
X  if (*prev == '\n' || *prev == '\r') return(-1);
X  tp->tty_inhead = prev;
X  tp->tty_incount--;
X  return(OK);			/* char erasure was possible */
X}
X
X
X/*===========================================================================*
X *				do_read					     *
X *===========================================================================*/
XPRIVATE do_read(tp, m_ptr)
Xregister struct tty_struct *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
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  /* 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_in_vir = m_ptr->ADDRESS;
X  tp->tty_inleft = m_ptr->COUNT;
X
X  /* Try to get chars.  This call either gets enough, or gets nothing. */
X  code = rd_chars(tp);
X
X  caller = (int) tp->tty_inproc;
X  tty_reply(TASK_REPLY, m_ptr->m_source, caller, code, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				rd_chars				     *
X *===========================================================================*/
X
XPRIVATE int rd_chars(tp)
Xregister struct tty_struct *tp;	/* pointer to terminal to read from */
X{
X/* A process wants to read from a terminal.  First check if enough data is
X * available. If so, pass it to the user.  If not, send FS a message telling
X * it to suspend the user.  When enough data arrives later, the tty driver
X * copies it to the user space directly and notifies FS with a message.
X */
X
X  int cooked, ct, user_ct, buf_ct, cum, enough, eot_seen;
X  vir_bytes in_vir, left;
X  phys_bytes user_phys, tty_phys;
X  char ch, *tty_ptr;
X  struct proc *rp;
X  extern phys_bytes umap();
X  static char tty_buf[256];	/* scratch buffer to/from user space */
X
X  message rstty_mess;
X
X/* for midi and rs232, call a get routine to fill the tty queue */
X  cooked = ( (tp->tty_mode & (RAW | CBREAK)) ? 0 : 1);	/* 1 iff COOKED mode */
X  if (tp->tty_incount == 0 || (cooked && tp->tty_lfct == 0)) return(SUSPEND);
X  rp = proc_addr(tp->tty_inproc);
X  in_vir = (vir_bytes) tp-> tty_in_vir;
X  left = (vir_bytes) tp->tty_inleft;
X  if ( (user_phys = umap(rp, D, in_vir, left)) == 0) return(E_BAD_ADDR);
X  tty_phys = umap(proc_addr(TTY), D, (vir_bytes) tty_buf, (vir_bytes) sizeof(tty_buf));
X  cum = 0;
X  enough = 0;
X  eot_seen = 0;
X
X  /* The outer loop iterates on buffers, one buffer load per iteration. */
X  while (tp->tty_inleft > 0) {
X	buf_ct = MIN(tp->tty_inleft, tp->tty_incount);
X	buf_ct = MIN(buf_ct, sizeof(tty_buf));
X	ct = 0;
X	tty_ptr = tty_buf;
X
X	/* The inner loop fills one buffer. */
X	while(buf_ct-- > 0) {
X		ch = *tp->tty_intail++;
X		if (tp->tty_intail == &tp->tty_inqueue[TTY_IN_BYTES])
X			tp->tty_intail = tp->tty_inqueue;
X		*tty_ptr++ = ch;
X		ct++;
X		if (ch == '\n' || ch == MARKER) {
X			tp->tty_lfct--;
X			if (cooked && ch == MARKER) eot_seen++;
X			enough++;	/* exit loop */
X			if (cooked) break;	/* only provide 1 line */
X		}
X	}
X
X	/* Copy one buffer to user space.  Be careful about CTRL-D.  In cooked
X	 * mode it is not transmitted to user programs, and is not counted as
X	 * a character as far as the count goes, but it does occupy space in 
X	 * the driver's tables and must be counted there.
X	 */
X	user_ct = (eot_seen ? ct - 1 : ct);	/* bytes to copy to user */
X	phys_copy(tty_phys, user_phys, (phys_bytes) user_ct);
X	user_phys += user_ct;
X	cum += user_ct;
X	tp->tty_inleft -= ct;
X	tp->tty_incount -= ct;
X	if (tp->tty_incount == 0 || enough) break;
X  }
X  if(tp->tty_incount == 0 && tp->tty_inleft && !enough && Rs_blocked) {
X	ct = lock();
X	rstty_mess.m_type = TTY_CHAR_INT;
X	rstty_mess.ADDRESS = (char *)0 ;
X	interrupt(RS232, &rstty_mess);	/* send message to tty task */
X	restore(ct);
X  }
X
X  tp->tty_inleft = 0;
X  return(cum);
X}
X
X
X/*===========================================================================*
X *				finish					     *
X *===========================================================================*/
XPRIVATE finish(tp, code)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xint code;			/* reply code */
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
X/*===========================================================================*
X *				do_write				     *
X *===========================================================================*/
XPRIVATE do_write(tp, m_ptr)
Xregister struct tty_struct *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  vir_bytes out_vir, out_left;
X  struct proc *rp;
X  extern phys_bytes umap();
X
X  /* Copy message parameters to the tty structure. */
X  tp->tty_otcaller = m_ptr->m_source;
X  tp->tty_outproc = m_ptr->PROC_NR;
X  tp->tty_out_vir = m_ptr->ADDRESS;
X  tp->tty_outleft = m_ptr->COUNT;
X  tp->tty_waiting = WAITING;
X  tp->tty_cum = 0;
X
X  /* Compute the physical address where the data is in user space. */
X  rp = proc_addr(tp->tty_outproc);
X  out_vir = (vir_bytes) tp->tty_out_vir;
X  out_left = (vir_bytes) tp->tty_outleft;
X  if ( (tp->tty_phys = umap(rp, D, out_vir, out_left)) == 0) {
X	/* Buffer address provided by user is outside its address space. */
X	tp->tty_cum = E_BAD_ADDR;
X	tp->tty_outleft = 0;
X  }
X#ifdef ATARI_ST
X  rp->p_physio = 1;	/* disable (un)shadowing */
X#endif
X
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
X
X/*===========================================================================*
X *				do_ioctl				     *
X *===========================================================================*/
XPRIVATE do_ioctl(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty_struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* Perform IOCTL on this terminal. */
X
X  long flags, erki, erase, kill, intr, quit, xon, xoff, eof, baud;
X  int r;
X
X  r = OK;
X  flags = 0;
X  erki = 0;
X  switch(m_ptr->TTY_REQUEST) {
X     case TIOCSETP:
X	/* Set erase, kill, and flags. */
X	baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
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(baud != tp->tty_baud)
X		r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X
X     case TIOCSETC:
X	/* Set intr, quit, xon, xoff, eof (brk not used). */
X
X	tp->tty_intr = (char) ((m_ptr->TTY_SPEK >> 24) & BYTE);	/* interrupt */
X	tp->tty_quit = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* quit */
X	tp->tty_xon  = (char) ((m_ptr->TTY_SPEK >>  8) & BYTE);	/* CTRL-S */
X	tp->tty_xoff = (char) ((m_ptr->TTY_SPEK >>  0) & BYTE);	/* CTRL-Q */
X	tp->tty_eof  = (char) ((m_ptr->TTY_FLAGS >> 8) & BYTE);	/* CTRL-D */
X	break;
X
X     case TIOCGETP:
X	/* Get erase, kill, and flags. */
X	erase = ((long) tp->tty_erase) & BYTE;
X	kill  = ((long) tp->tty_kill) & BYTE;
X	baud  = ((long) tp->tty_baud) & BYTE;
X	erki  = (baud << 16) | (erase << 8) | kill;
X	flags = (long) tp->tty_mode;
X	break;
X
X     case TIOCGETC:
X	/* Get intr, quit, xon, xoff, eof. */
X	intr  = ((long) tp->tty_intr) & BYTE;
X	quit  = ((long) tp->tty_quit) & BYTE;
X	xon   = ((long) tp->tty_xon)  & BYTE;
X	xoff  = ((long) tp->tty_xoff) & BYTE;
X	eof   = ((long) tp->tty_eof)  & BYTE;
X	erki  = (intr << 24) | (quit << 16) | (xon << 8) | (xoff << 0);
X	flags = (eof <<8);
X	break;
X
X     case TIOCSTART:
X     case TIOCSTOP:
X	rstty_init();
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X     case TCSETAW: /* wait for output to drain */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	/* Set erase, kill, and flags. */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
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	break;
X     case TCSETAF: /* wait for output to drain, then flush input */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	/* Set erase, kill, and flags. */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
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	break;
X     case TCSBRK:  /* drain output, send a break */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X     case TCXONC:  /* start/stop output arg ==0 stop, ==1 start */	
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X     	break;
X     case TCFLSH:  /* flush: 0==input 1==output 2=both */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X
X     default:
X	r = EINVAL;
X  }
X
X  /* Send the reply. */
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r, flags, erki);
X}
X
X
X/*===========================================================================*
X *				do_setpgrp				     *
X *===========================================================================*/
XPRIVATE do_setpgrp(tp, m_ptr)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* A control process group has changed */
X
X   if((tp->tty_pgrp = m_ptr->TTY_PGRP) )
X	(*tp->tty_open)(tp);	/* do a device open to force midi/rs232 startup */
X   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				do_cancel				     *
X *===========================================================================*/
XPRIVATE do_cancel(tp, m_ptr)
Xregister struct tty_struct *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
X  /* First check to see if the process is indeed hanging.  If it is not, don't
X   * reply (to avoid race conditions).
X   */
X  if (tp->tty_inleft == 0 && tp->tty_outleft == 0) return;
X
X  /* Kill off input and output. */
X  tp->tty_inhead = tp->tty_inqueue;	/* discard all input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  tp->tty_inleft = 0;
X  tp->tty_outleft = 0;
X  tp->tty_waiting = NOT_WAITING;	/* don't send reply */
X  tp->tty_inhibited = RUNNING;
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				tty_reply				     *
X *===========================================================================*/
XPRIVATE 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 rstty_mess;
X
X  rstty_mess.m_type = code;
X  rstty_mess.REP_PROC_NR = proc_nr;
X  rstty_mess.REP_STATUS = status;
X  rstty_mess.TTY_FLAGS = extra;	/* used by IOCTL for flags (mode) */
X  rstty_mess.TTY_SPEK = other;	/* used by IOCTL for erase and kill chars */
X  send(replyee, &rstty_mess);
X}
X
X/*===========================================================================*
X *				sigchar					     *
X *===========================================================================*/
XPRIVATE sigchar(tp, sig)
Xregister struct tty_struct *tp;	/* pointer to tty_struct */
Xint sig;			/* SIGINT, SIGQUIT, or SIGKILL */
X{
X/* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard */
X
X  tp->tty_inhibited = RUNNING;	/* do implied CRTL-Q */
X  finish(tp, EINTR);		/* send reply */
X  tp->tty_inhead = tp->tty_inqueue;	/* discard input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  if (tp->tty_pgrp)
X	cause_sig(tp->tty_pgrp, sig);
X}
X
X
X/*===========================================================================*
X *				rstty_init				     *
X *===========================================================================*/
XPRIVATE rstty_init()
X{
X/* Initialize the tty tables. */
X
X  register struct tty_struct *tp;
X  int i;
X
X  for (i = 0; i < NR_RS232; i++) {
X	tp = &rstty_struct[i];
X  tp->tty_inhead = tp->tty_inqueue;	/* discard all input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  tp->tty_inleft = 0;
X  tp->tty_outleft = 0;
X  tp->tty_waiting = NOT_WAITING;	/* don't send reply */
X  tp->tty_inhibited = RUNNING;
X	tp->tty_mode = CRMOD | XTABS | ECHO ;
X
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	Rs232_wempty = 0;
X	rs232init(tp);
X  }
X}
X
Xrstty_dmp()
X{
X	struct tty_struct *tp;
X
X	tp = &rstty_struct[0];
X
Xprintf("\rTTY for RS232: cnt_max=%d\n\
X\r\tinhead=%lx intail=%lx inqueue=%lx mode=%x\n\
X\r\terase=%x kill=%x intr=%x quit=%x xon=%x xoff=%x eof=%x\n\
X\r\tincount=%d lfct=%d escaped=%x inhibited=%x waiting=%x\n\
X\r\tincaller=%d inproc=%d in_vir=%lx inleft=%d otcaller=%d outproc=%d\n\
X\r\t out_vir=%lx phys=%lx outleft=%d cum=%d pgrp=%d baud=%x\n\r",
Xcnt_max,
X	tp->tty_inhead ,
X	tp->tty_intail , tp->tty_inqueue,
X	tp->tty_mode ,
X
X	tp->tty_erase ,
X	tp->tty_kill  ,
X	tp->tty_intr  ,
X	tp->tty_quit  ,
X	tp->tty_xon   ,
X	tp->tty_xoff  ,
X	tp->tty_eof   ,
X	tp->tty_incount, tp->tty_lfct, tp->tty_escaped, tp->tty_inhibited,
X	tp->tty_waiting,
X  	tp->tty_incaller,		/* process that made the call (usually FS) */
X  	tp->tty_inproc,		/* process that wants to read from tty */
X  	tp->tty_in_vir,		/* virtual address where data is to go */
X  	tp->tty_inleft,		/* how many chars are still needed */
X  	tp->tty_otcaller,		/* process that made the call (usually FS) */
X  	tp->tty_outproc,		/* process that wants to write to tty */
X  	tp->tty_out_vir,		/* virtual address where data comes from */
X  	tp->tty_phys,		/* physical address where data comes from */
X  	tp->tty_outleft,		/* # chars yet to be copied to tty_outqueue */
X  	tp->tty_cum,			/* # chars copied to tty_outqueue so far */
X  	tp->tty_pgrp,			/* Slot number of controlling process */
X  	tp->tty_baud		/* index of baud (rs232) */
X	);
X}
SHAR_EOF
echo extracting 'rs232.c'
sed -e 's/^X//' >rs232.c <<'SHAR_EOF'
X/* RS232 driver */
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/sgtty.h"
X#include "../h/signal.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X#include "tty.h"
X#include "stacia.h"
X#include "stmfp.h"
X#include "stsound.h"
X#include "staddr.h"
X#include "glo.h"
X#include "ring.h"
X
XPRIVATE dbg_flag = 0;
XPRIVATE message	commes;		/* message used for console input chars */
X
XPUBLIC struct ring rs232ring;
X#define COM_OUT_SIZE 512
XPRIVATE  char	com_out_buffer[COM_OUT_SIZE];
X
X#define COM_IN_SIZE 512
XPRIVATE  char	com_in_buffer[COM_IN_SIZE];
X
XPRIVATE int rs232_o_flag = 0;
XPRIVATE int Xmit_on = 0;
X
Xextern struct tty_struct rstty_struct[];
X
X#define T_BITS IA_TRDY
X#define R_BITS IA_RRDY
X#define RENABLE()	MFP->mf_imra |= (R_BITS)
X#define RDISABLE()	MFP->mf_imra &= ~(R_BITS)
X#define TENABLE()	MFP->mf_imra |= (T_BITS)
X#define TDISABLE()	MFP->mf_imra &= ~(IA_TERR | T_BITS)
X
Xint set_timer();
X
X/*
X * This file contains the device_dependent part of the rs232 driver.
X *
X */
X
X/*===========================================================================*
X *				open 					     *
X *===========================================================================*/
XPRIVATE int open(tp)
Xregister struct tty_struct *tp;
X{
X	int s;
X	int i;
X
X	if(rs232_o_flag ==0) {
X		rs232_o_flag = 1;
X		s = lock();
X		rs232init(tp); /* will turn off all interrupts */
X		restore(s);
X	}
X}
X
X
X/*===========================================================================*
X *				close 					     *
X *===========================================================================*/
XPRIVATE int close(tp)
Xregister struct tty_struct *tp;
X{
X	MFP->mf_imra &= ~( IA_RRDY | IA_TRDY | IA_TERR | IA_RERR);
X	rs232_o_flag = 0;
X	Xmit_on = 0;
X}
X/*===========================================================================*
X *				ioctl 					     *
X *===========================================================================*/
X
XPRIVATE int ioctl(tp,m_ptr)
Xregister struct tty_struct *tp;
Xmessage *m_ptr;
X{
X  long i;
X
X  switch(m_ptr->TTY_REQUEST) {
X     case TIOCSTART:
X	open(tp);
X	return(OK);
X     case TIOCSTOP:
X	close(tp);
X	return(OK);
X     case TIOCSETP:
X	set_timer(tp->tty_baud);
X     case TCSETAW: /* wait for output to drain */
X	while(rs232ring.o_head != rs232ring.o_tail);
X	return(OK);
X     case TCSETAF: /* wait for output to drain, then flush input */
X	while(rs232ring.o_head != rs232ring.o_tail);
X	rs232ring.i_head = rs232ring.i_tail = 0;
X	tp->tty_inhead = tp->tty_inqueue;
X	tp->tty_intail = tp->tty_inqueue;
X	tp->tty_incount = 0;
X	tp->tty_lfct = 0;
X	tp->tty_inleft = 0;
X	tp->tty_outleft = 0;
X	return(OK);
X     case TCSBRK:  /* drain output, send a break */
X	while(rs232ring.o_head != rs232ring.o_tail);
X	MFP->mf_tsr = T_BREAK | T_ENA;
X	for(i=0;i<30000;i++) ;
X	MFP->mf_tsr = T_ENA;
X	return(OK);
X     case TCXONC:  /* start/stop output arg ==0 stop, ==1 start */	
X	switch((int)m_ptr->TTY_SPEK) {
X	case 0:
X		break;
X	case 1:
X		break;
X	}
X	return(OK);
X     case TCFLSH:  /* flush: 0==input 1==output 2=both */
X	switch((int)m_ptr->TTY_SPEK) {
X	case 0:
X		rs232ring.i_head = rs232ring.i_tail;
X	tp->tty_inhead = tp->tty_inqueue;
X	tp->tty_intail = tp->tty_inqueue;
X	tp->tty_incount = 0;
X	tp->tty_lfct = 0;
X	tp->tty_inleft = 0;
X	tp->tty_outleft = 0;
X		break;
X	case 1:
X		rs232ring.o_head = rs232ring.o_tail;
X		break;
X	case 2:
X		rs232ring.i_head = rs232ring.i_tail;
X		rs232ring.o_head = rs232ring.o_tail;
X		break;
X	}
X	return(OK);
X  }
X}
X
XPUBLIC rs232charint()
X{
X	/* Build and send the interrupt message. */
Xif(dbg_flag)
Xprintf("sia_rrdy charint msg n=%d\n\r",rs232ring.i_head - rs232ring.i_tail);
X	commes.m_type = TTY_CHAR_INT;
X	commes.ADDRESS = (char *)0 ;
X	interrupt(RS232, &commes);	/* send message to tty task */
X}
X  
X
X/*===========================================================================*
X *				start					     *
X *===========================================================================*/
X
XPRIVATE int start(tp)
Xregister struct tty_struct *tp;
X{
X	int r;
X	int i;
X	register int k;	
X
X	if(rs232_o_flag == 0) {
X		rs232_o_flag++;
X		r = lock();
X		rs232init();
X	
X
X		restore(r);
X	}
X
X	if (tp->tty_outleft == 0)
X		return(1);
Xif(dbg_flag)
Xprintf("Start left=%d\n\r",tp->tty_outleft);
X	do {
X		if((r = rs232put( *(char*)tp->tty_phys)) == 0)
X			break;
X		tp->tty_phys++;
X		tp->tty_cum++;		/* number of characters printed */
X	} while ( --tp->tty_outleft != 0 );
X	return(r);
X}
X/*===========================================================================*
X *				echo	 				     *
X *===========================================================================*/
XPRIVATE echo(tp, c)
Xregister struct tty_struct *tp;
X{
X  rs232put(c);
X}
X/*
X * This file contains the device_dependent part of the rs232 driver.
X *
X */
X
X/*===========================================================================*
X *				siaint					*
X *===========================================================================*/
X
XPUBLIC siaint(which)
Xint which;	/* 0=rrdy, 1=rerr, 2=trdy, 3=terr */
X{
X	switch(which) {
X		case 1:	/* rerr */
X			printf("sia_rerr\n\r");
X			break;	
X		case 3:	/* terr */
X			printf("sia_terr\n\r");
X			break;	
X		case 0: /* rrdy */
X			sia_rrdy();
X			break;	
X		case 2: /* trdy */
X			sia_trdy();
X			break;	
X	}
X}
X
X/*===========================================================================*
X *				sia_rrdy					*
X *===========================================================================*/
X
XPRIVATE sia_rrdy()
X{
X	rs232rrdy();
X}
X/*===========================================================================*
X *				sia_trdy					*
X *===========================================================================*/
X
XPRIVATE sia_trdy()
X{
X	rs232trdy();
X}
X
X
X/*===========================================================================*
X *				rs232_init				     *
X *===========================================================================*/
XPUBLIC rs232init(tp)
Xregister struct tty_struct *tp;
X{
X  int i;
X  struct ring *rp = &rs232ring;
X
X
X	rs232_o_flag = 1;
X	rp->i_buffer = com_in_buffer;
X	rp->i_length = COM_IN_SIZE;
X	rp->i_head = 0;
X	rp->i_tail = 0;
X	rp->i_lo_water = (TTY_IN_BYTES / 16);	/* restart at this level */
X	rp->i_hi_water = (TTY_IN_BYTES / 4);	/* send xoff function at this level */
X	rp->i_lo_water = (16);	/* restart at this level */
X	rp->i_hi_water = (64);	/* send xoff function at this level */
X
X	rp->o_buffer = com_out_buffer;
X	rp->o_length = COM_OUT_SIZE;
X	rp->o_head = 0;
X	rp->o_tail = 0;
X	rp->o_lo_water = COM_OUT_SIZE / 4;
X	rp->o_hi_water = 3 * COM_OUT_SIZE / 4;
X
X	rp->rx_stat = 0;
X	rp->tx_stat = 0;
X	rp->xoff_flag = 0;
X	rp->xon_flag = 0;
X	rp->rtscts = 1;
X	rp->xoff_char = XOFF_CHAR;
X	rp->xon_char = XON_CHAR;
X
X  tp->tty_start = start;
X  tp->tty_echo = echo;
X  tp->tty_open = open;
X  tp->tty_close = close;
X  tp->tty_ioctl = ioctl;
X	MFP->mf_imra &= ~( IA_RRDY | IA_TRDY | IA_TERR | IA_RERR);
X	MFP->mf_tsr = 0;
X		tp->tty_inhead = tp->tty_inqueue;
X		tp->tty_intail = tp->tty_inqueue;
X		tp->tty_mode = CRMOD | XTABS | ECHO;
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_baud   = B2400;
X		Xmit_on  = 0;
X		tp->tty_inhibited = 0;
X		MFP->mf_rsr = 0;
X		MFP->mf_tsr = T_HIGH;
X		set_timer(tp->tty_baud);
X		MFP->mf_ucr = U_Q16 | U_ST2;
X		MFP->mf_rsr = R_ENA;
X		MFP->mf_tsr |= T_ENA;
X		MFP->mf_ierb &= ~(IB_SCTS | IB_SDCD);
X		MFP->mf_iera |= (  R_BITS | T_BITS); /* start receive */
X		MFP->mf_imra |= (T_BITS | R_BITS);
X
X		dtr_on();
X		rts_on();
X
X}
X/*===========================================================================*
X *				set_timer				     *
X *===========================================================================*/
XPRIVATE struct baud  {
X	unsigned char prescale;
X	unsigned char scale;
X} baud[] = {
X	T_Q004,	1,	/* 0 19200 divided by 1 */
X	T_Q004,	2,	/* 1 9600 */
X	T_Q004,	4,	/* 2 4800 */
X	T_Q004,	5,	/* 3 3600 */
X	T_Q004,	8,	/* 4 2400 */
X	T_Q004,	10,	/* 5 2000 */
X	T_Q004,	11,	/* 6 1800 */
X	T_Q004,	16,	/* 7 1200 */
X	T_Q004,	32,	/* 8 600 */
X	T_Q004,	64,	/* 9 300 */
X	T_Q004,	96,	/* a 200 */
X	T_Q004,	128,	/* b 150 */
X	T_Q004,	143,	/* c 134 */
X	T_Q004,	175,	/* d 110 */
X	T_Q016,	64,	/* e 75	 */
X	T_Q016,	96, 	/* f 50 */
X};
X
XPRIVATE set_timer(index)
X{
X/*
X * Initialize the timer D in the MFP 68901.
X */
X	int clock;
X	int clocka;
X
X	clock = MFP->mf_tcdcr & 0x70;
X	for(;;) {
X		clocka = MFP->mf_tcdcr & 0x70;
X		if(clock != clocka) {
X			clock = clocka;
X			continue;
X		}
X		break;
X	}
X  do
X	MFP->mf_tddr = baud[index].scale;
X  while ((MFP->mf_tddr & 0xFF) != baud[index].scale);
X  MFP->mf_tcdcr = clock | baud[index].prescale;
X}
Xrs232_dmp()
X{
X	dbg_flag ^=1;
X	printf("DMP:ohead=%d otail=%d ihead=%d itail=%d iera=%x imra=%x\n\r",
X		rs232ring.o_head, rs232ring.o_tail,
X		rs232ring.i_head, rs232ring.i_tail,
X	 MFP->mf_iera, MFP->mf_imra);
X	printf("\tdbgflg=%d Xmit_on=%d tsr=%x rsr=%x\n\r",
X	 dbg_flag,Xmit_on,MFP->mf_tsr,MFP->mf_rsr);
X	printf("\tring flgs: tx=%x rx=%x xoff=%x on=%x dtrcts=%x\n\r",
X		rs232ring.rx_stat, rs232ring.tx_stat,
X		rs232ring.xoff_flag, rs232ring.xon_flag,
X		rs232ring.rtscts);
X}
XRsdebuger(x)
X{
X	printf("Rsdebuger(%x)\n",x);
X}
SHAR_EOF
echo extracting 'rs232s.s'
sed -e 's/^X//' >rs232s.s <<'SHAR_EOF'
X
X! entry points
X	.define	_rs232get	!get chars from input ring
X	.define	_rs232put	!put chars to output ring
X	.define	_rs232rrdy	!process rec char interrupt
X	.define	_rs232trdy	!process xmit char interrupt
X	.define	_rs232cts	!process cts interrupt
X	.define _dtr_on		!turn on dtr
X	.define _rts_on		!turn on cts
X	.define _dtr_off	!turn off dtr
X	.define _rts_off	!turn off cts
X
X	.extern	_rs232ring	!input and output rings
X	.extern	_rs232charint	!sends a charint message
X	.extern	_Rs232_wempty	!a flag cleared in do_odone
X
X	.extern _Rsdebuger
X
X	.sect	.text
X	.sect	.rom
X	.sect	.data
X	.sect	.bss
X
X	.sect	.text
X_setjmp:
X!
X!  ring buffer offsets locked to ring.h
X!
Xi_buffer = 0
Xi_length = 4
Xi_head = 6
Xi_tail = 8
Xi_lo_wat = 0xa
Xi_hi_wat = 0xc
Xo_buffer = 0xe
Xo_length = 0x12
Xo_head = 0x14
Xo_tail = 0x16
Xo_low_wat = 0x18
Xo_hi_wat = 0x1a
Xrs_data = 0x1c
Xts_data = 0x1d
Xxoff_flag = 0x1e
Xxon_flag = 0x1f
Xrtscts_flag = 0x20
Xxoff_char = 0x21
Xxon_char  = 0x22
X
X	.sect	.text
X! setup a0, a1 for routines
Xrs232ptr:
X	lea	_rs232ring,a0		! pointer to rs232 iorec
X	lea	0xfffffa01,a1		! pointer to mfp
X	rts		! 4e75
X
X! compute actual size of input ring in use  (tail - head)
Xrs232ibuf:
X	move	i_tail(a0),d2		! tail index
X	move	i_head(a0),d3		! head index
X	cmp.w	d3,d2		! head > tail ?
X	bhi	L1		! no
X	add.w	i_length(a0),d2		! add buffer size
XL1:
X	sub.w	d3,d2		! tail - head
X	rts		! 4e75
Xrtschk:
X	btst	#0x1,rtscts_flag(a0)		! RTS/CTS mode
X	beq	L2		! no
X	bsr	rts_on		! rts on
XL2:
X	rts		! 4e75
X
X_rs232put:
X	move.w	4(a7), d1
Xcomput:
X	movem.l	d2-d3,-(a7)		!  save regs
X	move.w	sr,-(a7)		! save status
X	or.w	#0x700,sr		! IPL 7, disable interrupts
X	bsr	rs232ptr		! get buffer pointer
X	btst	#0x0,rtscts_flag(a0)		! XON/XOFF mode?
X	beq	L4		! no
X	tst.b	xoff_flag(a0)		! XON active?
X	bne	L5		! yes
XL4:
X	btst	#0x7,0x2c(a1)		! is MFP still sending?
X	beq	L5		! yes
X	move.w	o_head(a0),d2		! head index
X	cmp.w	o_tail(a0),d2		! tail index
X	bne	L5		! still chars in buffer?
X	move.b	d1,0x2e(a1)		! no, pass_data to mfp
X	bra	L6		!.data has been sent
X!queue the.data
XL5:
X	move.w	o_tail(a0),d2		! tail index
X	bsr	wrapout		! test for wrap around
X	cmp.w	o_head(a0),d2		! compare with head index
X!if buffer is full, just dump the char, boo!
X	beq	L7		! same, buffer is full
X	move.l	o_buffer(a0),a1		! get current buffer address
X	move.b	d1,0x0(a1,d2.w)		! write char in buffer
X	move.w	d2,o_tail(a0)		! save new tail index
XL6:
X	bsr	rtschk		! rschk, set RTS?
X	move	(a7)+,sr		! restore status
X	move.l	#1,d0			! char sent
X	movem.l	(a7)+,d2-d3		! restore regs
X	rts		! 4e75
XL7:
X	bsr	rtschk		!  rschk, set RTS?
X	move	(a7)+,sr		! restore status
X	move.l	#0,d0			! char not sent
X	movem.l	(a7)+,d2-d3		! restore regs
X	rts		! 4e75
X
X_rs232get: !rs232 input
X	movem.l	d2-d3,-(a7)		!  save regs
X	move	sr,-(a7)		! save status
X	or.w	#0x700,sr		! IPL 7, disable interrupts
X	bsr	rs232ptr		! get rs232 pointer
X	move	i_head(a0),d1		! head index
X	cmp.w	i_tail(a0),d1		! tail index
X	beq	L10		! no char in buffer ?
X	bsr	wrapin		! test for wrap arround
X	move.l	i_buffer(a0),a1		! get buffer address
X	move.l	#0x0,d0		! 7000
X	move.b	0x0(a1,d1.w),d0		! get char from the buffer
X	move	d1,i_head(a0)		! set new head index
X!move	(a7)+,sr		! restore status
X!and.b	#0xfe,ccr		! clear carry flag, OK
X	bra	L9		! 6006
XL10:
Xmove.w	#0x100,d0	!1xx if no char
X
X!move	(a7)+,sr		! restore status
X!or.b	#0x1,ccr		! set carry flag, no chars in buffer
X
XL9:
Xmove.w	d0,-(a7)
X	btst	#0x0,rtscts_flag(a0)		! XON/XOFF mode ?
X	beq	L11		! no
X	tst.b	xon_flag(a0)		! XON active ?
X	beq	L11		! no
X	bsr	rs232ibuf		! get input buffer, and length 
X	cmp.w	i_lo_wat(a0),d2		! equal low water mark?
X	bne	L11		! no
X	move.b	xon_char(a0),d1		! this is XON
X	bsr	comput		! send it
X!movem.l	d0-d1/a0-a1,-(a7)		!  save regs
X!move d1,-(a7)
X!jsr _Rsdebuger
X!add.l #2,a7
X!movem.l	(a7)+,d0-d1/a0-a1		! restore regs
X	clr.b	xon_flag(a0)		! clear the XON flag
XL11:
X	move	(a7)+,d0		! return value
X	move	(a7)+,sr		! restore status
X	movem.l	(a7)+,d2-d3		! restore regs
X	rts		! 4e75
X
X!rs232 receiver interrupt routine
X! called as a C program
X_rs232rrdy:
Xrcvint: 
X	movem.l	d2-d3/a2,-(a7)		!  save regs
X	bsr	rs232ptr		! get rs232 pointer
X	move.b	0x2a(a1),rs_data(a0)		! read receiver status reg
X	btst	#0x7,rs_data(a0)	! interrupt through receiver buffer full
X	beq	R2		! no
X	btst	#0x1,rtscts_flag(a0)		! RTS/CTS mode?
X	beq	R1		! no
X	bsr	rts_off		! rts off
XR1:
X	move.b	0x2e(a1),d0		! read data from rec. register
X	btst	#0x1,rtscts_flag(a0)		! RTS/CTS mode?
X	bne	R3		! yes
X	btst	#0x0,rtscts_flag(a0)		! XON/XOFF mode?
X	beq	R3		! no
X	cmp.b	xon_char(a0),d0		! XON received?
X	bne	R4		! no
X	move.b	#0x0,xoff_flag(a0)		! clear XOFF flag
X	move	o_head(a0),d2		! get head index
X	cmp.w	o_tail(a0),d2		! == to tail?
X	beq	R2		! yes
X	bsr	wrapout		! wrap the pointer
X	move.l	o_buffer(a0),a2		! get the output buffer 
X	move.b	0x0(a2,d2.w),0x2e(a1)		! 1372 2000 002e
X	move	d2,o_head(a0)		! 3142 0014
X	bra	R2		! 6062
XR4:
X	cmp.b	xoff_char(a0),d0		! receive XOFF?
X	bne	R3		! no
X	move.b	#0xff,xoff_flag(a0)		! save flag
X	bra	R2		! char not in buffer
XR3:
X	move	i_tail(a0),d1		! 3228 0008
X	bsr	wrapin		! 6100 01f8
X	cmp.w	i_head(a0),d1		! b268 0006
X	beq	R2		! yes, head == tail
X	move.l	i_buffer(a0),a2		! get buffer address
X	move.b	d0,0x0(a2,d1.w)		!  put.data in the buffer
X	move	d1,i_tail(a0)		! save new tail index
X	bsr	rs232ibuf		! get input length
X	cmp.w	i_hi_wat(a0),d2		! == high water?
X	bne	L12		! no
X	btst	#0x1,rtscts_flag(a0)		! tst if rts/cts mode
X	bne	R2		! yes
X	btst	#0x0,rtscts_flag(a0)		! xon/xoff mode
X	beq	L12		! no
X	tst.b	xon_flag(a0)		! xoff sent already?
X	bne	L12		! yes
X	move.b	#0xff,xon_flag(a0)		! set flag for xoff
X	move.b	xoff_char(a0),d1		! get an xoff
X	bsr	comput		! send it
X
XL12:
X	btst	#0x1,rtscts_flag(a0)		! rtscts mode
X	beq	R2		! no
X	bsr	rts_on		! rtson
XR2:
X	jsr	_rs232charint
X	movem.l	(a7)+,d2-d3/a2		! restore regs
X	rts
X
X_rs232trdy:
Xtxrint:
X	movem.l	d2/a2,-(a7)		! save registers
X	bsr	rs232ptr		! get rs232 pointer
X	btst	#0x1,rtscts_flag(a0)		! rtscts mode?
X	bne	T1		! yes, then use this interrupt
X	btst	#0x0,rtscts_flag(a0)		! xonxoff mode?
X	beq	T2		! no
X	tst.b	xoff_flag(a0)		! xoff active ?
X	bne	T1			! yes
XT2:
X	move.b	0x2c(a1),ts_data(a0)	! save transmit status reg
X	move	o_head(a0),d2		! head index
X	cmp.w	o_tail(a0),d2		! compare with tail
X	beq	T1A			! send buffer is empty
X!look, if buffer empty, dont change mfp, as only the TXRDY transition
X!causes the interrupt. NEAT
X!
X!but for minix, we will set a tx_empty flag, and send a charint message
X!charint will see and clear the flag, and call do_odone
X	bsr	wrapout			! test for wrap arround
X	move.l	o_buffer(a0),a2		! pointer to send buffer
X	move.b	0x0(a2,d2.w),0x2e(a1)	! pass_data to mfp 
X	move	d2,o_head(a0)		! save new head
XT1:
X	movem.l	(a7)+,d2/a2		! restore regs
X	rts		! 4e73
XT1A:
X	move.w	#1, _Rs232_wempty
X	jsr	_rs232charint
X	bra	T1
X
X_rs232cts:
Xctsint: !cts interrupt routine
X	movem.l	d2/a2,-(a7)		! save regs
X	bsr	rs232ptr		! get rs232 pointer
X	btst	#0x1,rtscts_flag(a0)	! rtscts mode?
X	beq	T4			! no, then ignore interrupt
X	move.b	0x2c(a1),ts_data(a0)	! save xmit status
XT6:
X	btst	#0x7,ts_data(a0)	! trans buffer empty?
X	beq	T6			! no, wait
X	move	o_head(a0),d2		! get head index
X	cmp.w	o_tail(a0),d2		! compare wiht tail index
X	beq	T5			! transmit buffer empty
X	bsr	wrapout			! test for wrap
X	move.l	o_buffer(a0),a2		! pointer to transmit buffer
X	move.b	0x0(a2,d2.w),0x2e(a1)	! pass_data to mfp for sending
X	move	d2,o_head(a0)		! save new head index
XT4:
X	bclr	#0x2,0x10(a1)		! clear interrupt service bit
X	movem.l	(a7)+,d2/a2		! restore regs
X	rts		! 4e73
XT5:
X	bra	T4		! transmit buffer empty
X
Xrxerror: !receive error
X	movem.l	d0/a0-a1,-(a7)		! save regs
X	bsr	rs232ptr		! get rs232 pointer
X	move.b	0x2a(a1),rs_data(a0)		! save receiver status
X	move.b	0x2e(a1),d0		! read data register (to clear status)
X	movem.l	(a7)+,d0/a0-a1		! restore regs
X	rte		! 4e73
X
Xtxerror: !receive error
X	movem.l	a0-a1,-(a7)		! save regs
X	bsr	rs232ptr		! get rs232 pointer
X	move.b	0x2c(a1),ts_data(a0)		! save transmitter status
X	movem.l	(a7)+,a0-a1		! restore regs
X	rte		! 4e73
X
X
Xwrapin: !test for wrap arround
X	add.w	#1,d1		! head index + 1
X	cmp.w	i_length(a0),d1		! equal to buffer size ?
X	bcs	W1		! no
X	move.l	#0x0,d1		! else start with zero again
XW1:
X	rts		! 4e75
Xwrapout: !test for wrap arround
X	add.w	#1,d2		! tail index +1
X	cmp.w	o_length(a0),d2		! equal to buffer size?
X	bcs	W2		! no
X	move.l	#0x0,d2		! else start with zero again
XW2:
X	rts		! 4e75
X! 
X!change cts dtr bits in sound reg
X!only called at spl7
X!
Xsound_bits:
X	movem.l	d1-d2/a0,-(a7)		!  save regs
X	lea	0xffff8800,a0		! 41f9 ffff 8800
X	move.b	d1,d2		! 1401
X	and.w	#0xf,d1		! 0201 000f
X	move.b	d1,(a0)		! 1081
X	asl.b	#1,d2		! e302
X	bcc	L3		! 6404
X	move.b	d0,0x2(a0)		! 1140 0002
XL3:
X	move.w	#0x0,d0		! 7000
X	move.b	(a0),d0		! 1010
X	movem.l	(a7)+,d1-d2/a0		!  restore regs
X	rts		! 4e75
X
X_rts_off:
Xrts_off:
X	move.w	#0x8,d2		! 7408
X	bra	do_off		! 6012
X_rts_on:
Xrts_on:
X	move.w	#0xf7,d2		! 74f7
X	bra	do_on		! 6034
X_dtr_off:
Xdtr_off:
X	move.w	#0x10,d2		! 7410
X	bra	do_off		! 600a
X_dtr_on:
Xdtr_on:
X	move.w	#0xef,d2		! 74ef
X	bra	do_on		! 602c
X
X! turn off a bit input 8=cts 10=dtr
X_dtrctsoff:
X	move.l	#0x0,d2		! 7400
X	move	0x4(a7),d2		! 342f 0004
X	neg	d2
Xdo_off:
X	movem.l	d0-d2,-(a7)		!  save regs
X	move.w	sr,-(a7)		! 40e7
X	or.w  	#0x700,sr		! 007c 0700
X	move.w	#0xe,d1		! 720e
X	move.l	d2,-(a7)		! 2f02
X	bsr	sound_bits		! 61ae
X	move.l	(a7)+,d2		! 241f
X	or.b	d2,d0		! 8002
X	move.w	#0x8e,d1		! 728e
X	bsr	sound_bits		! 61a6
X	move.w	(a7)+,sr		! 46df
X	movem.l	(a7)+,d0-d2		! restore regs
X	rts		! 4e75
X!
X! entry to turn on dtr bits
X_dtrctson:
X	move.l	#0x0,d2		! 7400
X	move	0x4(a7),d2		! 342f 0004
Xdo_on:
X	movem.l	d0-d2,-(a7)		!  save regs
X	move.w	sr,-(a7)		! 40e7
X	or.w  	#0x700,sr		! 007c 0700
X	move.w	#0xe,d1		! 720e
X	move.l	d2,-(a7)		! 2f02
X	bsr	sound_bits		! 6188
X	move.l	(a7)+,d2		! 241f
X	and.b	d2,d0		! c002
X	move.w	#0x8e,d1		! 728e
X	bsr	sound_bits		! 6180
X	move.w	(a7)+,sr		! 46df
X	movem.l	(a7)+,d0-d2		! restore regs
X	rts		! 4e75
X
SHAR_EOF
echo extracting 'ring.h'
sed -e 's/^X//' >ring.h <<'SHAR_EOF'
X
Xstruct ring {
X	char *i_buffer;
X	int i_length;
X	int i_head;
X	int i_tail;
X	int i_lo_water;
X	int i_hi_water;
X
X	char *o_buffer;
X	int o_length;
X	int o_head;
X	int o_tail;
X	int o_lo_water;
X	int o_hi_water;
X
X	char rx_stat;
X	char tx_stat;
X	char xoff_flag;
X	char xon_flag;
X	char rtscts;
X	char xoff_char;
X	char xon_char;
X};
SHAR_EOF