[comp.os.minix] V1.3c posting #13 - kernel

ast@cs.vu.nl (Andy Tanenbaum) (09/28/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'rs232.c.new'
sed 's/^X//' > 'rs232.c.new' << '+ END-OF-FILE ''rs232.c.new'
X/* Now begins the code and data for the device RS232 drivers. */
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 "glo.h"
X#include "proc.h"
X#include "tty.h"
X
X/* Definitions used by the RS232 driver. */
X#define	RS_BUF_SIZE		 256	/* output buffer per serial line */
X#define PRIMARY                0x3F8	/* I/O port of primary RS232 */
X#define SECONDARY              0x2F8	/* I/O port of secondary RS232 */
X#define SPARE                     16	/* leave room in buffer for echoes */
X#define THRESHOLD                 20	/* # chars to accumulate before msg */
X
X/* Constants relating to the 8250. */
X#define	RS232_RATE_DIVISOR	   0	/* address of baud rate divisor reg */
X#define	RS232_TRANSMIT_HOLDING	   0	/* address of transmitter holding reg*/
X#define	RS232_RECEIVER_DATA_REG	   0	/* address of receiver data register */
X#define	RS232_INTERRUPTS	   1	/* address of interrupt enable reg */
X#define	RS232_INTERRUPT_ID_REG	   2	/* address of interrupt id register */
X#define	RS232_LINE_CONTROL	   3	/* address of line control register */
X#define	RS232_MODEM_CONTROL	   4	/* address of modem control register */
X#define	RS232_LINE_STATUS	   5	/* address of line status register */
X#define	RS232_MODEM_STATUS	   6	/* address of modem status register */
X#define	LINE_CONTROLS		0x0B	/* odd parity,1 stop bit,8 data bits */
X#define	MODEM_CONTROLS		0x0B	/* RTS & DTR */
X#define	ADDRESS_DIVISOR		0x80	/* value to address divisor */
X#define HOLDING_REG_EMPTY       0x20	/* transmitter holding reg empty */
X#define	RS232_INTERRUPT_CLASSES	0x03	/* receiver Data Ready & xmt empty */
X#define	UART_FREQ  	     115200L	/* UART timer frequency */
X#define DEF_BAUD                1200	/* default baud rate */
X
X/* Line control setting related constants. */
X#define ODD			   0
X#define	EVEN			   1
X#define NONE			  -1
X#define	PARITY_ON_OFF		0x08	/* position of parity bit in line reg*/
X#define	PARITY_TYPE_SHIFT	   4	/* shift count for parity_type bit */
X#define	STOP_BITS_SHIFT		   2	/* shift count for # stop_bits */
X#define DATA_LEN                   8	/* how much to shift sg_mode for len */
X
X/* RS232 interrupt types. */
X#define MODEM_STATUS            0x00	/* UART modem status change */
X#define TRANSMITTER_READY	0x02	/* transmitter ready to accept data */
X#define RECEIVER_READY		0x04	/* data received interrupt */
X#define LINE_STATUS             0x06	/* UART line status change */
X#define INT_TYPE_MASK		0x06	/* mask to mask out interrupt type */
X#define	INT_PENDING		0x01	/* position of interrupt-pending bit */
X
X/* Status register values. */
X#define DATA_REGISTER_EMPTY	0x20	/* mask to see if data reg is empty */
X#define DATA_RECEIVED		0x01	/* mask to see if data has arrived */
X
X/* Global variables used by the RS232 driver. */
XPUBLIC message rs232_rd_mess;		/* used when chars arrive from tty */
XPUBLIC message rs232_wt_mess;		/* used when output to tty done */
XPUBLIC int flush_flag;			/* indicates chars in tty_driver_buf */
XPRIVATE int first_rs_write_int_seen = FALSE;
X
XPRIVATE struct rs_struct{
X  int rs_base;			/* 0x3F8 for primary, 0x2F8 secondary*/
X  int rs_busy;			/* line is idle or not */
X  int rs_left;			/* # chars left in buffer to output */
X  char *rs_next;		/* pointer to next char to output */
X  char rs_buf[RS_BUF_SIZE];	/* output buffer */
X} rs_struct[NR_RS_LINES];
X
X
X/*===========================================================================*
X *				rs232				 	     *
X *===========================================================================*/
XPUBLIC rs232(unit)
Xint unit;				/* which unit caused the interrupt */
X{
X/* When an RS232 interrupt occurs, mpx88.s catches it and calls rs232().
X * Because more than one interrupt condition can occur at the same
X * time, the conditions are presented in the interrupt-identification
X * register in priority order, we have to keep scanning until the 
X * interrupt-pending bit goes down.  Only one communications port is really
X * supported here because the other vector is used by the Ethernet.
X */
X
X  int interrupt_type, t, old_state, val;
X  struct rs_struct *rs;
X
X  old_state = lock();
X  rs = &rs_struct[unit - NR_CONS];
X  while (TRUE) {
X	port_in(rs->rs_base + RS232_INTERRUPT_ID_REG, &interrupt_type); 
X	if ((interrupt_type & INT_PENDING) == 1) break;	/* 1 = no interrupt */
X	t = interrupt_type & INT_TYPE_MASK;
X	switch(t) {
X	    case RECEIVER_READY:	/* a character has arrived */
X		rs_read_int(unit);
X		break;
X
X	    case TRANSMITTER_READY:	/* a character has been output */
X		rs_write_int(unit);
X		break;
X
X	    case LINE_STATUS:		/* line status event, (disabled) */
X		port_in(rs_struct[unit-1].rs_base + RS232_LINE_STATUS, &val);
X		printf("RS 232 line status event %x\n", val);
X		break;
X
X	    case MODEM_STATUS:		/* modem status event, (disabled) */
X		port_in(rs_struct[unit-1].rs_base + RS232_MODEM_STATUS, &val);
X		printf("RS 232 modem status event %x\n", val);
X		break;
X	}
X  }
X  restore(old_state);
X}
X
X
X/*===========================================================================*
X *				rs_read_int			 	     *
X *===========================================================================*/
XPRIVATE	rs_read_int(line)
Xint line;
X{
X  int val, k, base;
X
X  base = rs_struct[line - NR_CONS].rs_base;
X
X  /* Fetch the character from the RS232 hardware. */
X  port_in(base + RS232_RECEIVER_DATA_REG, &val);
X
X  /* Store the character in memory so the task can get at it later */
X  if ((k = tty_driver_buf[0]) < tty_driver_buf[1]) {
X	/* There is room to store this character, do it */
X	k = k + k;			/* each entry contains two bytes */
X	tty_driver_buf[k + 2] = val;	/* store the ascii code */
X	tty_driver_buf[k + 3] = line;	/* tell wich line it came from */ 
X	tty_driver_buf[0]++;		/* increment counter */
X
X	if (tty_driver_buf[0] < THRESHOLD) {
X		/* Don't send message.  Just accumulate.  Let clock do it. */
X		port_out(INT_CTL, ENABLE);
X		flush_flag++;
X		return;
X	}
X	rs_flush();			/* send TTY task a message */
X  } else {
X	/* Too many character have been buffered. Discard excess */
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X  }
X}
X
X
X/*===========================================================================*
X *				rs_flush	  		 	     *
X *===========================================================================*/
XPUBLIC rs_flush()
X{
X/* Flush the tty_driver_buf by sending a message to TTY.  This procedure can
X * be triggered locally, when a character arrives, or by the clock task.
X */
X
X  /* Build and send the interrupt message */ 
X  flush_flag = 0;
X  if (tty_driver_buf[0] == 0) return;	/* nothing to flush */
X  rs232_rd_mess.m_type = TTY_CHAR_INT;
X  rs232_rd_mess.ADDRESS = tty_driver_buf;
X  interrupt(TTY, &rs232_rd_mess);	/* send a message to the tty task */
X}
X
X
X/*===========================================================================*
X *				rs_write_int	  		 	     *
X *===========================================================================*/
XPRIVATE	rs_write_int(line)
Xint line;
X{
X/* An output ready interrupt has occurred, or a write has been done to an idle
X * line.  In both cases, start the output.
X */
X
X  int val;
X  struct tty_struct *tp;
X  struct rs_struct *rs;
X
X  if (first_rs_write_int_seen == FALSE) {
X	first_rs_write_int_seen = TRUE;
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X	return;
X  }
X
X  /* On the XT and clones, check for spurious write-completed interrupts. */
X  rs = &rs_struct[line - NR_CONS];
X  port_in(rs->rs_base + RS232_LINE_STATUS, &val);
X  if ( (val & HOLDING_REG_EMPTY) == 0) {
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X	return;
X  }
X
X  /* If there are more characters in rs_buf, output the next one. */
X  if (rs->rs_left > 0) {
X	rs_feed(rs);			/* output the next char in rs_buf */
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X	return;
X  }
X
X  /* The current rs_buf is finished.  See if the complete user buf is done. */
X  tp = &tty_struct[line];
X  rs->rs_busy = FALSE;
X  rs->rs_next = &rs->rs_buf[0];
X  if (tp->tty_outleft > 0) {
X	serial_out(tp);			/* copy the next chunk to rs_buf */
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X	return;
X  }
X
X  /* The current output buffer is finished.  Send a message to the tty task. */
X  if (tp->tty_waiting == WAITING) {
X	rs232_wt_mess.m_type = TTY_O_DONE;	/* build the message */
X	rs232_wt_mess.ADDRESS = tty_driver_buf;	/* pro forma */
X	rs232_wt_mess.TTY_LINE = line;	/* which line is finished */
X	tp->tty_waiting = COMPLETED;	/* mark this line as done */
X	output_done++;			/* # of RS232 lines now completed */
X	interrupt(TTY, &rs232_wt_mess);	/* send the message to the tty task */
X  } else {
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X  }
X}
X
X
X/*===========================================================================*
X *				rs_feed		  		 	     *
X *===========================================================================*/
XPRIVATE rs_feed(rs)
Xstruct rs_struct *rs;			/* which line */
X{
X/* If there is more output queued, output the next character. */
X
X  char byte;
X
X  if (rs->rs_left > 0) {
X	byte = *rs->rs_next;
X	port_out(rs->rs_base + RS232_TRANSMIT_HOLDING, (int) byte);
X	rs->rs_next++;
X	rs->rs_left--;			/* one char done */
X  }
X}
X
X
X/*===========================================================================*
X *				start_rs232				     * 
X *===========================================================================*/
XPRIVATE	start_rs232(tp)
Xstruct tty_struct *tp;			/* which tty */
X{
X  int old_state;
X
X  old_state = lock();
X  serial_out(tp);
X  restore(old_state);
X}	
X
X
X/*===========================================================================*
X *				serial_out				     * 
X *===========================================================================*/
XPRIVATE	serial_out(tp)
Xregister struct tty_struct *tp;	/* tells which terminal is to be used */
X{
X/* Copy as much data as possible to the output queue, then start I/O if
X * necessary.
X */
X  int bytes, line;
X  char c, *limit;
X  unsigned short segment, offset, offset1;
X  register struct rs_struct *rs;
X  extern char get_byte();
X
X  if (tp->tty_inhibited != RUNNING) return;
X
X  line = tp - &tty_struct[0];		/* line is index into tty_struct */
X  rs = &rs_struct[line - NR_CONS];	/* 0 to NR_CONS - 1 are consoles */
X	
X  /* Copy bytes from user space to rs_buf. */
X  limit = &rs->rs_buf[RS_BUF_SIZE - SPARE];
X  segment = (tp->tty_phys >> 4) & WORD_MASK;
X  offset = tp->tty_phys & OFF_MASK;
X  offset1 = offset;
X
X  /* While there is still data to output and there is still room in buf, copy*/
X  while (tp->tty_outleft > 0 && rs->rs_next + rs->rs_left < limit) {
X	c = get_byte(segment, offset);	/* fetch 1 byte */
X	offset++;
X	tp->tty_outleft--;
X	if (c < ' ') {
X		rs_expand(tp, rs, c);	/* insert the char in rs_buf */
X	} else {
X		*(rs->rs_next + rs->rs_left) = c;	/* avoid proc call */
X		rs->rs_left++;
X		tp->tty_column++;
X	}
X  }
X
X  bytes = offset - offset1;		/* does not include '\r' or tab exp */
X  tp->tty_cum += bytes;			/* update cumulative total */
X  tp->tty_phys += bytes;		/* next time, take different bytes */
X
X  if (!rs->rs_busy) {			/* is the line idle? */
X	rs->rs_busy = TRUE;		/* if so, mark it as busy */
X	rs_feed(rs);			/* and start it going */
X  }
X}
X
X
X/*===========================================================================*
X *				rs_out_char				     *
X *===========================================================================*/
XPRIVATE rs_out_char(tp, c)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xchar c;				/* character to be output */
X{
X/* Output a character on an RS232 line. */
X
X  int line, old_state;
X  register struct rs_struct *rs;
X
X  /* See if there is room to store a character, and if so, do it. */
X  old_state = lock();
X  line = tp - tty_struct;
X  rs = &rs_struct[line - NR_CONS];
X  if (rs->rs_next + rs->rs_left == &rs->rs_buf[RS_BUF_SIZE]) return;  /*full */
X  rs_expand(tp, rs, c);
X
X  if (!rs->rs_busy) {		/* if terminal line is idle, start it */
X	rs->rs_busy = TRUE;
X	rs_feed(rs);
X  }
X  restore(old_state);
X}
X
X
X/*===========================================================================*
X *				rs_expand				     *
X *===========================================================================*/
XPRIVATE rs_expand(tp, rs, c)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xregister struct rs_struct *rs;	/* pointer to rs struct */
Xchar c;				/* character to be output */
X{
X/* Some characters output to RS-232 lines need special processing, such as
X * tab expansion and LF to CR+CF mapping.  These things are done here.
X */
X
X  int mode, count, count1;
X  char *deposit;		/* where to deposit the next character */
X
X  mode = tp->tty_mode;
X  deposit = rs->rs_next + rs->rs_left;
X
X  switch(c) {
X	case '\b':
X		tp->tty_column -= 2;	/* it is incremented later */
X		break;
X
X	case '\r':
X		tp->tty_column = -1;	/* it is incremented below */
X		break;
X
X	case '\n':
X		/* Check to see if LF has to be mapped to CR + LF. */
X		if (mode & CRMOD) {
X			*deposit++ = '\r';
X			rs->rs_left++;
X			tp->tty_column = -1;
X		}
X		break;
X
X	case '\t':
X	 	count = 8 - (tp->tty_column % 8);	/* # spaces */
X		count1 = count;
X		if ((mode & XTABS) == XTABS) {
X			/* Tabs must be expanded. */
X			while (count1--) *deposit++ = ' ';
X			rs->rs_left += count;
X			tp->tty_column += count;
X			return;
X		} else {
X			/* Tabs are sent to the terminal hardware. */
X			tp->tty_column += count - 1;
X		}
X  }
X
X  /* Output character and update counters. */
X  *deposit = c;			/* copy character to rs_buf */
X  rs->rs_left++;		/* there is one more character to print */
X  tp->tty_column++;		/* update column */
X}
X
X
X/*===========================================================================*
X *				tty_o_done				     *
X *===========================================================================*/
XPRIVATE int tty_o_done()
X{
X/* A write request on an RS232 line has completed.  Send FS a message. */
X
X  int replyee, caller, old_state;
X  struct tty_struct *tp;
X
X  /* See if any of the RS232 lines are complete.  Send at most one message. */
X  old_state = lock();
X  for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; tp++){
X	if (tp->tty_waiting == COMPLETED) {
X		replyee = (int) tp->tty_otcaller;
X		caller = (int) tp->tty_outproc;
X		tty_reply(REVIVE, replyee, caller, tp->tty_cum, 0L, 0L);
X		tp->tty_waiting = NOT_WAITING;
X		output_done--;
X		restore(old_state);
X		return(1);
X	}
X  }
X  restore(old_state);
X  return(0);
X}
X
X/*===========================================================================*
X *				rs_sig					     * 
X *===========================================================================*/
XPRIVATE rs_sig(tp)
Xstruct tty_struct *tp;
X{
X/* Called when a DEL character is typed.  It resets the output. */
X
X  int line;
X  struct rs_struct *rs;
X
X  line = tp - tty_struct;
X  rs = &rs_struct[line - NR_CONS];
X  rs->rs_left = 0;
X  rs->rs_busy = 0;
X  rs->rs_next = &rs->rs_buf[0];
X}
X
X
X/*===========================================================================*
X *				init_rs232				     * 
X *===========================================================================*/
XPRIVATE	init_rs232()
X{
X  register struct tty_struct *tp;
X  register struct rs_struct *rs;
X  int line;
X
X  for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; 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_mode = RAW | BITS8;
X	tp->tty_devstart = start_rs232;
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_makebreak = ONE_INT;	/* RS232 only interrupts once/char */
X  }
X
X#if NR_RS_LINES > 0
X  rs_struct[0].rs_base = PRIMARY;
X#endif
X#if NR_RS_LINES > 1
X  rs_struct[1].rs_base = SECONDARY;
X#endif
X
X  for (rs = &rs_struct[0]; rs < &rs_struct[NR_RS_LINES]; rs++) {
X	line = rs - rs_struct + NR_CONS;
X	rs->rs_next = & rs->rs_buf[0];
X	rs->rs_left = 0;
X	rs->rs_busy = FALSE;
X	config_rs232(line, DEF_BAUD, DEF_BAUD, NONE, 1, 8);    /* set params */
X	port_out(rs->rs_base + RS232_MODEM_CONTROL, MODEM_CONTROLS);
X	port_out(rs->rs_base + RS232_INTERRUPTS, RS232_INTERRUPT_CLASSES);
X  }
X}
X
X
X/*===========================================================================*
X *				set_uart			 	     *
X *===========================================================================*/
XPRIVATE set_uart(line, mode, speeds)
Xint line;			/* which line number (>= NR_CONS) */
Xint mode;			/* sgtty.h sg_mode word */
Xint speeds;			/* low byte is input speed, next is output */
X{
X/* Set the UART parameters. */
X  int in_baud, out_baud, parity, stop_bits, data_bits;
X
X  in_baud = 100 * (speeds & BYTE);
X  if (in_baud == 100) in_baud = 110;
X  out_baud = 100 * ((speeds >> 8) & BYTE);
X  if (out_baud == 100) out_baud = 110;
X  parity = NONE;
X  if (mode & ODDP) parity = ODD;
X  if (mode & EVENP) parity = EVEN;
X  stop_bits = (in_baud == 110 ? 2 : 1);		/* not quite cricket */
X  data_bits = 5 + ((mode >> DATA_LEN) & 03);
X  config_rs232(line, in_baud, out_baud, parity, stop_bits, data_bits);
X}
X
X
X/*===========================================================================*
X *				config_rs232			 	     *
X *===========================================================================*/
XPRIVATE	config_rs232(line, in_baud, out_baud, parity, stop_bits, data_bits)
Xint line;			/* which tty */
Xint in_baud;			/* input speed: 110, 300, 1200, etc. */
Xint out_baud;			/* output speed: 110, 300, 1200, etc. */
Xint parity;			/* EVEN, ODD, or NONE */
Xint stop_bits;			/* 2 (110 baud) or 1 (other speeds) */
Xint data_bits;			/* 5, 6, 7, or 8 */
X{
X/* Set various line control parameters for RS232 I/O.
X * If DataBits == 5 and StopBits == 2, UART 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 line_controls = 0, base, freq;
X
X  base = rs_struct[line - NR_CONS].rs_base;
X
X  /* First tell line control register to address baud rate divisor */
X  port_out(base + RS232_LINE_CONTROL, ADDRESS_DIVISOR);
X
X  /* Now set the baud rate. */
X  if (in_baud < 50) in_baud = DEF_BAUD;		/* prevent divide overflow */
X  if (out_baud < 50) out_baud = DEF_BAUD;	/* prevent divide overflow */
X  freq = (int) (UART_FREQ / in_baud);		/* UART can't hack 2 speeds  */
X  port_out(base + RS232_RATE_DIVISOR, freq & BYTE);
X  port_out(base + RS232_RATE_DIVISOR+1, (freq >> 8) & BYTE);
X  tty_struct[line].tty_speed = ((out_baud/100) << 8) | (in_baud/100);
X
X  /* Put parity_type bits in line_controls */
X  if (parity != NONE) {
X	line_controls |= PARITY_ON_OFF;
X	line_controls |= (parity << PARITY_TYPE_SHIFT);
X  }
X
X  /* Put #stop_bits bits in line_controls */
X  if (stop_bits == 1 || stop_bits == 2)
X	line_controls |= (stop_bits - 1) << STOP_BITS_SHIFT;
X
X  /* Put #data_bits bits in line_controls */
X  if (data_bits >=5 && data_bits <= 8)
X	line_controls |= (data_bits - 5);
X
X  port_out(base + RS232_LINE_CONTROL, line_controls);
X}
+ END-OF-FILE rs232.c.new
chmod 'u=rw,g=r,o=r' 'rs232.c.new'
set `wc -c 'rs232.c.new'`
count=$1
case $count in
18997)	:;;
*)	echo 'Bad character count in ''rs232.c.new' >&2
		echo 'Count should be 18997' >&2
esac
echo Extracting 'table.c.cdif'
sed 's/^X//' > 'table.c.cdif' << '+ END-OF-FILE ''table.c.cdif'
X*** /local/ast/minix/tape3b/kernel/table.c	Wed Jul 13 16:59:21 1988
X--- table.c	Tue Sep 27 08:51:20 1988
X***************
X*** 32,37 ****
X--- 32,38 ----
X  #define  EXTERN
X  #include "glo.h"
X  #include "proc.h"
X+ #include "tty.h"
X  
X  extern int sys_task(), clock_task(), mem_task(), floppy_task(),
X             winchester_task(), tty_task(), printer_task();
+ END-OF-FILE table.c.cdif
chmod 'u=rw,g=r,o=r' 'table.c.cdif'
set `wc -c 'table.c.cdif'`
count=$1
case $count in
356)	:;;
*)	echo 'Bad character count in ''table.c.cdif' >&2
		echo 'Count should be 356' >&2
esac
echo Extracting 'tty.c'
sed 's/^X//' > 'tty.c' << '+ END-OF-FILE ''tty.c'
X/* This file contains the terminal driver, both for the IBM console and regular
X * ASCII terminals.  It is split into two sections, a device-independent part
X * and a device-dependent part.  The device-independent part accepts
X * characters to be printed from programs and queues them in a standard way
X * for device-dependent output.  It also accepts input and queues it for
X * programs. This file contains 2 main entry points: tty_task() and keyboard().
X * When a key is struck on a terminal, an interrupt to an assembly language
X * routine is generated.  This routine saves the machine state and registers
X * and calls keyboard(), which enters the character in an internal table, and
X * then sends a message to the terminal task.  The main program of the terminal
X * task is tty_task(). It accepts not only messages about typed input, but
X * also requests to read and write from terminals, etc. 
X *
X * The device-dependent part interfaces with the IBM console and ASCII
X * terminals.  The IBM keyboard is unusual in that keystrokes yield key numbers
X * rather than ASCII codes, and furthermore, an interrupt is generated when a
X * key is depressed and again when it is released.  The IBM display is memory
X * mapped, so outputting characters such as line feed, backspace and bell are
X * tricky.
X *
X * The valid messages and their parameters are:
X *
X *   TTY_CHAR_INT: a character has been typed (character arrived interrupt)
X *   TTY_READ:     a process wants to read from a terminal
X *   TTY_WRITE:    a process wants to write on a terminal
X *   TTY_IOCTL:    a process wants to change a terminal's parameters
X *   TTY_SETPGRP:  indicate a change in a control terminal
X *   CANCEL:       terminate a previous incomplete system call immediately
X *
X *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
X * ---------------------------------------------------------------------------
X * | TTY_CHAR_INT|         |         |         |         |         |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_O_DONE  |minor dev|         |         |         |         |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_READ    |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_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 "glo.h"
X#include "proc.h"
X#include "tty.h"
X#include "ttymaps.h"
X
X/*===========================================================================*
X *				tty_task				     *
X *===========================================================================*/
XPUBLIC tty_task()
X{
X/* Main routine of the terminal task. */
X
X  message tty_mess;		/* buffer for all incoming messages */
X  register struct tty_struct *tp;
X
X  tty_init();			/* initialize */
X  init_rs232();
X
X  while (TRUE) {
X	receive(ANY, &tty_mess);
X	tp = &tty_struct[tty_mess.TTY_LINE];
X	switch(tty_mess.m_type) {
X	    case TTY_O_DONE:	/* same action as TTY_CHAR_INT */
X	    case TTY_CHAR_INT:	do_int(&tty_mess);		break;
X	    case TTY_READ:	do_read(tp, &tty_mess);		break;
X	    case TTY_WRITE:	do_write(tp, &tty_mess);	break;
X	    case TTY_IOCTL:	do_ioctl(tp, &tty_mess);	break;
X	    case TTY_SETPGRP:   do_setpgrp(tp, &tty_mess);	break;
X	    case CANCEL:	do_cancel(tp, &tty_mess);	break;
X	    default:		tty_reply(TASK_REPLY, tty_mess.m_source, 
X					tty_mess.PROC_NR, EINVAL, 0L, 0L);
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				do_int					     *
X *===========================================================================*/
XPRIVATE do_int(m_ptr)
Xmessage *m_ptr;
X{
X/* The TTY task can generate two kinds of interrupts:
X *	- a character has been typed on the console or an RS232 line
X *	- an RS232 line has completed a write request (on behalf of a user)
X * If either interrupt happens and the TTY task is idle, the task gets the
X * interrupt message immediately and processes it.  However, if the TTY
X * task is busy, a bit is set in 'busy_map' and the message pointer stored.
X * If multiple messages happen, the bit is only set once.  No input data is
X * lost even if this happens because all the input messages say is that there
X * is some input.  The actual input is in the tty_driver_buf array, so losing
X * a message just means that when the one interrupt-generated message is given
X * to the TTY task, it will find multiple characters in tty_driver_buf.
X *
X * The introduction of RS232 lines has complicated this situation somewhat. Now
X * a message can mean that some RS232 line has finished transmitting all the
X * output given to it.  If a character is typed at the instant an RS232 line
X * finishes, one of the two messages may be overwritten because MINIX only
X * provides single buffering for interrupt messages (in proc.c).To avoid losing
X * information, whenever an RS232 line finishes, the flag tty_waiting is set
X * to COMPLETED and kept that way until its completion is processed and a 
X * message sent to FS saying that output is done.  The number of RS232 lines in
X * COMPLETED state is kept in output_done, which is checked on each interrupt,
X * so that a lost TTY_O_DONE line completion interrupt will be quickly
X * recovered.
X *
X * In short, when this procedure is called, it can check for RS232 line done
X * by inspecting output_done and it can check for characters in the input
X * buffer by inspecting tty_driver_buf[0].  Thus losing a message to the TTY
X * task is not serious because the underlying conditions are explicitly checked
X * for on each interrupt.
X */
X
X  /* First check to see if any RS232 lines have completed. */
X  if (output_done > 0) {
X	/* If a message is sent to FS for RS232 done, don't process any input
X	 * characters now for fear of sending a second message to FS, which 
X	 * would be lost.
X	 */
X	if (tty_o_done()) {
X		return;
X	}
X  }
X  charint(m_ptr);			/* check for input characters */
X}
X
X
X/*===========================================================================*
X *				charint					     *
X *===========================================================================*/
XPRIVATE 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, old_state;
X  char *ptr, *copy_ptr, ch;
X  struct tty_struct *tp;
X
X  old_state = lock();
X  ptr = m_ptr->ADDRESS;		/* pointer to accumulated char array */
X  copy_ptr = tty_copy_buf;	/* ptr to shadow array where chars copied */
X  n = *ptr;			/* how many chars have been accumulated */
X  count = n;			/* save the character count */
X  n = n + n;			/* each char occupies 2 bytes */
X  ptr += 2;			/* skip count field at start of array */
X  while (n-- > 0)
X	*copy_ptr++ = *ptr++;	/* copy the array to safety */
X  ptr = m_ptr->ADDRESS;
X  *ptr = 0;			/* accumulation count set to 0 */
X  restore(old_state);
X
X  /* Loop on the accumulated characters, processing each in turn. */
X  if (count == 0) return;	/* on TTY_O_DONE interrupt, count might be 0 */
X  copy_ptr = tty_copy_buf;
X  while (count-- > 0) {
X	ch = *copy_ptr++;	/* get the character typed */
X	n = *copy_ptr++;	/* get the line number it came in on */
X	in_char(n, ch);		/* queue the char and echo it */
X
X	/* See if a previously blocked reader can now be satisfied. */
X	tp = &tty_struct[n];	/* pointer to struct for this character */
X	if (tp->tty_inleft > 0 ) {	/* does anybody want input? */
X		m = tp->tty_mode & (CBREAK | RAW);
X		if (tp->tty_lfct > 0 || (m != 0 && tp->tty_incount > 0)) {
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 */
Xchar ch;			/* scan 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, sig, scode, c;
X  int make_break();
X
X  scode = ch;			/* save the scan code */
X  tp = &tty_struct[line];	/* set 'tp' to point to proper struct */
X
X  /* Function keys are temporarily being used for debug dumps. */
X  if (line == 0 && ch >= F1 && ch <= F10) {	/* Check for function keys */
X	func_key(ch);		/* process function key */
X	return;
X  }
X  if (tp->tty_incount >= TTY_IN_BYTES) return;	/* no room, discard char */
X  mode = tp->tty_mode & (RAW | CBREAK);
X  if (tp->tty_makebreak == TWO_INTS) {
X	c = make_break(ch);	/* console give 2 ints/ch */
X	if (c == -1) return;
X	ch = c;
X  }
X  else
X	if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
X
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;
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;
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;	/* 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) {
X				ch = MARKER;
X				tp->tty_lfct++; /* counts as LF */
X			}
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 || ch == tp->tty_quit) {
X		sig = (ch == tp->tty_intr ? SIGINT : SIGQUIT);
X		sigchar(tp, sig);
X		return;
X	}
X
X	/* Check for and process CTRL-S (terminal stop). */
X	if (ch == tp->tty_xoff) {
X		tp->tty_inhibited = STOPPED;
X		return;
X	}
X
X	/* Check for and process CTRL-Q (terminal start). */
X	if (tp->tty_inhibited == STOPPED) {
X		tp->tty_inhibited = RUNNING;
X		(*tp->tty_devstart)(tp);	/* resume output */
X		return;
X	}
X  }
X
X  /* All 3 modes come here. */
X  if (ch == '\n') tp->tty_lfct++;	/* count line feeds */
X
X  /* The numeric pad generates ASCII escape sequences: ESC [ letter */
X  if (line == 0 && scode >= SCODE1 && scode <= SCODE2 && 
X		shift1 == 0 && shift2 == 0 && numlock == 0) {
X	/* This key is to generate a three-character escape sequence. */
X	*tp->tty_inhead++ = ESC; /* put ESC 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, 'E');
X	*tp->tty_inhead++ = BRACKET; /* put ESC 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, BRACKET);
X	ch = scode_map[scode-SCODE1];	/* generate the letter */
X  }
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}
X
X
X#ifdef i8088
X/*===========================================================================*
X *				make_break				     *
X *===========================================================================*/
XPRIVATE int make_break(ch)
Xchar ch;			/* scan code of key just struck or released */
X{
X/* This routine can handle keyboards that interrupt only on key depression,
X * as well as keyboards that interrupt on key depression and key release.
X * For efficiency, the interrupt routine filters out most key releases.
X */
X
X  int c, make, code;
X
X  c = ch & 0177;		/* high-order bit set on key release */
X  make = (ch & 0200 ? 0 : 1);	/* 1 when key depressed, 0 when key released */
X
X  if (alt && keyb_type == DUTCH_EXT) 
X	code = alt_c[c];
X  else 
X	code = (shift1 || shift2 ? sh[c] : unsh[c]);
X
X  if (control && c < TOP_ROW) code = sh[c];	/* CTRL-(top row) */
X  if (numlock && c > 70 && c < 0x56)
X	code = (shift1 || shift2 ? unsh[c] : sh[c]);
X
X  code &= BYTE;
X  if (code < 0200 || code >= 0206) {
X	/* Ordinary key, i.e. not shift, control, alt, etc. */
X	if (capslock)
X		if (code >= 'A' && code <= 'Z')
X			code += 'a' - 'A';
X		else if (code >= 'a' && code <= 'z')
X			code -= 'a' - 'A';
X	if (alt && keyb_type != DUTCH_EXT) code |= 0200;  /* alt ORs in 0200 */
X	if (control) code &= 037;
X	if (make == 0) code = -1;	/* key release */
X	return(code);
X  }
X
X  /* Table entries 0200 - 0206 denote special actions. */
X  switch(code - 0200) {
X    case 0:	shift1 = make;		break;	/* shift key on left */
X    case 1:	shift2 = make;		break;	/* shift key on right */
X    case 2:	control = make;		break;	/* control */
X    case 3:	alt = make;		break;	/* alt key */
X    case 4:	if (make && caps_off) {
X			capslock = 1 - capslock;
X			set_leds();
X		}
X		caps_off = 1 - make;
X		break;	/* caps lock */
X    case 5:	if (make && num_off) {
X			numlock  = 1 - numlock;
X			set_leds();
X		}
X		num_off = 1 - make;
X		break;	/* num lock */
X  }
X  return(-1);
X}
X#endif
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/* MARKER is meaningful only in cooked mode */
X  if (c != MARKER || tp->tty_mode & (CBREAK | RAW)) {
X	if (tp - tty_struct < NR_CONS)
X		out_char(tp, c);	/* echo to console */
X	else
X		rs_out_char(tp, c);	/* echo to RS232 line */
X  }
X  flush(tp);			/* force character out onto the screen */
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
X  if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
X	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
X	return;
X  }
X
X  /* 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 *===========================================================================*/
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
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, TTY_BUF_SIZE);
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, TTY_BUF_SIZE);
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 && cooked) {
X			tp->tty_lfct--;
X			if (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
X  tp->tty_inleft = 0;
X  return(cum);
X}
X
X
X/*===========================================================================*
X *				finish					     *
X *===========================================================================*/
XPUBLIC 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 line, result, replyee, caller;
X
X  tp->tty_rwords = 0;
X  tp->tty_outleft = 0;
X  if (tp->tty_waiting == NOT_WAITING) return;
X  line = tp - tty_struct;
X  result = (line < NR_CONS ? TASK_REPLY : REVIVE);
X  replyee = (int) tp->tty_otcaller;
X  caller = (int) tp->tty_outproc;
X  tty_reply(result, replyee, caller, code, 0L, 0L);
X  tp->tty_waiting = NOT_WAITING;
X}
X
X
X/*===========================================================================*
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  int caller,replyee;
X
X  /* If the slot is already in use, better return an error than mess it up. */
X  if (tp->tty_outleft > 0) {	/* if someone else is hanging, give up */
X	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L);
X	return;
X  }
X
X  /* Copy message parameters to the tty structure. */
X  tp->tty_otcaller = m_ptr->m_source;
X  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
X  /* Copy characters from the user process to the terminal. */
X  (*tp->tty_devstart)(tp);	/* copy data to queue and start I/O */
X
X  /* If output is for a bitmapped terminal as the IBM-PC console, the output-
X   * routine will return at once so there is no need to suspend the caller,
X   * on ascii terminals however, the call is suspended and later revived.
X   */
X  if (m_ptr->TTY_LINE != 0) {
X	caller = (int) tp->tty_outproc;
X	replyee = (int) tp->tty_otcaller;
X	tty_reply(TASK_REPLY, replyee, caller, SUSPEND, 0L, 0L);
X  }
X}
X
X
X/*===========================================================================*
X *				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;
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	tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE);	/* erase  */
X	tp->tty_kill  = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE);	/* kill  */
X	tp->tty_mode  = (int) m_ptr->TTY_FLAGS;	/* mode word */
X	if (m_ptr->TTY_SPEED != 0) tp->tty_speed = m_ptr->TTY_SPEED;
X	if (tp-tty_struct >= NR_CONS)
X		set_uart(tp - tty_struct, tp->tty_mode, tp->tty_speed);
X	break;
X
X     case TIOCSETC:
X	/* Set intr, quit, xon, xoff, eof (brk not used). */
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	erki  = (erase << 8) | kill;
X	flags = ( (long) tp->tty_speed << 16) | (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     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   tp->tty_pgrp = m_ptr->TTY_PGRP;
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  int mode;
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/output. */
X  mode = m_ptr->COUNT;
X  if (mode & R_BIT) {
X	/* Process was reading when killed.  Clean up input. */
X	tp->tty_inhead = tp->tty_inqueue;	/* discard all data */
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_inhibited = RUNNING;
X  }
X  if (mode & W_BIT) {
X	/* Process was writing when killed.  Clean up output. */
X	tp->tty_outleft = 0;
X	tp->tty_waiting = NOT_WAITING;	/* don't send reply */
X  }
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				tty_reply				     *
X *===========================================================================*/
XPUBLIC tty_reply(code, replyee, proc_nr, status, extra, other)
Xint code;			/* TASK_REPLY or REVIVE */
Xint replyee;			/* destination address for the reply */
Xint proc_nr;			/* to whom should the reply go? */
Xint status;			/* reply code */
Xlong extra;			/* extra value */
Xlong other;			/* used for IOCTL replies */
X{
X/* Send a reply to a process that wanted to read or write data. */
X
X  message tty_mess;
X
X  tty_mess.m_type = code;
X  tty_mess.REP_PROC_NR = proc_nr;
X  tty_mess.REP_STATUS = status;
X  tty_mess.TTY_FLAGS = extra;	/* used by IOCTL for flags (mode) */
X  tty_mess.TTY_SPEK = other;	/* used by IOCTL for erase and kill chars */
X  send(replyee, &tty_mess);
X}
X
X
X/*===========================================================================*
X *				sigchar					     *
X *===========================================================================*/
XPUBLIC 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_struct[NR_CONS]) rs_sig(tp);	/* RS232 only */
X  if (tp->tty_pgrp) cause_sig(tp->tty_pgrp, sig);
X}
+ END-OF-FILE tty.c
chmod 'u=rw,g=r,o=r' 'tty.c'
set `wc -c 'tty.c'`
count=$1
case $count in
28048)	:;;
*)	echo 'Bad character count in ''tty.c' >&2
		echo 'Count should be 28048' >&2
esac
echo Extracting 'tty.h.new'
sed 's/^X//' > 'tty.h.new' << '+ END-OF-FILE ''tty.h.new'
X#define NR_CONS            1	/* how many consoles can system handle */
X#define	NR_RS_LINES	   1	/* how many rs232 terminals can system handle*/
X#define TTY_IN_BYTES     200	/* input queue size */
X#define TTY_RAM_WORDS    320	/* ram buffer size */
X#define TTY_BUF_SIZE     256	/* unit for copying to/from queues */
X#define TAB_SIZE           8	/* distance between tabs */
X#define TAB_MASK          07	/* mask for tty_column when tabbing */
X#define WORD_MASK     0xFFFF	/* mask for 16 bits */
X#define OFF_MASK      0x000F	/* mask for  4 bits */
X#define MAX_OVERRUN      100	/* size of overrun input buffer */
X#define MAX_ESC_PARMS      2	/* number of escape sequence params allowed */
X
X#define ERASE_CHAR      '\b'	/* default erase character */
X#define KILL_CHAR        '@'	/* default kill character */
X#define INTR_CHAR (char)0177	/* default interrupt character */
X#define QUIT_CHAR (char) 034	/* default quit character */
X#define XOFF_CHAR (char) 023	/* default x-off character (CTRL-S) */
X#define XON_CHAR  (char) 021	/* default x-on character (CTRL-Q) */
X#define EOT_CHAR  (char) 004	/* CTRL-D */
X/*
X * This MARKER is used as an unambiguous flag for an unescaped end of
X * file character.  It is meaningful only in cooked mode.  0200 should
X * never be used in cooked mode, since that is supposed to be used only
X * for 7-bit ASCII.  Be careful that code only checks
X * for MARKER in cooked mode.  This kludge is needed because
X * chars are stored in char arrays, so there's no way to have a
X * completely out of band value.
X */
X#define MARKER   (char) 0200	/* non-escaped CTRL-D stored as MARKER */
X#define SCODE1            71	/* scan code for Home on numeric pad */
X#define SCODE2            81	/* scan code for PgDn on numeric pad */
X#define DEL_CODE   (char) 83	/* DEL for use in CTRL-ALT-DEL reboot */
X#define ESC       (char) 033	/* escape */
X#define BRACKET          '['	/* Part of the ESC [ letter escape seq */
X
X#define F1                59	/* scan code for function key F1 */
X#define F2                60	/* scan code for function key F2 */
X#define F3                61	/* scan code for function key F3 */
X#define F4                62	/* scan code for function key F4 */
X#define F9                67	/* scan code for function key F9 */
X#define F10               68	/* scan code for function key F10 */
X#define TOP_ROW           14	/* codes below this are shifted if CTRL */
X
X#define IBM_PC		   1	/* Standard IBM keyboard */
X#define OLIVETTI	   2	/* Olivetti keyboard	 */
X#define DUTCH_EXT	   3	/* Dutch extended IBM keyboard */
X#define US_EXT		   4	/* U.S. extended keyboard */
X#define NR_SCAN_CODES   0x69	/* Number of scan codes */
X
XEXTERN struct tty_struct {
X  /* Input queue.  Typed characters are stored here until read by a program. */
X  char tty_inqueue[TTY_IN_BYTES];    /* array used to store the characters */
X  char *tty_inhead;		/* pointer to place where next char goes */
X  char *tty_intail;		/* pointer to next char to be given to prog */
X  int tty_incount;		/* # chars in tty_inqueue */
X  int tty_lfct;			/* # line feeds in tty_inqueue */
X
X  /* Output section. */
X  int tty_ramqueue[TTY_RAM_WORDS];	/* buffer for video RAM */
X  int tty_rwords;		/* number of WORDS (not bytes) in outqueue */
X  int tty_org;			/* location in RAM where 6845 base points */
X  int tty_vid;			/* current position of cursor in video RAM */
X  char tty_esc_state;		/* 0=normal, 1=ESC, 2=ESC[ */
X  char tty_esc_intro;		/* Distinguishing character following ESC */
X  int tty_esc_parmv[MAX_ESC_PARMS];	/* list of escape parameters */
X  int *tty_esc_parmp;		/* pointer to current escape parameter */
X  int tty_attribute;		/* current attribute byte << 8 */
X  int (*tty_devstart)();	/* routine to start actual device output */
X
X  /* Terminal parameters and status. */
X  int tty_mode;			/* terminal mode set by IOCTL */
X  int tty_speed;		/* low byte is ispeed; high byte is ospeed */
X  int tty_column;		/* current column number (0-origin) */
X  int tty_row;			/* current row (0 at top of screen) */
X  char tty_busy;		/* 1 when output in progress, else 0 */
X  char tty_escaped;		/* 1 when '\' just seen, else 0 */
X  char tty_inhibited;		/* 1 when CTRL-S just seen (stops output) */
X  char tty_makebreak;		/* 1 for terminals that interrupt twice/key */
X  char tty_waiting;		/* 1 when output process waiting for reply */
X
X  /* User settable characters: erase, kill, interrupt, quit, x-on; x-off. */
X  char tty_erase;		/* char used to erase 1 char (init ^H) */
X  char tty_kill;		/* char used to erase a line (init @) */
X  char tty_intr;		/* char used to send SIGINT  (init DEL) */
X  char tty_quit;		/* char used for core dump   (init CTRL-\) */
X  char tty_xon;			/* char used to start output (init CTRL-Q)*/
X  char tty_xoff;		/* char used to stop output  (init CTRL-S) */
X  char tty_eof;			/* char used to stop output  (init CTRL-D) */
X
X  /* Information about incomplete I/O requests is stored here. */
X  char tty_incaller;		/* process that made the call (usually FS) */
X  char tty_inproc;		/* process that wants to read from tty */
X  char *tty_in_vir;		/* virtual address where data is to go */
X  int tty_inleft;		/* how many chars are still needed */
X  char tty_otcaller;		/* process that made the call (usually FS) */
X  char tty_outproc;		/* process that wants to write to tty */
X  char *tty_out_vir;		/* virtual address where data comes from */
X  phys_bytes tty_phys;		/* physical address where data comes from */
X  int tty_outleft;		/* # chars yet to be copied to tty_outqueue */
X  int tty_cum;			/* # chars copied to tty_outqueue so far */
X  int tty_pgrp;			/* slot number of controlling process */
X
X  /* Miscellaneous. */
X  int tty_ioport;		/* I/O port number for this terminal */
X} tty_struct[NR_CONS+NR_RS_LINES];
X
X/* Values for the fields. */
X#define NOT_ESCAPED        0	/* previous character on this line not '\' */
X#define ESCAPED            1	/* previous character on this line was '\' */
X#define RUNNING            0	/* no CRTL-S has been typed to stop the tty */
X#define STOPPED            1	/* CTRL-S has been typed to stop the tty */
X#define INACTIVE           0	/* the tty is not printing */
X#define BUSY               1	/* the tty is printing */
X#define ONE_INT            0	/* regular terminals interrupt once per char */
X#define TWO_INTS           1	/* IBM console interrupts two times per char */
X#define NOT_WAITING        0	/* no output process is hanging */
X#define WAITING            1	/* an output process is waiting for a reply */
X#define COMPLETED          2	/* output done; send a completion message */
X
XEXTERN char tty_driver_buf[2*MAX_OVERRUN+2]; /* driver collects chars here */
XEXTERN char tty_copy_buf[2*MAX_OVERRUN];  /* copy buf used to avoid races */
XEXTERN char tty_buf[TTY_BUF_SIZE];	/* scratch buffer to/from user space */
XEXTERN int shift1, shift2, capslock, numlock;	/* keep track of shift keys */
XEXTERN int control, alt;	/* keep track of key statii */
XEXTERN int caps_off;		/* 1 = normal position, 0 = depressed */
XEXTERN int num_off;		/* 1 = normal position, 0 = depressed */
XEXTERN int softscroll;		/* 1 = software scrolling, 0 = hardware */
XEXTERN int output_done;	/* number of RS232 output messages to be sent*/
XEXTERN int ega_origin;		/* origin to set at next ega int */
XEXTERN int ega_line;		/* line to set at next ega int */
XEXTERN int char_height;	/* number of scan lines for a char */
XEXTERN int keyb_type;		/* type of keyboard attached */
XEXTERN int minus_code;		/* numeric minus on dutch extended keyboard */
XEXTERN int num_slash;		/* scan code of numeric slash */
+ END-OF-FILE tty.h.new
chmod 'u=rw,g=r,o=r' 'tty.h.new'
set `wc -c 'tty.h.new'`
count=$1
case $count in
7512)	:;;
*)	echo 'Bad character count in ''tty.h.new' >&2
		echo 'Count should be 7512' >&2
esac
echo Extracting 'ttymaps.h.new'
sed 's/^X//' > 'ttymaps.h.new' << '+ END-OF-FILE ''ttymaps.h.new'
X
X/* Scan codes to ASCII for alt keys (IBM Extended keyboard) */
XPUBLIC char alt_c[NR_SCAN_CODES];
X
X/* Scan codes to ASCII for unshifted keys for IBM-PC (default) */
XPUBLIC char unsh[NR_SCAN_CODES] = {
X 0,033,'1','2','3','4','5','6',        '7','8','9','0','-','=','\b','\t',
X 'q','w','e','r','t','y','u','i',      'o','p','[',']',015,0202,'a','s',
X 'd','f','g','h','j','k','l',';',      047,0140,0200,0134,'z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',     0203,' ',0204,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,0205,0210,0267,  0270,0271,0211,0264,0265,0266,0214
X,0261,0262,0263,'0',0177,0,0,0,0,	0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
X/* Scan codes to ASCII for shifted keys */
XPUBLIC char sh[NR_SCAN_CODES] = {
X 0,033,'!','@','#','$','%','^',        '&','*','(',')','_','+','\b','\t',
X 'Q','W','E','R','T','Y','U','I',      'O','P','{','}',015,0202,'A','S',
X 'D','F','G','H','J','K','L',':',      042,'~',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',    0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0204,0213,'7',  '8','9',0211,'4','5','6',0214,'1',
X '2','3','0','.',0,0,0,0,		0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
X/* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
XPUBLIC char unm24[NR_SCAN_CODES] = {
X 0,033,'1','2','3','4','5','6',        '7','8','9','0','-','^','\b','\t',
X 'q','w','e','r','t','y','u','i',      'o','p','@','[','\r',0202,'a','s',
X 'd','f','g','h','j','k','l',';',      ':',']',0200,'\\','z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',     0203,' ',0204,0241,0242,0243,0244,0245,
X0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
X0262,0263,'0','.',' ',014,0212,'\r',   0264,0262,0266,0270,032,0213,' ','/',
X0253,0254,0255,0256,0257,0215,0216,0217
X};
X
X/* Scan codes to ASCII for Olivetti M24 for shifted keys. */
XPUBLIC char m24[NR_SCAN_CODES] = {
X 0,033,'!','"','#','$','%','&',        047,'(',')','_','=','~','\b','\t',
X 'Q','W','E','R' ,'T','Y','U','I',     'O','P',0140,'{','\r',0202,'A','S',
X 'D','F','G','H','J','K','L','+',      '*','}',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',     0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0270,023,'7', '8','9',0211,'4','5','6',0214,'1',
X '2','3',0207,0177,0271,014,0272,'\r', '\b','\n','\f',036,032,0273,0274,'/',
X 0233,0234,0235,0236,0237,0275,0276,0277
X};
X
XPUBLIC char dutch_unsh[NR_SCAN_CODES] = {
X 0,033,'1','2','3','4','5','6',		'7','8','9','0','/',0370,'\b','\t',
X 'q','w','e','r','t','y','u','i',	'o','p',0,'*','\r',0202,'a','s',
X 'd','f','g','h','j','k','l','+',	'\'',0100,0200,'<','z','x','c','v',
X 'b','n','m',',','.','-',0201,'*',	0203,' ',0204,0,0,0,0,0,
X 0,0,0,0,0,0205,0,183,			184,185,137,180,'5',182,140,177,
X 178,179,0,0177,0,0,']','/',0,		0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
XPUBLIC char dutch_sh[NR_SCAN_CODES] = {
X 0,033,'!','\"','#','$','%','&',	'_','(',')','\'','?',0176,'\b','\t',
X 'Q','W','E','R','T','Y','U','I',	'O','P','^','|','\r',0202,'A','S',
X 'D','F','G','H','J','K','L',0361,	0,025,0200,'>','Z','X','C','V',
X 'B','N','M',';',':','=',0201,'*',	0203,' ',0204,0,0,0,0,0,
X 0,0,0,0,0,0205,0,'7',			'8','9',137,'4','5','6',140,'1',
X '2','3','0',',',0,0,'[','/',0,		0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
X/* Code table for alt key */
XPUBLIC char dutch_alt[NR_SCAN_CODES] = {
X 0,0,0,253,0,172,171,0,		156,'{','}',0,'\\',0,0,0,
X 0,0,0,0,0,0,0,0,		0,0,0,0,0,0202,0,0,
X 0,0,0,0,0,0,0,0,		0,170,0200,0,174,175,0,0,
X 0,0,0,0,0,0,0201,0,		0203,0,0204,0,0,0,0,0,
X 0,0,0,0,0,0205,0,0,		0,0,0,0,0,0,0,0,
X 0,0,0,0177,0,0,'|',0,0,	0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
X
X/* Unshifted U.S. extended kbd */
XPUBLIC char unsh_usx[NR_SCAN_CODES] = {
X 0,'`','1','2','3','4','5','6',        '7','8','9','0','-','=','\b','\t',
X 'q','w','e','r','t','y','u','i',      'o','p','[',']',015,0202,'a','s',
X 'd','f','g','h','j','k','l',';',      047,033,0200,0134,'z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',     0203,' ',0202,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,0205,0210,0267,  0270,0271,0211,0264,0265,0266,0214
X,0261,0262,0263,'0',0177,0,0,0,0,	0,0,0,0,0,0,0,0,
X0,0,0,0,0,0,0,0
X};
X
X/* Shifted U.S. extended kbd */
XPUBLIC char sh_usx[NR_SCAN_CODES] = {
X 0,033,'!','@','#','$','%','^',        '&','*','(',')','_','+','\b','\t',
X 'Q','W','E','R','T','Y','U','I',      'O','P','{','}',015,0202,'A','S',
X 'D','F','G','H','J','K','L',':',      042,'~',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',    0203,' ',0202,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0204,0213,'7',  '8','9',0211,'4','5','6',0214,'1',
X '2','3','0','.',0,0,0,0,		0,0,0,0,0,0,0,0,
X 0,0,0,0,0,0,0,0
X};
X
XPUBLIC char scode_map[] = 
X		{'H', 'A', 'V', 'S', 'D', 'G', 'C', 'T', 'Y', 'B', 'U'};
+ END-OF-FILE ttymaps.h.new
chmod 'u=rw,g=r,o=r' 'ttymaps.h.new'
set `wc -c 'ttymaps.h.new'`
count=$1
case $count in
4708)	:;;
*)	echo 'Bad character count in ''ttymaps.h.new' >&2
		echo 'Count should be 4708' >&2
esac
exit 0