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