[comp.os.minix] Yet another TTY driver, part 2 of 3

evans@ditsyda.oz (Bruce Evans) (01/02/89)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 3)."
# Contents:  console.c.cdif rs232.c
# Wrapped by sys@besplex on Mon Jan  2 04:34:25 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'console.c.cdif' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'console.c.cdif'\"
else
echo shar: Extracting \"'console.c.cdif'\" \(13395 characters\)
sed "s/^X//" >'console.c.cdif' <<'END_OF_FILE'
X*** orig/console.c	Thu Oct 20 06:04:19 1988
X--- console.c	Mon Jan  2 03:07:19 1989
X***************
X*** 55,57 ****
X  #define CURSOR            14	/* 6845's cursor register */
X! #define LINE_CMP	0x18	/* EGA line compare register */
X  
X--- 55,57 ----
X  #define CURSOR            14	/* 6845's cursor register */
X! #define CURSOR_SHAPE      15	/* block cursor for MDA/HGC/CGA/EGA/VGA... */
X  
X***************
X*** 77,80 ****
X  
X  /* Global variables used by the console driver. */
X- PUBLIC  message keybd_mess;	/* message used for console input chars */
X  PUBLIC int vid_mask;		/* 037777 for color (16K) or 07777 for mono */
X--- 77,82 ----
X  
X+ #define kb_addr(n)        (&kb_lines[0])
X+ #define KB_IBUFSIZE       16	/* size of keyboard input buffer */
X+ 
X  /* Global variables used by the console driver. */
X  PUBLIC int vid_mask;		/* 037777 for color (16K) or 07777 for mono */
X***************
X*** 82,83 ****
X--- 84,87 ----
X  PUBLIC int blank_color = 0x0700; /* display code for blank */
X+ 
X+ /* Private variables used by the console driver. */
X  PRIVATE vid_retrace;		/* how many characters to display per burst */
X***************
X*** 89,90 ****
X--- 93,111 ----
X  
X+ /* Keyboard structure, 1 per console. */
X+ struct kb_s
X+ {
X+   int minor;		/* minor number of this line (base 0) */
X+ 
X+   char *ibuf;		/* start of input buffer */
X+   char *ibufend;	/* end of input buffer */
X+   char *iptr;		/* next free spot in input buffer */
X+ 
X+   char ibuf1[KB_IBUFSIZE+1];	/* 1st input buffer, guard at end */
X+   char ibuf2[KB_IBUFSIZE+1];	/* 2nd input buffer (for swapping) */
X+ };
X+ 
X+ PRIVATE struct kb_s kb_lines[NR_CONS];
X+ PRIVATE int one_con_attribute;	/* current attribute byte << 8 */
X+ 
X+ 
X  /*===========================================================================*
X***************
X*** 96,99 ****
X  
X!   int val, code, k, raw_bit;
X!   char stopc;
X  
X--- 117,120 ----
X  
X!   int val, code, k;
X!   register struct kb_s *kb;
X  
X***************
X*** 126,131 ****
X  	/* A key has been released. */
X! 	if (k != 29 && k != 42 && k != 54 && k != 56 && k != 58 && k != 69) {
X! 		port_out(INT_CTL, ENABLE);	/* re-enable interrupts */
X  	 	return;		/* don't call tty_task() */
X- 	}
X    } else {
X--- 147,150 ----
X  	/* A key has been released. */
X! 	if (k != 29 && k != 42 && k != 54 && k != 56 && k != 58 && k != 69)
X  	 	return;		/* don't call tty_task() */
X    } else {
X***************
X*** 137,143 ****
X  	 */
X! 	raw_bit = tty_struct[CONSOLE].tty_mode & RAW;
X! 	stopc = tty_struct[CONSOLE].tty_xoff;
X! 	if (raw_bit == 0 && control && code == CTRL_S && stopc == XOFF_CHAR) {
X  		tty_struct[CONSOLE].tty_inhibited = STOPPED;
X- 		port_out(INT_CTL, ENABLE);
X  		return;
X--- 156,161 ----
X  	 */
X! 	if (!(tty_struct[CONSOLE].tty_mode & RAW) &&
X! 	    control && code == CTRL_S &&
X! 	    tty_struct[CONSOLE].tty_xoff == XOFF_CHAR) {
X  		tty_struct[CONSOLE].tty_inhibited = STOPPED;
X  		return;
X***************
X*** 146,169 ****
X  
X!   /* Check for CTRL-ALT-DEL, and if found, reboot the computer. */
X!   if (control && alt && code == DEL_CODE) reboot();	/* CTRL-ALT-DEL */
X! 
X!   /* Store the character in memory so the task can get at it later.
X!    * tty_driver_buf[0] is the current count, and tty_driver_buf[2] is the
X!    * maximum allowed to be stored.
X!    */
X!   if ( (k = tty_buf_count(tty_driver_buf)) < tty_buf_max(tty_driver_buf)) {
X! 	/* There is room to store this character; do it. */
X! 	k = k + k;			/* each entry contains two bytes */
X! 	tty_driver_buf[k+4] = code;	/* store the scan code */
X! 	tty_driver_buf[k+5] = CONSOLE;	/* tell which line it came from */
X! 	tty_buf_count(tty_driver_buf)++;		/* increment counter */
X! 
X! 	/* Build and send the interrupt message. */
X! 	keybd_mess.m_type = TTY_CHAR_INT;
X! 	keybd_mess.ADDRESS = tty_driver_buf;
X! 	interrupt(TTY, &keybd_mess);	/* send a message to the tty task */
X!   } else {
X! 	/* Too many characters have been buffered.  Discard excess. */
X! 	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X    }
X  }
X--- 164,173 ----
X  
X!   /* Store the character in memory so the task can get at it later. */
X!   kb = kb_addr(-NR_CONS);
X!   *kb->iptr = code;
X!   if (kb->iptr < kb->ibufend) {
X! 	tty_events += EVENT_THRESHOLD;
X! 	++kb->iptr;
X    }
X+   /* Else discard if it doesn't fit. */
X  }
X***************
X*** 171,172 ****
X--- 175,211 ----
X  
X+ /*==========================================================================*
X+  *				kb_read					    *
X+  *==========================================================================*/
X+ PUBLIC int kb_read( minor, bufindirect, odoneindirect )
X+ int minor;
X+ char **bufindirect;
X+ unsigned char *odoneindirect;
X+ {
X+ /* Swap the keyboard input buffers, giving the old one to TTY. */
X+ 
X+   register char *ibuf;
X+   register struct kb_s *kb;
X+   int nread;
X+   int old_state;
X+ 
X+   kb = kb_addr(minor);
X+   *odoneindirect = FALSE;
X+   if (kb->iptr == (ibuf = kb->ibuf))
X+ 	return 0;
X+   *bufindirect = ibuf;
X+   old_state = lock();
X+   nread = kb->iptr - ibuf;
X+   tty_events -= nread * EVENT_THRESHOLD;
X+   if (ibuf == kb->ibuf1)
X+ 	ibuf = kb->ibuf2;
X+   else
X+ 	ibuf = kb->ibuf1;
X+   kb->ibufend = ibuf + KB_IBUFSIZE;
X+   kb->iptr = ibuf;
X+   restore(old_state);
X+   kb->ibuf = ibuf;
X+   return nread;
X+ }
X+ 
X+ 
X  /*===========================================================================*
X***************
X*** 174,176 ****
X   *===========================================================================*/
X! PRIVATE console(tp)
X  register struct tty_struct *tp;	/* tells which terminal is to be used */
X--- 213,215 ----
X   *===========================================================================*/
X! PUBLIC console(tp)
X  register struct tty_struct *tp;	/* tells which terminal is to be used */
X***************
X*** 182,208 ****
X  
X-   extern char get_byte();
X    int count;
X!   char c;
X!   unsigned segment, offset, offset1;
X  
X!   /* Loop over the user bytes one at a time, outputting each one. */
X!   segment = (tp->tty_phys >> 4) & WORD_MASK;
X!   offset = tp->tty_phys & OFF_MASK;
X!   offset1 = offset;
X!   count = 0;
X  
X!   while (tp->tty_outleft > 0 && tp->tty_inhibited == RUNNING) {
X! 	c = get_byte(segment, offset);	/* fetch 1 byte from user space */
X! 	out_char(tp, c);	/* write 1 byte to terminal */
X! 	offset++;		/* advance one character in user buffer */
X! 	tp->tty_outleft--;	/* decrement count */
X!   }
X!   flush(tp);			/* clear out the pending characters */
X  
X!   /* Update terminal data structure. */
X!   count = offset - offset1;	/* # characters printed */
X!   tp->tty_phys += count;	/* advance physical data pointer */
X!   tp->tty_cum += count;		/* number of characters printed */
X  
X!   /* If all data has been copied to the terminal, send the reply. */
X    if (tp->tty_outleft == 0) finish(tp, tp->tty_cum);
X--- 221,258 ----
X  
X    int count;
X!   int remaining;
X!   register char *tbuf;
X  
X!   /* Check quickly for nothing to do, so this can be called often without
X!    * unmodular tests elsewhere.
X!    */
X!   if ( (remaining = tp->tty_outleft) == 0 || tp->tty_inhibited == STOPPED)
X! 	return;
X  
X!   /* Copy the user bytes to tty_buf for decent addressing. Loop over the
X!    * copies, since the user buffer may be much larger than tty_buf.
X!    */
X!   do {
X! 	if (remaining > sizeof tty_buf) remaining = sizeof tty_buf;
X! 	phys_copy(tp->tty_phys, tty_bphys, (phys_bytes) remaining);
X! 	tbuf = tty_buf;
X  
X! 	/* Output each byte of the copy to the screen. */
X! 	do
X! 		out_char(tp, *tbuf++);	/* part of this should be in-line */
X! 	while (--remaining != 0 && tp->tty_inhibited == RUNNING);
X  
X! 	/* Update terminal data structure. */
X! 	count = tbuf - tty_buf;		/* # characters printed */
X! 	tp->tty_phys += count;		/* advance physical data pointer */
X! 	tp->tty_cum += count;		/* number of characters printed */
X! 	tp->tty_outleft -= count;
X! 	if (remaining != 0) break;	/* inhibited while in progress */
X!   }
X!   while ( (remaining = tp->tty_outleft) != 0 && tp->tty_inhibited == RUNNING);
X!   flush(tp);			/* transfer anything buffered to the screen */
X! 
X!   /* If output was not inhibited early, send the appropiate completion reply.
X!    * Otherwise, let TTY handle suspension.
X!    */
X    if (tp->tty_outleft == 0) finish(tp, tp->tty_cum);
X***************
X*** 283,285 ****
X  		if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
X! 		tp->tty_ramqueue[tp->tty_rwords++]=tp->tty_attribute|(c&BYTE);
X  		tp->tty_column++;	/* next column */
X--- 333,335 ----
X  		if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
X! 		tp->tty_ramqueue[tp->tty_rwords++]=one_con_attribute|(c&BYTE);
X  		tp->tty_column++;	/* next column */
X***************
X*** 504,506 ****
X  		value = tp->tty_esc_parmv[0];
X! 		attr = tp->tty_attribute;
X  		switch (c) {
X--- 554,556 ----
X  		value = tp->tty_esc_parmv[0];
X! 		attr = one_con_attribute;
X  		switch (c) {
X***************
X*** 610,615 ****
X  				if (color)
X! 	 				tp->tty_attribute = /* red fg */
X  					 	(attr & 0xf0ff) | 0x0400;
X  				else
X! 		 			tp->tty_attribute |= 0x0800; /* inten*/
X   				break;
X--- 660,665 ----
X  				if (color)
X! 	 				one_con_attribute = /* red fg */
X  					 	(attr & 0xf0ff) | 0x0400;
X  				else
X! 		 			one_con_attribute |= 0x0800; /* inten*/
X   				break;
X***************
X*** 618,623 ****
X  				if (color)
X! 					tp->tty_attribute = /* blue fg */
X  					 (attr & 0xf0ff) | 0x0100;
X  				else
X! 					tp->tty_attribute = /* ul */
X  					 (attr & 0x8900);
X--- 668,673 ----
X  				if (color)
X! 					one_con_attribute = /* blue fg */
X  					 (attr & 0xf0ff) | 0x0100;
X  				else
X! 					one_con_attribute = /* ul */
X  					 (attr & 0x8900);
X***************
X*** 627,632 ****
X  				if (color) /* can't blink color */
X! 					tp->tty_attribute = /* magenta fg */
X  					 (attr & 0xf0ff) | 0x0500;
X  				else
X! 		 			tp->tty_attribute |= /* blink */
X  					 0x8000;
X--- 677,682 ----
X  				if (color) /* can't blink color */
X! 					one_con_attribute = /* magenta fg */
X  					 (attr & 0xf0ff) | 0x0500;
X  				else
X! 		 			one_con_attribute |= /* blink */
X  					 0x8000;
X***************
X*** 636,638 ****
X  				if (color)
X! 	 				tp->tty_attribute = 
X  					 ((attr & 0xf000) >> 4) |
X--- 686,688 ----
X  				if (color)
X! 	 				one_con_attribute = 
X  					 ((attr & 0xf000) >> 4) |
X***************
X*** 640,645 ****
X  				else if ((attr & 0x7000) == 0)
X! 					tp->tty_attribute =
X  					 (attr & 0x8800) | 0x7000;
X  				else
X! 					tp->tty_attribute =
X  					 (attr & 0x8800) | 0x0700;
X--- 690,695 ----
X  				else if ((attr & 0x7000) == 0)
X! 					one_con_attribute =
X  					 (attr & 0x8800) | 0x7000;
X  				else
X! 					one_con_attribute =
X  					 (attr & 0x8800) | 0x0700;
X***************
X*** 648,650 ****
X   			    default: if (value >= 30 && value <= 37) {
X! 					tp->tty_attribute = 
X  					 (attr & 0xf0ff) |
X--- 698,700 ----
X   			    default: if (value >= 30 && value <= 37) {
X! 					one_con_attribute = 
X  					 (attr & 0xf0ff) |
X***************
X*** 655,657 ****
X  				} else if (value >= 40 && value <= 47) {
X! 					tp->tty_attribute = 
X  					 (attr & 0x0fff) |
X--- 705,707 ----
X  				} else if (value >= 40 && value <= 47) {
X! 					one_con_attribute = 
X  					 (attr & 0x0fff) |
X***************
X*** 662,664 ****
X  				} else
X! 	 				tp->tty_attribute = blank_color;
X    				break;
X--- 712,714 ----
X  				} else
X! 	 				one_con_attribute = blank_color;
X    				break;
X***************
X*** 854,864 ****
X  /*===========================================================================*
X!  *				tty_init				     *
X   *===========================================================================*/
X! PUBLIC tty_init()
X  {
X! /* Initialize the tty tables. */
X  
X!   register struct tty_struct *tp;
X  
X    /* Set initial values. */
X    caps_off = 1;
X--- 904,926 ----
X  /*===========================================================================*
X!  *				con_init				     *
X   *===========================================================================*/
X! PUBLIC con_init(minor)
X! int minor;
X  {
X! /* Initialize the console tables. */
X  
X!   register struct kb_s *kb;
X  
X+   kb = kb_addr(minor) /*= &kb_lines[minor] */;
X+ 
X+   /* Record minor number. */
X+   kb->minor = minor;
X+ 
X+   /* Set up input queue. */
X+   kb->iptr = kb->ibuf = kb->ibuf1;
X+   kb->ibufend = kb->ibuf1 + KB_IBUFSIZE;
X+   kb->iptr = kb->ibuf1;
X+ 
X    /* Set initial values. */
X+   one_con_attribute = BLANK;
X    caps_off = 1;
X***************
X*** 870,887 ****
X  
X-   for (tp = &tty_struct[0]; tp < &tty_struct[NR_CONS]; tp++) {
X- 	tp->tty_inhead = tp->tty_inqueue;
X- 	tp->tty_intail = tp->tty_inqueue;
X- 	tp->tty_mode = CRMOD | XTABS | ECHO;
X- 	tp->tty_devstart = console;
X- 	tp->tty_makebreak = TWO_INTS;
X- 	tp->tty_attribute = BLANK;
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-   }
X- 
X    if (color) {
X--- 932,933 ----
X***************
X*** 902,905 ****
X    }
X!   tty_buf_max(tty_driver_buf) = MAX_OVERRUN;	/* set up limit on keyboard buffering*/
X!   set_6845(CUR_SIZE, 31);		/* set cursor shape */
X    set_6845(VID_ORG, 0);			/* use page 0 of video ram */
X--- 948,951 ----
X    }
X! 
X!   set_6845(CUR_SIZE, CURSOR_SHAPE);	/* set cursor shape */
X    set_6845(VID_ORG, 0);			/* use page 0 of video ram */
X***************
X*** 924,925 ****
X--- 970,974 ----
X    }
X+ 
X+   set_leds();			/* don't accept BIOS state */
X+   enable_irq(KEYBOARD_IRQ);	/* safe now everything initialised! */
X  }
END_OF_FILE
if test 13395 -ne `wc -c <'console.c.cdif'`; then
    echo shar: \"'console.c.cdif'\" unpacked with wrong size!
fi
# end of 'console.c.cdif'
fi
if test -f 'rs232.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rs232.c'\"
else
echo shar: Extracting \"'rs232.c'\" \(19504 characters\)
sed "s/^X//" >'rs232.c' <<'END_OF_FILE'
X/*==========================================================================*
X *		rs232.c - serial driver for 8250 and 16450 UARTs 	    *
X *==========================================================================*/
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/sgtty.h"
X#include "const.h"
X#include "tty.h"
X
X/* Switches */
X/*#define NO_HANDSHAKE		/* don't require CTS for output */
X
X/* 8250 constants */
X#define DEF_BAUD             4800	/* default baud rate */
X#define UART_FREQ         115200L	/* timer frequency */
X
X/* Interrupt enable bits */
X#define IE_RECEIVER_READY       1
X#define IE_TRANSMITTER_READY    2
X#define IE_LINE_STATUS_CHANGE   4
X#define IE_MODEM_STATUS_CHANGE  8
X
X/* Interrupt status bits */
X#define IS_MODEM_STATUS_CHANGE  0
X#define IS_TRANSMITTER_READY    2
X#define IS_RECEIVER_READY       4
X#define IS_LINE_STATUS_CHANGE   6
X
X/* Line control bits */
X#define LC_NO_PARITY            0
X#define LC_DATA_BITS            3
X#define LC_ODD_PARITY           8
X#define LC_EVEN_PARITY       0x18
X#define LC_ADDRESS_DIVISOR   0x80
X#define LC_STOP_BITS_SHIFT      2
X
X#define DATA_BITS_SHIFT         8	/* amount data bits shifted in mode */
X
X/* Line status bits */
X#define LS_OVERRUN_ERR          2
X#define LS_PARITY_ERR           4
X#define LS_FRAMING_ERR          8
X#define LS_BREAK_INTERRUPT   0x10
X#define LS_TRANSMITTER_READY 0x20
X
X/* Modem control bits */
X#define MC_DTR                  1
X#define MC_RTS                  2
X#define MC_OUT2                 8	/* required for PC & AT interrupts */
X
X/* Modem status bits */
X#define MS_CTS               0x10
X
X/*
X  Input buffer watermarks.
X  The external device is asked to stop sending when the buffer
X  exactly reaches high water, or when TTY requests it.
X  TTY is also notified directly (rather than at a later clock tick) when
X  this watermark is reached.
X  A lower threshold could be used, but the buffer size and wakeup intervals
X  are chosen so the watermark shouldn't be hit at reasonable baud rates,
X  so this is unnecessary - the throttle is applied when TTY's buffers
X  get too full.
X  The low watermark is invisibly 0 since the buffer is always emptied all
X  at once.
X*/
X#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
X
X/*
X  Macros to handle flow control.
X  Interrupts must be off when they are used.
X  Time is critical - already the function call for port_out() is annoying.
X  If port_out() can be done in-line, tests to avoid it can be dropped.
X  istart() tells external device we are ready by raising RTS.
X  istop() tells external device we are not ready by dropping RTS.
X  DTR is kept high all the time (it probably should be raised by open and
X  dropped by close of the device).
X  OUT2 is also kept high all the time.
X*/
X#define istart( rs ) \
X  (port_out( (rs)->modem_ctl_port, MC_OUT2 | MC_RTS | MC_DTR ), \
X   (rs)->idevready = TRUE)
X#define istop( rs ) \
X  (port_out( (rs)->modem_ctl_port, MC_OUT2 | MC_DTR ), (rs)->idevready = FALSE)
X
X/*
X  Macro to tell if device is ready.
X  Don't require DSR, since modems drop this to indicate the line is not
X  ready even when the modem itself is ready.
X*/
X#ifdef NO_HANDSHAKE
X# define devready( rs ) ODEVREADY
X#else
X# define devready( rs ) (inportb( rs->modem_status_port ) & MS_CTS)
X#endif
X
X/* Macro to tell if transmitter is ready */
X#define txready( rs ) (inportb( rs->line_status_port ) & LS_TRANSMITTER_READY)
X
X/* Types */
Xtypedef char bool_t;		/* boolean */
Xtypedef unsigned port_t;	/* hardware port */
X
X/* RS232 device structure, one per device */
Xstruct rs232_s
X{
X  int minor;			/* minor number of this line (base 0) */
X
X  bool_t idevready;		/* nonzero if we are ready to receive (RTS) */
X  bool_t ittyready;		/* nonzero if TTY is ready to receive */
X  char *ibuf;			/* start of input buffer */
X  char *ibufend;		/* end of input buffer */
X  char *ihighwater;		/* threshold in input buffer */
X  char *iptr;			/* next free spot in input buffer */
X
X  unsigned char ostate;		/* combination of flags: */
X#define ODEVREADY MS_CTS	/* external device hardware ready (CTS) */
X#define ODONE          1	/* output completed (< output enable bits) */
X#define OQUEUED     0x20	/* output buffer not empty */
X#define ORAW           2	/* raw mode for xoff disable (< enab. bits) */
X#define OSWREADY    0x40	/* external device software ready (no xoff) */
X#define OWAKEUP        4	/* tty_wakeup() pending (asm code only) */
X#if (ODEVREADY | 0x63) == 0x63
X#error				/* bits are not unique */
X#endif
X  unsigned char oxoff;		/* char to stop output */
X  char *obufend;		/* end of output buffer */
X  char *optr;			/* next char to output */
X
X  port_t xmit_port;		/* i/o ports */
X  port_t recv_port;
X  port_t div_low_port;
X  port_t div_hi_port;
X  port_t int_enab_port;
X  port_t int_id_port;
X  port_t line_ctl_port;
X  port_t modem_ctl_port;
X  port_t line_status_port;
X  port_t modem_status_port;
X
X  unsigned char lstatus;	/* last line status */
X  unsigned framing_errors;	/* error counts (no reporting yet) */
X  unsigned overrun_errors;
X  unsigned parity_errors;
X  unsigned break_interrupts;
X
X  char ibuf1[RS_IBUFSIZE+1];	/* 1st input buffer, guard at end */
X  char ibuf2[RS_IBUFSIZE+1];	/* 2nd input buffer (for swapping) */
X};
X
X/*
X  Table and macro to translate an RS232 minor device number to its
X  struct rs232_s pointer.
X*/
Xstruct rs232_s *p_rs_addr[NR_RS_LINES];
X#define rs_addr( minor ) (p_rs_addr[minor])
X
X/* 8250 base addresses */
XPRIVATE port_t addr_8250[] =
X{
X  0x3F8,			/* COM1: (line 0); COM3 might be at 0x3E8 */
X  0x2F8,			/* COM2: (line 1); COM4 might be at 0x2E8 */
X};
X
XPUBLIC struct rs232_s rs_lines[NR_RS_LINES];
X
XFORWARD void inint();
X#ifndef inportb
Xextern unsigned inportb();	/* port_in() with faster interface */
X#endif
XFORWARD void lineint();
XFORWARD void modemint();
XFORWARD void outint();
X
X
X/* High level routines (should only be called by TTY) */
X
X/*==========================================================================*
X *				rs_config			 	    *
X *==========================================================================*/
XPRIVATE	int rs_config( minor, in_baud, out_baud, parity, stop_bits,
X                       data_bits, mode )
Xint minor;			/* which rs line */
Xint in_baud;			/* input speed: 110, 300, 1200, etc */
Xint out_baud;			/* output speed: 110, 300, 1200, etc */
Xint parity;			/* LC_something */
Xint stop_bits;			/* 2 (110 baud) or 1 (other speeds) */
Xint data_bits;			/* 5, 6, 7, or 8 */
Xint mode;
X{
X  /*
X    Set various line control parameters for RS232 I/O.
X    If DataBits == 5 and StopBits == 2, 8250 will generate 1.5 stop bits
X    The 8250 can't handle split speed, but we have propagated both speeds
X    anyway for the benefit of future UART chips.
X  */
X
X  int divisor;
X  int line_controls;
X  int old_state;
X  register struct rs232_s *rs;
X
X  rs = rs_addr( minor );
X
X  /* Precalculate divisor and line_controls for reduced latency */
X  if ( in_baud < 50 )
X    in_baud = DEF_BAUD;		/* prevent divide overflow */
X  if ( out_baud < 50 )
X    out_baud = DEF_BAUD;	/* prevent divide overflow */
X  divisor = (int) (UART_FREQ / in_baud);	/* 8250 can't hack 2 speeds */
X  line_controls = parity | ((stop_bits - 1) << LC_STOP_BITS_SHIFT) |
X                  (data_bits - 5);
X
X  /*
X    Lock out interrupts while changing rate. The interrupt status register
X    is going to be hidden by the div_low register. Without being able
X    to access it, the input interrupt routine hang on the RECEIVER_READY
X    interrupt status bit. Output is merely messed up.
X  */
X  old_state = lock();
X
X  /* Select the baud rate divisor registers and change the rate */
X  port_out( rs->line_ctl_port, LC_ADDRESS_DIVISOR );
X  port_out( rs->div_low_port, divisor );
X  port_out( rs->div_hi_port, divisor >> 8 );
X
X  /* Change the line controls and reselect the usual registers */
X  port_out( rs->line_ctl_port, line_controls );
X
X  if ( mode & RAW )
X    rs->ostate |= ORAW;
X  else
X    rs->ostate &= ~ORAW;
X  restore( old_state );
X  return ((out_baud/100) << 8) | (in_baud/100);
X}
X
X
X/*==========================================================================*
X *				rs_ioctl			 	    *
X *==========================================================================*/
XPUBLIC int rs_ioctl( minor, mode, speeds )
Xint minor;			/* which rs line number (>= 0) */
Xint mode;			/* sgtty.h sg_mode word */
Xint speeds;			/* low byte is input speed, next is output */
X{
X  /* Set the UART parameters */
X
X  int data_bits;
X  int in_baud;
X  int out_baud;
X  int parity;
X  int stop_bits;
X
X  in_baud = 100 * (speeds & BYTE);
X  if ( in_baud == 100 )
X    in_baud = 110;
X  out_baud = 100 * ((speeds >> 8) & BYTE);
X  if ( out_baud == 100 )
X    out_baud = 110;
X  parity = LC_NO_PARITY;
X  if ( mode & ODDP )
X    parity = LC_ODD_PARITY;
X  if ( mode & EVENP )
X    parity = LC_EVEN_PARITY;
X  stop_bits = in_baud == 110 ? 2 : 1;	/* not quite cricket */
X  data_bits = 5 + ((mode >> DATA_BITS_SHIFT) & LC_DATA_BITS);
X  return rs_config( minor, in_baud, out_baud, parity, stop_bits, data_bits,
X                    mode );
X}
X
X
X/*==========================================================================*
X *				rs_inhibit				    * 
X *==========================================================================*/
XPUBLIC void rs_inhibit( minor, inhibit )
Xint minor;
Xbool_t inhibit;
X{
X  /* Update inhibition state to keep in sync with TTY */
X
X  register struct rs232_s *rs;
X  int old_state;
X
X  rs = rs_addr( minor );
X  old_state = lock();
X  if ( inhibit )
X    rs->ostate &= ~OSWREADY;
X  else
X    rs->ostate |= OSWREADY;
X  restore( old_state );
X}
X
X
X/*==========================================================================*
X *				rs_init					    * 
X *==========================================================================*/
XPUBLIC int rs_init( minor )
Xint minor;
X{
X  register struct rs232_s *rs;
X  int this_8250;
X
X  rs = rs_addr( minor ) = &rs_lines[minor];
X
X  /* Record minor number */
X  rs->minor = minor;
X
X  /* Set up input queue */
X  rs->iptr = rs->ibuf = rs->ibuf1;
X  rs->ibufend = rs->ibuf1 + RS_IBUFSIZE;
X  rs->ihighwater = rs->ibuf1 + RS_IHIGHWATER;
X  rs->ittyready = TRUE;		/* idevready set to TRUE by istart() */
X
X  /* Precalculate port numbers for speed. Magic numbers in the code (once). */
X  this_8250 = addr_8250[minor];
X  rs->xmit_port = this_8250 + 0;
X  rs->recv_port = this_8250 + 0;
X  rs->div_low_port = this_8250 + 0;
X  rs->div_hi_port = this_8250 + 1;
X  rs->int_enab_port = this_8250 + 1;
X  rs->int_id_port = this_8250 + 2;
X  rs->line_ctl_port = this_8250 + 3;
X  rs->modem_ctl_port = this_8250 + 4;
X  rs->line_status_port = this_8250 + 5;
X  rs->modem_status_port = this_8250 + 6;
X
X  /* Set up output queue */
X  rs->ostate = devready( rs ) | ORAW | OSWREADY;
X
X  /* Stop external device while we initialize the hardware */
X  istop( rs );
X
X  /*
X     Clear any leftover interrupts.
X     Modem status was just done in devready().
X     Output int will be generated by enabling interrupts.
X   */
X  inportb( rs->recv_port );
X  inportb( rs->line_status_port );
X
X  /* Enable interrupts for both interrupt controller and device */
X  if ( minor & 1 )		/* COM2 on IRQ3 */
X    enable_irq( SECONDARY_IRQ );
X  else				/* COM1 on IRQ4 */
X    enable_irq( RS232_IRQ );
X  port_out( rs->int_enab_port, IE_LINE_STATUS_CHANGE | IE_MODEM_STATUS_CHANGE
X                             | IE_RECEIVER_READY | IE_TRANSMITTER_READY );
X
X  /* Tell external device we are ready */
X  istart( rs );
X  return rs_config( minor, DEF_BAUD, DEF_BAUD, LC_NO_PARITY, 1, 8, RAW );
X}
X
X
X/*==========================================================================*
X *				rs_istop				    * 
X *==========================================================================*/
XPUBLIC void rs_istop( minor )
Xint minor;
X{
X  /*
X    TTY wants RS232 to stop input.
X    RS232 drops RTS but keeps accepting input till its buffer overflows.
X  */
X
X  register struct rs232_s * rs;
X  int old_state;
X
X  rs = rs_addr( minor );
X  old_state = lock();
X  rs->ittyready = FALSE;
X  istop( rs );
X  restore( old_state );
X}
X
X
X/*==========================================================================*
X *				rs_istart				    * 
X *==========================================================================*/
XPUBLIC void rs_istart( minor )
Xint minor;
X{
X  /* 
X    TTY is ready for another buffer full of input from RS232.
X    RS232 raises RTS unless its own buffer is already too full.
X  */
X
X  register struct rs232_s * rs;
X  int old_state;
X
X  rs = rs_addr( minor );
X  old_state = lock();
X  rs->ittyready = TRUE;
X  if ( rs->iptr < rs->ihighwater )
X    istart( rs );
X  restore( old_state );
X}
X
X
X/*==========================================================================*
X *				rs_ocancel				    * 
X *==========================================================================*/
XPUBLIC void rs_ocancel( minor )
Xint minor;
X{
X  /* Cancel pending output */
X
X  int old_state;
X  register struct rs232_s *rs;
X
X  old_state = lock();
X  rs = rs_addr( minor );
X  if ( rs->ostate & ODONE )
X    tty_events -= EVENT_THRESHOLD;
X  rs->ostate &= ~(ODONE | OQUEUED);
X  restore( old_state );
X}
X
X
X/*==========================================================================*
X *				rs_read					    * 
X *==========================================================================*/
XPUBLIC int rs_read( minor, bufindirect, odoneindirect )
Xint minor;
Xchar **bufindirect;
Xbool_t *odoneindirect;
X{
X  /* Swap the input buffers, giving the old one to TTY, and restart input */
X
X  register char *ibuf;
X  int nread;
X  int old_state;
X  register struct rs232_s *rs;
X  
X  rs = rs_addr( minor );
X  *odoneindirect = rs->ostate & ODONE;
X  if ( rs->iptr == (ibuf = rs->ibuf) )
X    return 0;
X  *bufindirect = ibuf;
X  old_state = lock();
X  nread = rs->iptr - ibuf;
X  tty_events -= nread;
X  if ( ibuf == rs->ibuf1 )
X    ibuf = rs->ibuf2;
X  else
X    ibuf = rs->ibuf1;
X  rs->ibufend = ibuf + RS_IBUFSIZE;
X  rs->ihighwater = ibuf + RS_IHIGHWATER;
X  rs->iptr = ibuf;
X  if ( !rs->idevready && rs->ittyready )
X    istart( rs );
X  restore( old_state );
X  rs->ibuf = ibuf;
X  return nread;
X}
X
X
X/*==========================================================================*
X *				rs_setc					    * 
X *==========================================================================*/
XPUBLIC void rs_setc( minor, xoff )
Xint minor;
Xint xoff;
X{
X  /* RS232 needs to know the xoff character */
X
X  rs_addr( minor )->oxoff = xoff;
X}
X
X
X/*==========================================================================*
X *				rs_write				    * 
X *==========================================================================*/
XPUBLIC void rs_write( minor, buf, nbytes )
Xint minor;
Xchar *buf;
Xint nbytes;
X{
X  /*
X    Tell RS232 about the buffer to be written and start output.
X    Previous output must have completed.
X  */
X
X  int old_state;
X  register struct rs232_s *rs;
X
X  rs = rs_addr( minor );
X  old_state = lock();
X  rs->obufend = (rs->optr = buf) + nbytes;
X  rs->ostate |= OQUEUED;
X  if ( txready( rs ) )
X    outint( rs );
X  restore( old_state );
X}
X
X
X/* Low level (interrupt) routines */
X
X#ifdef C_RS232_INT_HANDLERS
X/*==========================================================================*
X *				rs232_1handler				    * 
X *==========================================================================*/
XPUBLIC void rs232_1handler()
X{
X  /* Interrupt hander for IRQ4. Only 1 line (usually COM1) should use it. */
X
X#if NR_RS_LINES > 0
X  register struct rs232_s *rs;
X
X  rs = &rs_lines[0];
X  while ( TRUE )
X  {
X    /*
X      Loop to pick up ALL pending interrupts for device.
X      This usually just wastes time unless the hardware has a buffer
X      (and then we have to worry about being stuck in the loop too long).
X      Unfortunately, some serial cards lock up without this.
X    */
X    switch ( inportb( rs->int_id_port ) )
X    {
X    case IS_RECEIVER_READY:
X      inint( rs );
X      continue;
X    case IS_TRANSMITTER_READY:
X      outint( rs );
X      continue;
X    case IS_MODEM_STATUS_CHANGE:
X      modemint( rs );
X      continue;
X    case IS_LINE_STATUS_CHANGE:
X      lineint( rs );
X      continue;
X    }
X    return;
X  }
X#endif
X}
X
X
X/*==========================================================================*
X *				rs232_2handler				    * 
X *==========================================================================*/
XPUBLIC void rs232_2handler()
X{
X  /* Interrupt hander for IRQ3. Only 1 line (usually COM2) should use it. */
X
X#if NR_RS_LINES > 1
X  register struct rs232_s *rs;
X
X  rs = &rs_lines[1];
X  while ( TRUE )
X  {
X    switch ( inportb( rs->int_id_port ) )
X    {
X    case IS_RECEIVER_READY:
X      inint( rs );
X      continue;
X    case IS_TRANSMITTER_READY:
X      outint( rs );
X      continue;
X    case IS_MODEM_STATUS_CHANGE:
X      modemint( rs );
X      continue;
X    case IS_LINE_STATUS_CHANGE:
X      lineint( rs );
X      continue;
X    }
X    return;
X  }
X#endif
X}
X
X
X/*==========================================================================*
X *				inint					    * 
X *==========================================================================*/
XPRIVATE void inint( rs )
Xregister struct rs232_s *rs;
X{
X  /*
X    Read the data which just arrived.
X    If it is the oxoff char, clear OSWREADY, else if OSWREADY was clear,
X    set it and restart output (any char does this, not just xon).
X    Put data in the buffer if room, otherwise discard it.
X    Set a flag for the clock interrupt handler to eventually notify TTY.
X  */
X
X  if ( rs->ostate & ORAW )
X    *rs->iptr = inportb( rs->recv_port );
X  else if ( (*rs->iptr = inportb( rs->recv_port )) == rs->oxoff )
X    rs->ostate &= ~OSWREADY;
X  else if ( !(rs->ostate & OSWREADY) )
X  {
X    rs->ostate |= OSWREADY;
X    if ( txready( rs ) )
X      outint( rs );
X  }
X  if ( rs->iptr < rs->ibufend )
X  {
X    ++tty_events;
X    if ( ++rs->iptr == rs->ihighwater )
X      istop( rs );
X  }
X}
X
X
X/*==========================================================================*
X *				lineint					    * 
X *==========================================================================*/
XPRIVATE void lineint( rs )
Xregister struct rs232_s *rs;
X{
X  /* Check for and record errors */
X
X  if ( (rs->lstatus = inportb( rs->line_status_port )) & LS_FRAMING_ERR )
X    ++rs->framing_errors;
X  if ( rs->lstatus & LS_OVERRUN_ERR )
X    ++rs->overrun_errors;
X  if ( rs->lstatus & LS_PARITY_ERR )
X    ++rs->parity_errors;
X  if ( rs->lstatus & LS_BREAK_INTERRUPT )
X    ++rs->break_interrupts;
X}
X
X
X/*==========================================================================*
X *				modemint				    * 
X *==========================================================================*/
XPRIVATE void modemint( rs )
Xregister struct rs232_s *rs;
X{
X  /*
X    Get possibly new device-ready status, and clear ODEVREADY if necessary.
X    If the device just became ready, restart output.
X  */
X
X  if ( !devready( rs ) )
X    rs->ostate &= ~ODEVREADY;
X  else if ( !(rs->ostate & ODEVREADY) )
X  {
X    rs->ostate |= ODEVREADY;
X    if ( txready( rs ) )
X      outint( rs );
X  }
X}
X#endif /* C_RS232_INT_HANDLERS (except outint is used from high level) */
X
X
X/*==========================================================================*
X *				outint					    * 
X *==========================================================================*/
XPRIVATE void outint( rs )
Xregister struct rs232_s *rs;
X{
X  /*
X    If there is output to do and everything is ready, do it (local device
X    is known ready).
X    Interrupt TTY to indicate completion.
X  */
X
X  if ( rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY) )  /* maybe ORAW */
X  {
X    port_out( rs->xmit_port, *rs->optr );
X    if ( ++rs->optr >= rs->obufend )
X    {
X      tty_events += EVENT_THRESHOLD;
X      rs->ostate ^= (ODONE | OQUEUED);	/* ODONE on, OQUEUED off */
X      tty_wakeup();
X    }
X  }
X}
END_OF_FILE
if test 19504 -ne `wc -c <'rs232.c'`; then
    echo shar: \"'rs232.c'\" unpacked with wrong size!
fi
# end of 'rs232.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

Bruce Evans
evans@ditsyda.oz.au
D