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