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