[comp.os.minix] ST Minix kernel with rs232 -- upgrade to rs232

hcj@lzaz.ATT.COM (HC Johnson) (03/28/89)

>> Steve Kirkendall (..uunet!tektronix!psu-cs!kirkenda) writes:
* You have never posted a patch for the ioctl library function

Sorry about that.  What I did is take all the things I would have put in
my copy of libc.a and instead put the routines in cu, and created a new
library.  The reason was to try to prevent 'suprises' when an unsuspecting
function is being used in my libc.a.  Feel free to move items from the 
library in cu to lib.

* Your driver doesn't seem to respond to the CRMOD mode when outputting or
  echoing characters.  I get linefeeds but no carriage returns. 

The rstty.c uses many routines in tty.c.  As I posted earlier the problem 
is that tty.c is only ansi (minix), and dumb terminals may not like that.
Attached is a solution to the problem.


* Eventually, the port gets stuck.  When I use the port for outgoing calls on
  my modem, this is fairly rare... not prohibitive, anyway.  But when I use the
  port for logging in, it seizes up rather quickly.  Major problem.

  Symptoms of a "stuck" port:  You can write to the port with no problem, but
  any attempt to read from it will hang forever. "stty" commands seem to work
  OK, too.

  Possible cause: You receive messages in more than one place; perhaps an
  interrupt is being received by the wrong call to receive() ?  Just a guess.

This may be the symptom of a larger problem.  I have already descibed that
I have lockup problems from the keyboard.  I have stopped my symptoms
(Notice, I did not say FIXED the problem) by disconnecting the sharing of
tty.c routines by rstty.c.  (This is real easy; copy all the routines
called ISGLOBAL from tty.c to rstty.c; define ISGLOBAL to be static; and
turn off the conflicing defines at the head of rstty.c).  This option will
be in the next posting of rstty.c

* Some commands are poison!  For example, 'more' always sets the baud rate
  to 19200.

YES!.  Any routine that does an ioctl (to the rs232 port) that doesn't
use the new ioctl.c (see item 1.) will ZAP the baud.  
I have added a cludge to handle the worst of this.  Relinking the routines
in commands/ is the real fix.


>BTW, why did you *post* that message to me?  Did you have trouble mailing
>it?  (I'm curious because Portland State recently changed their local
>topography, and I haven't received any non-local mail since then.)

Do not blame Portland State.  Its an ATT problem. I think!

===============================================================
Attached are cdiff for kernel/rstty.c kernel/rs232.c and h/sgtty.h
Implemented is:
1. Add ioctl flag, OCRMOD to cause NL to be output as CR-NL.
2. Not share procs with tty.c.  This had made rs232 more stable for me.
3. Not allow a normal TCSET to change to baud rate 0.  This allows
   programs like 'more' to run without being relinked with corrected ioctl.c
   in libc.a.  
4. Added TCSETBAUD to set the baud to any value (including 0).  You will 
   probably never need this. 

5. Tomorrow I will post commands/login.c  to fix using OCRMOD and lib/ioctl.c
   to allow TCSETBAUD to work.
PS. I have kept the form of sharing proc with tty.c, but do not.  Feel free
    to experiment with which ones can be shared safely.
Testing:  I have used this to login a second ST running a terminal emulator.
    I had to fix login to use the OCRMOD and to turn ECHO off/on correctly.
    This done, all NL were preceded with a CR.  With the login turned off,
    I can still login on my UNIX(r) host.

This cdiff is meant to run in the directory containing kernel an h.
be sure to copy h/sgtty.h to /usr/include/sgtty.h
===============================================================

Howard C. Johnson
ATT Bell Labs
att!lzaz!hcj
hcj@lzaz.att.com

*** /usr/src/xminix/kernel/rstty.c	Thu Feb 22 09:46:00 1989
--- kernel/rstty.c	Thu Mar 27 09:46:49 1989
***************
*** 49,55 ****
  #include "tty.h"
  #include "ring.h"
  
! 
  /*
   * These routines are actually in tty.c
   */
--- 49,61 ----
  #include "tty.h"
  #include "ring.h"
  
! #if HAVE_LOCAL
! #define USE_TTY 0
! #endif
! 
! /* if USE_TTY is 1, then rstty.c uses routines from tty.c */
! 
! #if USE_TTY
  /*
   * These routines are actually in tty.c
   */
***************
*** 63,68 ****
--- 69,75 ----
  #define chuck(x)	tty_chuck(x)
  #define echo(x,y)	tty_echo(x,y)
  #define tty_reply(x,y,z,a,b,c)	tty_tty_reply(x,y,z,a,b,c)
+ #endif
  
  /* n.b. sigchar is public already */
  
***************
*** 81,86 ****
--- 88,94 ----
  #define DBG(x) printf(x);
  
  extern int dbg_flag;
+ extern int rs232_o_flag;
  
  /*===========================================================================*
   *				rs232_task				     *
***************
*** 98,103 ****
--- 106,114 ----
  	receive(ANY, &rstty_mess);
  /* we would rather be general here, but not enough info is avail USE 0 */
  	tp = &rstty_struct[0];
+ 	if(rs232_o_flag ==0 && rstty_mess.m_type != RS232_CLOSE)
+ 		rs232init(tp);
+ 		
  if(dbg_flag)
  printf("rstty:m_type=%d,incount=%d blocked=%d wempty=%d\n\r",
   rstty_mess.m_type, tp->tty_incount , Rs_blocked, Rs232_wempty);
***************
*** 148,153 ****
--- 159,165 ----
  message *m_ptr;			/* message containing pointer to char(s) */
  {
  	int minor;
+ 	(*tp->tty_open)(tp, m_ptr);
  	return; /* we do not know how to handle this and set pgrp also */
  }
  
***************
*** 440,452 ****
       case TCFLOWOFF:  /* set TOS flow XOFFto char == arg*/
       case TCSETDTR:  /* set DTR to arg & 1, set RTS to arg & 2 */
  	r = (*tp->tty_ioctl)(tp, m_ptr);
- if(dbg_flag)
- printf("lv rstty:req= %x\n\r",m_ptr->TTY_REQUEST);
  	break;
       case TCBAUD:  /* set the baud; really reserved for internal use */
  	r = (*tp->tty_ioctl)(tp, m_ptr);
  	tp->tty_baud = baud; 
  	break;
       case TCGETRS:
  	cp = (char *)umap(proc_addr(m_ptr->PROC_NR),D,
  		(vir_bytes)m_ptr->TTY_SPEK,
--- 452,466 ----
       case TCFLOWOFF:  /* set TOS flow XOFFto char == arg*/
       case TCSETDTR:  /* set DTR to arg & 1, set RTS to arg & 2 */
  	r = (*tp->tty_ioctl)(tp, m_ptr);
  	break;
       case TCBAUD:  /* set the baud; really reserved for internal use */
  	r = (*tp->tty_ioctl)(tp, m_ptr);
  	tp->tty_baud = baud; 
  	break;
+      case TCSETBAUD:  /* set the baud; public interface */
+ 	r = (*tp->tty_ioctl)(tp, m_ptr);
+ 	tp->tty_baud = baud; 
+ 	break;
       case TCGETRS:
  	cp = (char *)umap(proc_addr(m_ptr->PROC_NR),D,
  		(vir_bytes)m_ptr->TTY_SPEK,
***************
*** 461,467 ****
       default:
  	r = EINVAL;
    }
!   if(baud != tp->tty_baud) {
    	m_ptr->TTY_REQUEST = TCBAUD;
  	r = (*tp->tty_ioctl)(tp, m_ptr);
    }
--- 475,484 ----
       default:
  	r = EINVAL;
    }
! if(dbg_flag)
! printf("lv rstty:req= %x\n\r",m_ptr->TTY_REQUEST);
! 
!   if(tp->tty_baud && baud != tp->tty_baud) {
    	m_ptr->TTY_REQUEST = TCBAUD;
  	r = (*tp->tty_ioctl)(tp, m_ptr);
    }
***************
*** 590,594 ****
  		interrupt(RS232, &Rstty_mess);	/* send message to tty task */
  	}
  }
! #endif
! 
--- 607,993 ----
  		interrupt(RS232, &Rstty_mess);	/* send message to tty task */
  	}
  }
! #if !USE_TTY
! 
! #define ISGLOBAL PRIVATE
! 
! /*===========================================================================*
!  *				in_char					     *
!  *===========================================================================*/
! ISGLOBAL in_char(tp, ch)
! register struct tty_struct *tp; /* struct of line number of char */
! int ch;				/* code for character that arrived */
! {
! /* A character has just been typed in.  Process, save, and echo it. */
! 
!   int mode;
! 
!   if (tp->tty_incount >= TTY_IN_BYTES) return;	/* no room, discard char */
!   mode = tp->tty_mode & (RAW | CBREAK);
!   if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
! 
!   /* Processing for COOKED and CBREAK mode contains special checks. */
!   if (mode == COOKED || mode == CBREAK) {
! 	/* Handle erase, kill and escape processing. */
! 	if (mode == COOKED) {
! 		/* First erase processing (rub out of last character). */
! 		if (ch == tp->tty_erase && tp->tty_escaped == NOT_ESCAPED) {
! 			if (chuck(tp) != -1) {	/* remove last char entered */
! 				echo(tp, '\b');	/* remove it from the screen */
! 				echo(tp, ' ');
! 				echo(tp, '\b');
! 			}
! 			return;
! 		}
! 
! 		/* Now do kill processing (remove current line). */
! 		if (ch == tp->tty_kill && tp->tty_escaped == NOT_ESCAPED) {
! 			while ( chuck(tp) == OK) /* keep looping */ ;
! 			echo(tp, tp->tty_kill);
! 			echo (tp, '\n');
! 			return;
! 		}
! 
! 		/* Handle EOT and the escape symbol (backslash). */
! 		if (tp->tty_escaped == NOT_ESCAPED) {
! 			/* Normal case: previous char was not backslash. */
! 			if (ch == '\\') {
! 				/* An escaped symbol has just been typed. */
! 				tp->tty_escaped = ESCAPED;
! 				echo(tp, ch);
! 				return;	/* do not store the '\' */
! 			}
! 			/* CTRL-D means end-of-file, unless it is escaped. It
! 			 * is stored in the text as MARKER, and counts as a
! 			 * line feed in terms of knowing whether a full line
! 			 * has been typed already.
! 			 */
! 			if (ch == tp->tty_eof) ch = MARKER;
! 		} else {
! 			/* Previous character was backslash. */
! 			tp->tty_escaped = NOT_ESCAPED;	/* turn escaping off */
! 			if (ch != tp->tty_erase && ch != tp->tty_kill &&
! 						   ch != tp->tty_eof) {
! 				/* Store the escape previously skipped over */
! 				*tp->tty_inhead++ = '\\';
! 				tp->tty_incount++;
! 				if (tp->tty_inhead ==
! 						&tp->tty_inqueue[TTY_IN_BYTES])
! 					tp->tty_inhead = tp->tty_inqueue;
! 			}
! 		}
! 	}
! 	/* Both COOKED and CBREAK modes come here; first map CR to LF. */
! 	if (ch == '\r' && (tp->tty_mode & CRMOD)) ch = '\n';
! 
! 	/* Check for interrupt and quit characters. */
! 	if (ch == tp->tty_intr) {
! 		sigchar(tp, SIGINT);
! 		return;
! 	}
! 	if (ch == tp->tty_quit) {
! 		sigchar(tp, SIGQUIT);
! 		return;
! 	}
! 
! 	/* Check for and process CTRL-S (terminal stop). */
! 	if (ch == tp->tty_xoff) {
! 		tp->tty_inhibited = STOPPED;
! 		return;
! 	}
! 
! 	/* Check for stopped output (any key including CTRL-Q) */
! 	if (tp->tty_inhibited == STOPPED) {
! 		tp->tty_inhibited = RUNNING;
! 		if ((*tp->tty_start)(tp))	/* resume output */
! 			finish(tp, tp->tty_cum);
! 		return;
! 	}
!   }
! 
!   /* All 3 modes come here. */
!   if (ch == '\n' || ch == MARKER) tp->tty_lfct++;	/* count line feeds */
!   *tp->tty_inhead++ = ch;	/* save the character in the input queue */
!   if (tp->tty_inhead == &tp->tty_inqueue[TTY_IN_BYTES])
! 	tp->tty_inhead = tp->tty_inqueue;	/* handle wraparound */
!   tp->tty_incount++;
!   echo(tp, ch);
! }
! 
! 
! /*===========================================================================*
!  *				echo					     *
!  *===========================================================================*/
! ISGLOBAL echo(tp, c)
! register struct tty_struct *tp;	/* terminal on which to echo */
! register char c;		/* character to echo */
! {
! /* Echo a character on the terminal. */
! /* If logged in on tty1, prepare to do NL to CR NL conversion:
!  * If RAW, dont do it
!  */
! 
! 
!   if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
!   if ( ((tp->tty_mode & (RAW | CBREAK)) == 0) &&
!     (tp->tty_mode & OCRMOD ) && (c == '\n')) 
! 	(*tp->tty_echo)(tp, '\r');
!   if (c != MARKER)
! 	  (*tp->tty_echo)(tp, c);
! }
! 
! 
! /*===========================================================================*
!  *				chuck					     *
!  *===========================================================================*/
! ISGLOBAL int chuck(tp)
! register struct tty_struct *tp;	/* from which tty should chars be removed */
! {
! /* Delete one character from the input queue.  Used for erase and kill. */
! 
!   char *prev;
! 
!   /* If input queue is empty, don't delete anything. */
!   if (tp->tty_incount == 0) return(-1);
! 
!   /* Don't delete '\n' or '\r'. */
!   prev = (tp->tty_inhead != tp->tty_inqueue ? tp->tty_inhead - 1 :
! 					     &tp->tty_inqueue[TTY_IN_BYTES-1]);
!   if (*prev == '\n' || *prev == '\r') return(-1);
!   tp->tty_inhead = prev;
!   tp->tty_incount--;
!   return(OK);			/* char erasure was possible */
! }
! 
! 
! /*===========================================================================*
!  *				do_read					     *
!  *===========================================================================*/
! ISGLOBAL do_read(tp, m_ptr)
! register struct tty_struct *tp;	/* pointer to tty struct */
! message *m_ptr;			/* pointer to message sent to the task */
! {
! /* A process wants to read from a terminal. */
! 
!   int code, caller;
! 
!   if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
! 	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L);
! 	return;
!   }
! 
!   /* Copy information from the message to the tty struct. */
!   tp->tty_incaller = m_ptr->m_source;
!   tp->tty_inproc = m_ptr->PROC_NR;
!   tp->tty_in_vir = m_ptr->ADDRESS;
!   tp->tty_inleft = m_ptr->COUNT;
! 
!   /* Try to get chars.  This call either gets enough, or gets nothing. */
!   code = rd_chars(tp);
!   caller = (int) tp->tty_inproc;
!   tty_reply(TASK_REPLY, m_ptr->m_source, caller, code, 0L, 0L);
! }
! 
! 
! /*===========================================================================*
!  *				rd_chars				     *
!  *===========================================================================*/
! ISGLOBAL int rd_chars(tp)
! register struct tty_struct *tp;	/* pointer to terminal to read from */
! {
! /* A process wants to read from a terminal.  First check if enough data is
!  * available. If so, pass it to the user.  If not, send FS a message telling
!  * it to suspend the user.  When enough data arrives later, the tty driver
!  * copies it to the user space directly and notifies FS with a message.
!  */
! 
!   int cooked, ct, user_ct, buf_ct, cum, enough, eot_seen;
!   vir_bytes in_vir, left;
!   phys_bytes user_phys, tty_phys;
!   char ch, *tty_ptr;
!   struct proc *rp;
!   extern phys_bytes umap();
! 
!   cooked = ( (tp->tty_mode & (RAW | CBREAK)) ? 0 : 1);	/* 1 iff COOKED mode */
!   if (tp->tty_incount == 0 || (cooked && tp->tty_lfct == 0)) return(SUSPEND);
!   rp = proc_addr(tp->tty_inproc);
!   in_vir = (vir_bytes) tp-> tty_in_vir;
!   left = (vir_bytes) tp->tty_inleft;
!   if ( (user_phys = umap(rp, D, in_vir, left)) == 0) return(E_BAD_ADDR);
!   tty_phys = umap(proc_addr(TTY), D, (vir_bytes) tp->tty_buf, (vir_bytes) sizeof(tp->tty_buf));
!   cum = 0;
!   enough = 0;
!   eot_seen = 0;
! 
!   /* The outer loop iterates on buffers, one buffer load per iteration. */
!   while (tp->tty_inleft > 0) {
! 	buf_ct = MIN(tp->tty_inleft, tp->tty_incount);
! 	buf_ct = MIN(buf_ct, sizeof(tp->tty_buf));
! 	ct = 0;
! 	tty_ptr = tp->tty_buf;
! 
! 	/* The inner loop fills one buffer. */
! 	while(buf_ct-- > 0) {
! 		ch = *tp->tty_intail++;
! 		if (tp->tty_intail == &tp->tty_inqueue[TTY_IN_BYTES])
! 			tp->tty_intail = tp->tty_inqueue;
! 		*tty_ptr++ = ch;
! 		ct++;
! 		if (ch == '\n' || ch == MARKER) {
! 			tp->tty_lfct--;
! 			if (cooked && ch == MARKER) eot_seen++;
! 			enough++;	/* exit loop */
! 			if (cooked) break;	/* only provide 1 line */
! 		}
! 	}
! 
! 	/* Copy one buffer to user space.  Be careful about CTRL-D.  In cooked
! 	 * mode it is not transmitted to user programs, and is not counted as
! 	 * a character as far as the count goes, but it does occupy space in 
! 	 * the driver's tables and must be counted there.
! 	 */
! 	user_ct = (eot_seen ? ct - 1 : ct);	/* bytes to copy to user */
! 	phys_copy(tty_phys, user_phys, (phys_bytes) user_ct);
! 	user_phys += user_ct;
! 	cum += user_ct;
! 	tp->tty_inleft -= ct;
! 	tp->tty_incount -= ct;
! 	if (tp->tty_incount == 0 || enough) break;
!   }
! 
!   tp->tty_inleft = 0;
!   return(cum);
! }
! 
! 
! /*===========================================================================*
!  *				finish					     *
!  *===========================================================================*/
! ISGLOBAL finish(tp, code)
! register struct tty_struct *tp;	/* pointer to tty struct */
! int code;			/* reply code */
! {
! /* A command has terminated (possibly due to DEL).  Tell caller. */
! 
!   int replyee, caller;
! 
!   tp->tty_outleft = 0;
! #ifdef ATARI_ST
!   (proc_addr(tp->tty_outproc))->p_physio = 0;	/* enable (un)shadowing */
! #endif
!   if (tp->tty_waiting == NOT_WAITING) return;
!   replyee = (int) tp->tty_otcaller;
!   caller = (int) tp->tty_outproc;
!   tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L);
!   tp->tty_waiting = NOT_WAITING;
! }
! 
! 
! /*===========================================================================*
!  *				do_write				     *
!  *===========================================================================*/
! ISGLOBAL do_write(tp, m_ptr)
! register struct tty_struct *tp;	/* pointer to tty struct */
! message *m_ptr;			/* pointer to message sent to the task */
! {
! /* A process wants to write on a terminal. */
! 
!   vir_bytes out_vir, out_left;
!   struct proc *rp;
!   extern phys_bytes umap();
! 
!   /* Copy message parameters to the tty structure. */
!   tp->tty_otcaller = m_ptr->m_source;
!   tp->tty_outproc = m_ptr->PROC_NR;
!   tp->tty_out_vir = m_ptr->ADDRESS;
!   tp->tty_outleft = m_ptr->COUNT;
!   tp->tty_waiting = WAITING;
!   tp->tty_cum = 0;
! 
!   /* Compute the physical address where the data is in user space. */
!   rp = proc_addr(tp->tty_outproc);
!   out_vir = (vir_bytes) tp->tty_out_vir;
!   out_left = (vir_bytes) tp->tty_outleft;
!   if ( (tp->tty_phys = umap(rp, D, out_vir, out_left)) == 0) {
! 	/* Buffer address provided by user is outside its address space. */
! 	tp->tty_cum = E_BAD_ADDR;
! 	tp->tty_outleft = 0;
!   }
! #ifdef ATARI_ST
!   rp->p_physio = 1;	/* disable (un)shadowing */
! #endif
! 
!   /* Copy characters from the user process to the terminal. */
!   if ((*tp->tty_start)(tp))	/* copy data to queue and start I/O */
! 	finish(tp, tp->tty_cum);
! }
! 
! /*===========================================================================*
!  *				do_setpgrp				     *
!  *===========================================================================*/
! ISGLOBAL do_setpgrp(tp, m_ptr)
! register struct tty_struct *tp; /* pointer to tty struct */
! message *m_ptr;			/* pointer to message sent to task */
! {
! /* A control process group has changed */
! 
!    tp->tty_pgrp = m_ptr->TTY_PGRP;
!    tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK, 0L, 0L);
! }
! 
! 
! /*===========================================================================*
!  *				do_cancel				     *
!  *===========================================================================*/
! ISGLOBAL do_cancel(tp, m_ptr)
! register struct tty_struct *tp;	/* pointer to tty_struct */
! message *m_ptr;			/* pointer to message sent to task */
! {
! /* A signal has been sent to a process that is hanging trying to read or write.
!  * The pending read or write must be finished off immediately.
!  */
! 
!   /* First check to see if the process is indeed hanging.  If it is not, don't
!    * reply (to avoid race conditions).
!    */
!   if (tp->tty_inleft == 0 && tp->tty_outleft == 0) return;
! 
!   /* Kill off input and output. */
!   tp->tty_inhead = tp->tty_inqueue;	/* discard all input */
!   tp->tty_intail = tp->tty_inqueue;
!   tp->tty_incount = 0;
!   tp->tty_lfct = 0;
!   tp->tty_inleft = 0;
!   tp->tty_outleft = 0;
!   tp->tty_waiting = NOT_WAITING;	/* don't send reply */
!   tp->tty_inhibited = RUNNING;
!   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR, 0L, 0L);
! }
! 
! 
! /*===========================================================================*
!  *				tty_reply				     *
!  *===========================================================================*/
! ISGLOBAL tty_reply(code, replyee, proc_nr, status, extra, other)
! int code;			/* TASK_REPLY or REVIVE */
! int replyee;			/* destination address for the reply */
! int proc_nr;			/* to whom should the reply go? */
! int status;			/* reply code */
! long extra;			/* extra value */
! long other;			/* used for IOCTL replies */
! {
! /* Send a reply to a process that wanted to read or write data. */
! 
!   message tty_mess;
! 
!   tty_mess.m_type = code;
!   tty_mess.REP_PROC_NR = proc_nr;
!   tty_mess.REP_STATUS = status;
!   tty_mess.TTY_FLAGS = extra;	/* used by IOCTL for flags (mode) */
!   tty_mess.TTY_SPEK = other;	/* used by IOCTL for erase and kill chars */
!   send(replyee, &tty_mess);
! }
! #endif /* USE_TTY */
! 
! #endif /* HAVERS232 */
! 
*** /usr/src/xminix/kernel/rs232.c	Thu Mar 12 10:19:32 1989
--- kernel/rs232.c	Thu Mar 27 00:37:18 1989
***************
*** 20,26 ****
  
  #define lbolt (realtime + lost_ticks)
  #define RS232_DRAIN (1*HZ)	/* time in ticks to drain */
! #define RS232_BREAK 5		/* ticks */
  PUBLIC int dbg_flag = 0;
  PRIVATE message	commes;		/* message used for console input chars */
  
--- 20,26 ----
  
  #define lbolt (realtime + lost_ticks)
  #define RS232_DRAIN (1*HZ)	/* time in ticks to drain */
! #define RS232_BREAK 12		/* ticks */
  PUBLIC int dbg_flag = 0;
  PRIVATE message	commes;		/* message used for console input chars */
  
***************
*** 31,37 ****
  #define COM_IN_SIZE 512
  PRIVATE  char	com_in_buffer[COM_IN_SIZE];
  
! PRIVATE int rs232_o_flag = 0;
  PRIVATE int Xmit_on = 0;
  
  extern struct tty_struct rstty_struct[];
--- 31,37 ----
  #define COM_IN_SIZE 512
  PRIVATE  char	com_in_buffer[COM_IN_SIZE];
  
! PUBLIC int rs232_o_flag = 0;
  PRIVATE int Xmit_on = 0;
  
  extern struct tty_struct rstty_struct[];
***************
*** 55,60 ****
--- 55,62 ----
  	int s;
  	int i;
  
+ if( dbg_flag != 0) 
+ printf("RS232 open flag=%d\n",rs232_o_flag);
  	if(rs232_o_flag ==0) {
  		rs232_o_flag = 1;
  		s = lock();
***************
*** 70,75 ****
--- 72,79 ----
  PRIVATE int close(tp)
  register struct tty_struct *tp;
  {
+ if( dbg_flag != 0) 
+ printf("RS232 close flag=%d -> 0\n",rs232_o_flag);
  	MFP->mf_imra &= ~( IA_RRDY | IA_TRDY | IA_TERR | IA_RERR);
  	rs232_o_flag = 0;
  	Xmit_on = 0;
***************
*** 159,167 ****
  		break;
  	}
  	return(OK);
!      case TCBAUD:  /* change the baud */
! 		set_timer(tp->tty_baud);
! 		break;
  		return(OK);
       case TCFLOW:  /* set TOS flow to arg 0 = off, 1=xon/off 2=rts/cts */
  		rs232ring.rtscts =  (int)m_ptr->TTY_SPEK;
--- 163,173 ----
  		break;
  	}
  	return(OK);
!      case TCBAUD:  /* change the baud internal*/
! 		set_timer(tp->tty_baud);
! 		return(OK);
!      case TCSETBAUD:  /* change the baud external*/
! 		set_timer( (int)(m_ptr->TTY_SPEK & 0xf));
  		return(OK);
       case TCFLOW:  /* set TOS flow to arg 0 = off, 1=xon/off 2=rts/cts */
  		rs232ring.rtscts =  (int)m_ptr->TTY_SPEK;
***************
*** 233,244 ****
  	if(rs232_o_flag == 0) {
  		rs232_o_flag++;
  		r = lock();
! 		rs232init();
  		restore(r);
  	}
  	if (tp->tty_outleft == 0)
  		return(1);
  	do {
  		if((r = rs232put( *(char*)tp->tty_phys)) == 0)
  			break;
  		tp->tty_phys++;
--- 239,254 ----
  	if(rs232_o_flag == 0) {
  		rs232_o_flag++;
  		r = lock();
! 		rs232init(tp);
  		restore(r);
  	}
  	if (tp->tty_outleft == 0)
  		return(1);
  	do {
+ 		if((tp->tty_mode & OCRMOD) &&  (*(char*)tp->tty_phys == '\n')) {
+ 			if((r = rs232put('\r')) == 0)
+ 				break;
+ 		}
  		if((r = rs232put( *(char*)tp->tty_phys)) == 0)
  			break;
  		tp->tty_phys++;
***************
*** 252,258 ****
  PRIVATE echo(tp, c)
  register struct tty_struct *tp;
  {
!   rs232put(c);
  }
  /*
   * This file contains the device_dependent part of the rs232 driver.
--- 262,268 ----
  PRIVATE echo(tp, c)
  register struct tty_struct *tp;
  {
! 	rs232put(c);
  }
  /*
   * This file contains the device_dependent part of the rs232 driver.
***************
*** 266,271 ****
--- 276,284 ----
  PUBLIC siaint(which)
  int which;	/* 0=rrdy, 1=rerr, 2=trdy, 3=terr */
  {
+ if( dbg_flag != 0) {
+   printf("SIAINT(%d)\n",which);
+ }
  	switch(which) {
  		case 1:	/* rerr */
  			printf("sia_rerr\n\r");
***************
*** 349,355 ****
  	MFP->mf_tsr = 0;
  		tp->tty_inhead = tp->tty_inqueue;
  		tp->tty_intail = tp->tty_inqueue;
! 		tp->tty_mode = CRMOD | XTABS | ECHO ;
  		tp->tty_erase = ERASE_CHAR;
  		tp->tty_kill  = KILL_CHAR;
  		tp->tty_intr  = INTR_CHAR;
--- 362,368 ----
  	MFP->mf_tsr = 0;
  		tp->tty_inhead = tp->tty_inqueue;
  		tp->tty_intail = tp->tty_inqueue;
! 		tp->tty_mode = CRMOD | XTABS /* | ECHO */;
  		tp->tty_erase = ERASE_CHAR;
  		tp->tty_kill  = KILL_CHAR;
  		tp->tty_intr  = INTR_CHAR;
***************
*** 407,412 ****
--- 420,428 ----
  	int clock;
  	int clocka;
  
+ if( dbg_flag != 0) {
+   printf("SET_TIMER(%d)\n",index);
+ }
  	clock = MFP->mf_tcdcr & 0x70;
  	for(;;) {
  		clocka = MFP->mf_tcdcr & 0x70;
*** /usr/src/xminix/kernel/../h/sgtty.h	Thu Jan 22 22:17:18 1989
--- h/sgtty.h	Thu Mar 26 20:49:46 1989
***************
*** 21,30 ****
  /* every one thinks XTABS is 06000 but only 1 bit is needed:
   */
  #define XTABS	     0004000	/* do tab expansion */
! #define RAW	     0000040	/* enable raw mode */
! #define IN_CANON     0001000	/* when off, no special processing on input */
!                                 /* the VEOF is how many inchars to wakeup on*/
! #define CRMOD	     0000020	/* map lf to cr + lf */
  /* the following is a magic cookie, the same name and value with termio.h */
  #define ECHO	     0000010	/* echo input */
  #define CBREAK	     0000002	/* enable cbreak mode */
--- 21,31 ----
  /* every one thinks XTABS is 06000 but only 1 bit is needed:
   */
  #define XTABS	     0004000	/* do tab expansion */
! #define IN_CANON     0001000	/* when off, no special processing on input */
!                                 /* the VEOF is how many inchars to wakeup on*/
! #define RAW	     0000040	/* enable raw mode */
! #define CRMOD	     0000020	/* map lf to cr + lf INPUT */
! #define OCRMOD	     0000001	/* map lf to cr + lf OUTPUT */
  /* the following is a magic cookie, the same name and value with termio.h */
  #define ECHO	     0000010	/* echo input */
  #define CBREAK	     0000002	/* enable cbreak mode */
***************
*** 32,39 ****
  /* when IN_CANON is OFF, then we will interpret additional bits for special
   * processing
   */
- #define SPECIAL_0    0000040
- #define SPECIAL_1    0000100
  
  #define TIOCGETP (('t'<<8) | 8)
  #define TIOCSETP (('t'<<8) | 9)
--- 33,38 ----
***************
*** 79,84 ****
--- 78,84 ----
  #define	FIONREAD	(TC_RS232|36)
  #define	TCGETRS	(TC_RS232|37)
  #define	TCSETDTR (TC_RS232|38) /* |rts|dtr| each 2 bits: 01=off 10=on */
+ #define	TCSETBAUD (TC_RS232|39)	/* set only baud rate - external */
  #define	TCBAUD	(TC_RS232|99)	/* used by rstty.c internally */
  #endif