Path: utzoo!attcan!uunet!munnari!uqcspe!elec!marks
From: marks@elec.uq.oz (Mark Schulz)
Newsgroups: comp.os.minix
Subject: new tty driver (3 of 3)
Keywords: tty MINIX rs232
Message-ID: <27@elec.uq.oz>
Date: 22 Sep 88 07:31:51 GMT
Organization: Elec Eng, Queensland Uni, Australia
Lines: 1596
echo x - tty2.c
sed 's/^X//' >tty2.c <<'*-*-END-of-tty2.c-*-*'
X/* tty2.c - device dependant code for console tty driver (IBM-PC)
X *
X * Written by: A.Hannam (Feb 1988)
X *
X * Modifications:
X * 28/8/88 - Modified for MINIX V1.3 on IBM-PC
X * Added scan-code translation & macro sequences
X * 5/9/88 - Added a significant portion of ANSI sequences
X * Fixed EGA code
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/******************************* CONSOLE DRIVER ******************************/
X/*****************************************************************************/
X
XPUBLIC int scan_code; /* scancode for '=' to test if olivetti */
XPUBLIC int color; /* 1 if console is color, 0 if it is mono */
XPUBLIC int vid_mask; /* 037777 for color (16K) or 07777 for mono */
XPUBLIC int vid_retrace; /* how many words to display per burst */
XPUBLIC unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */
X
XPUBLIC void int_con(), init_con();
X
Xextern int pc_at;
Xextern int lock();
Xextern void do_nothing(), sigchar(), reboot(), wreboot(), restore()
X , vid_write(), vid_fill(), vid_fmove(), vid_bmove();
X
XPRIVATE bool rout_con();
XPRIVATE unsigned trans_con();
XPRIVATE void ofl_con(), scroll_screen(), move_to(), do_escape()
X , set_6845(), beep_on(), dset_con(), parse_escape(), set_leds()
X , beep_off(), check_reboot();
X
X
X/* Definitions used by the console driver. */
X#define COLOR_BASE 0xB800 /* video ram paragraph for color display */
X#define MONO_BASE 0xB000 /* video ram address for mono display */
X#define C_VID_MASK 0x3FFF /* mask for 16K video RAM */
X#define M_VID_MASK 0x0FFF /* mask for 4K video RAM */
X#define C_RETRACE 0x0180 /* maximum words to display at once (cga) */
X#define M_RETRACE 0x7FFF /* maximum words to display at once (mono) */
X#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
X#define B_TIME 3 /* length of CTRL-G beep in ticks */
X#define BLANK 0x0700 /* default blank color */
X#define GO_FORWARD 0 /* scroll forward */
X#define GO_BACKWARD 1 /* scroll backward */
X#define TIMER2 0x42 /* I/O port for timer channel 2 */
X#define TIMER3 0x43 /* I/O port for timer channel 3 */
X#define KEYBD 0x60 /* I/O port for keyboard data */
X#define PORT_B 0x61 /* I/O port for 8255 port B */
X#define KBIT 0x80 /* bit used to ack characters to keyboard */
X#define LED_CODE 0xED /* command to keyboard to set LEDs */
X#define LED_DELAY 0x80 /* device dependent delay needed */
X#define MAX_ESC_PARMS 2 /* no. of escape sequence parameters allowed */
X#define FAST_BAUD B115200 /* console looks like a term at this speed */
X#define BEEPING DD_FLAG1 /* flag in tty struct when console beeping */
X#define REBOOT DD_FLAG2 /* flag in tty struct when about to reboot */
X
X#define LINE_WIDTH 80 /* # characters on a line */
X#define SCR_LINES 25 /* # lines on the screen */
X
X#define ESC 033 /* ESC for use in ansi term sequences */
X#define XOFF_CHAR 0x13 /* xoff char that these routines can decode */
X
X#define OLIVETTI_EQUAL 12 /* scan code for '=' on olivetti (13 on IBM) */
X#define CTRL_S 31 /* scan code for letter S (for CRTL-S) */
X#define DEL_CODE 83 /* code for DEL for in CTRL-ALT-DEL reboot */
X#define FUNC_KEY 58 /* codes above this belong to function keys */
X#define F10 68 /* scan code for function key F10 */
X#define TOP_ROW 14 /* codes below this are shifted if CTRL */
X#define NUM_PAD 70 /* codes above this belong to the number pad */
X#define NUM_PGDN 81 /* code for pgdn key on number pad */
X
X/* Constants relating to the video RAM and 6845. */
X#define M_6845 0x3B0 /* port for 6845 mono */
X#define C_6845 0x3D0 /* port for 6845 color */
X#define EGA 0x3C0 /* port for EGA card */
X#define INDEX 4 /* 6845's index register */
X#define DATA 5 /* 6845's data register */
X#define CUR_SIZE 10 /* 6845's cursor size register */
X#define VID_ORG 12 /* 6845's origin register */
X#define CURSOR 14 /* 6845's cursor register */
X
X/* Global variables used by the console driver. */
XPRIVATE message c_mess; /* message used for console input chars */
X
XPRIVATE bool shift1, shift2; /* keep track of key statii */
XPRIVATE bool capslock, numlock;
XPRIVATE bool control, alt;
X
XPRIVATE char c_estate; /* 0=normal, 1=ESC, 2=ESC[ etc */
XPRIVATE int c_enum[MAX_ESC_PARMS]; /* list of escape parameters */
XPRIVATE int * c_p_enum; /* pointer to current escape param */
XPRIVATE int c_row; /* the current row for the console */
XPRIVATE int c_attr; /* the current character atrribute */
XPRIVATE unsigned c_blank; /* blanking character and attribute */
XPRIVATE int c_org; /* origin of the screen in video ram */
XPRIVATE int c_vid; /* current cursor pos in video ram */
XPRIVATE int c_port; /* I/O port for accessing 6845 */
XPRIVATE char * c_key_sh; /* translation tables - shifted keys */
XPRIVATE char * c_key_ush; /* - unshifted keys */
XPRIVATE char c_s_col; /* saved cursor column */
XPRIVATE char c_s_row; /* saved cursor row */
X
X/* Scan codes to ASCII for unshifted keys */
XPRIVATE char unsh[] = {
X 0,ESC,'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,0260,0177
X};
X
X/* Scan codes to ASCII for shifted keys */
XPRIVATE char sh[] = {
X 0,ESC,'!','@','#','$','%','^','&','*','(',')','_','+','\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','-','4','5','6','+','1',
X '2','3','0','.'
X};
X
X/* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
XPRIVATE char unm24[] = {
X 0,ESC,'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,
X 0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
X 0262,0263,0207,0177,0271,014,0212,'\r',0264,0262,0266,0270,032,0213,0274,'/',
X 0253,0254,0255,0256,0257,0215,0216,0217
X};
X
X/* Scan codes to ASCII for Olivetti M24 for shifted keys. */
XPRIVATE char m24[] = {
X 0,ESC,'!','"','#','$','%','&',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','0','.',' ',014,0272,'\r','\b','\n','\f',036,032,0273,' ','/',
X 0233,0234,0235,0236,0237,0275,0276,0277
X};
X
XPRIVATE char *fn_macros[4][10]= {
X { /* no shift, control or alt - ANSI Fn Keys */
X "\033OS","\033OT","\033OU","\033OV","\033OW",
X "\033OP","\033OQ","\033OR","\033OX","\033OY"
X },{ /* shift, no control or alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X },{ /* control, no shift or alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X },{ /* control & shift, no alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X}};
X
XPRIVATE char *fn_a_macros[2][10]= {
X { /* alt, no shift or control - Useful Strings */
X "ls -al ","ls -al\n","mount /dev/","umount /dev/",
X "dosdir -l ","dosdir -l 1\n","doswrite -a 1 ","doswrite 1 ",
X "dosread -a 1 ","dosread 1 "
X },{ /* alt & shift, no control - Useful Strings */
X 0,0,0,0,0,0,0,0,0,"\nexit\n"
X}};
X
XPRIVATE char *arrow_macros[]= {
X "[H","[A","[V","[S","[D","[G","[C","[T","[Y","[B","[U"
X };
X
XPRIVATE charfbuf con_inbuf;
X
X#define CONS_RAM_WORDS 256
XPRIVATE int cons_ramqueue[CONS_RAM_WORDS];
XPRIVATE int cons_rwords;
X
X/*===========================================================================*
X * init_con *
X *===========================================================================*/
XPUBLIC void init_con(tp)
Xregister tty_entry *tp;
X{
X
X c_mess.TTY_LINE= CON1; /* The interrupt message */
X c_mess.m_type= TTY_CHAR_INT; /* Could have been TTY_O_DONE */
X
X /* Tell the EGA card, if any, to simulate a 16K CGA card. */
X port_out(EGA + INDEX, 4); /* register select */
X port_out(EGA + DATA, 1); /* no extended memory to be used */
X
X
X tp->tty_devraw= rout_con;
X tp->tty_devclr= ofl_con;
X tp->tty_devflush= ofl_con;
X tp->tty_devioctl= dset_con;
X tp->tty_devtrans= trans_con;
X tp->tty_devempty= check_reboot;
X
X /* console requires translation and always gives 8 bits */
X tp->tty_state |= TRANSLATE|COK8BIT;
X tp->tty_ddmod |= CON_COOK8|CON_WRAP|D_CONSOLE;
X tp->tty_ispeed= tp->tty_ospeed = FAST_BAUD;
X
X tp->tty_fbuf = &con_inbuf;
X fbufinit(con_inbuf);
X
X /* Set parameters based on this particular machine */
X if (color&1) { /* What mode is the console in ? */
X vid_base = COLOR_BASE;
X vid_mask = C_VID_MASK;
X c_port = C_6845;
X vid_retrace = C_RETRACE;
X } else {
X vid_base = MONO_BASE;
X vid_mask = M_VID_MASK;
X c_port = M_6845;
X vid_retrace = M_RETRACE;
X }
X if (scan_code == OLIVETTI_EQUAL) {
X c_key_sh= m24;
X c_key_ush= unm24;
X } else {
X c_key_sh= sh;
X c_key_ush = unsh;
X }
X
X c_blank = c_attr = BLANK; /* attribute byte for screen */
X cons_rwords = 0; /* initialize buffer */
X c_estate = 0; /* ESC state is 0 */
X c_s_col = c_s_row = 0; /* The saved cursor pos is home */
X set_6845(CUR_SIZE, 23); /* set cursor shape (old = 31) */
X set_6845(VID_ORG, c_org = 0); /* use page 0 of video ram */
X move_to(0,SCR_LINES-1); /* move cursor to bottom left corner */
X}
X
X
X/*===========================================================================*
X * int_con *
X *===========================================================================*/
XPUBLIC void int_con()
X{
X/* A keyboard interrupt has occurred. Process it. (Interrupts are off) */
X
X int val, c;
X
X /* Fetch the character from the keyboard hardware and acknowledge it. */
X port_in(KEYBD, &c); /* get the scan code for the key struck */
X port_in(PORT_B, &val); /* strobe the keyboard to ack the char */
X port_out(PORT_B, val | KBIT); /* strobe the bit high */
X port_out(PORT_B, val); /* now strobe it low */
X
X /* If Keyboard Locked then discard char */
X if (tty_struct[CON1].tty_ddmod&CON_LOCK) {
X port_out(INT_CTL, ENABLE);
X return;
X }
X
X /* The IBM keyboard interrupts twice per key, once when depressed, once when
X * released. Filter out the latter, ignoring all but the shift-type keys.
X * The shift-type keys, 29, 42, 54, 56, 58, and 69 must be processed normally.
X */
X if (c > 0200)
X switch(c) {
X case 29 + 0200: case 42 + 0200:
X case 54 + 0200: case 56 + 0200:
X case 58 + 0200: case 69 + 0200:
X break;
X default: /* re-enable interrupts */
X port_out(INT_CTL, ENABLE);
X return; /* don't call tty_task() */
X }
X
X /* Check for CTRL-ALT-DEL, and if found set a flag. */
X if (control && alt && c == DEL_CODE)
X tty_struct[CON1].tty_state |= REBOOT;
X
X/* Check to see if character is CTRL-S, to stop output. Setting xoff
X * to anything other than CTRL-S will not be detected here, but will
X * be detected later, in the driver. A general routine to detect any
X * xoff character here would be complicated since we only have the
X * scan code here, not the ASCII character. This is just done to
X * improve responce.
X */
X if ( !(tty_struct[CON1].tty_mode & RAW)
X && tty_struct[CON1].tty_xoff == XOFF_CHAR
X && control && c == CTRL_S ) {
X tty_struct[CON1].tty_state |= INHIBITED;
X port_out(INT_CTL, ENABLE);
X return;
X }
X
X
X /* Store the character in memory so the task can get at it later. */
X if ( bufnfull(con_inbuf) ) {
X putfobj(con_inbuf,c); /* Enough room so store the char */
X }
X
X /* Inform other routines that we have chars available */
X tty_struct[CON1].tty_state |= IN_FLUSH;
X flush_flag |= IN_FLUSH;
X
X /* Build and send the int message to tty task only if absolutly necessary */
X if (bufcount(con_inbuf) >= CHAR_BUF_THRESHOLD) {
X interrupt(TTY, &c_mess);
X }
X
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X}
X
X/*===========================================================================*
X * dset_con *
X *===========================================================================*/
XPRIVATE void dset_con(tp, m)
Xregister tty_entry *tp;
Xregister message *m;
X{
X switch (m->TTY_REQUEST) {
X case TIOCSETN:
X case TIOCSETP:
X /* Console baud rate is always fast */
X tp->tty_ispeed= tp->tty_ospeed= FAST_BAUD;
X break;
X
X case TIOCSETM:
X /* Ensure modes are valid - if something looks
X * suspicious then don't allow keyboard lock.
X */
X if (!(tp->tty_ddmod & D_CONSOLE))
X tp->tty_ddmod &= ~CON_LOCK;
X tp->tty_ddmod &= (CON_COOK8|CON_LOCK|CON_WRAP|CON_INSERT);
X tp->tty_ddmod |= D_CONSOLE;
X /* Process the device dependant modes */
X if (tp->tty_ddmod & CON_COOK8)
X tp->tty_state |= COK8BIT;
X else
X tp->tty_state &= ~COK8BIT;
X break;
X
X case TIOCMODG:
X /* This looks like an operating terminal */
X m->TTY_FLAGS = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS
X |TIOCM_CAR|TIOCM_DSR;
X m->TTY_SPEK = 0;
X break;
X
X /* Ignore all other ioctl calls */
X }
X}
X
X
X/*===========================================================================*
X * rout_con *
X *===========================================================================*/
XPRIVATE bool rout_con(tp, c, prio)
Xregister tty_entry *tp; /* pointer to tty struct */
Xchar c; /* character to be output */
X{
X/* Output a character on the console. Priority order is ...
X * Handle control codes,
X * Handle escape sequences
X * Handle normal chars
X *
X * This allows control code processing to occur without disturbing
X * escape sequences.
X */
X
X if (c < ' ') switch(c) { /* Handle control codes */
X
X /* Cancel a escape sequence and beep */
X case 0x18: /* CAN & SUB */
X case 0x1A:
X if (!c_estate) break;
X c_estate = 0;
X
X /* ring the bell */
X case 007: /* BEL */
X ofl_con();
X beep_on(BEEP_FREQ,B_TIME);
X break;
X
X /* BackSpace - with EOL wrap - (left) */
X case '\b': /* BS */
X if (tp->tty_state & BS_WRAP) {
X tp->tty_state &= ~BS_WRAP;
X if (c_row != 0 && tp->tty_ddmod&CON_WRAP) {
X c_row--;
X tp->tty_column= LINE_WIDTH - 1;
X }
X }
X move_to(tp->tty_column, c_row);
X break;
X
X /* Tab Handling - don't bother clearing space */
X case '\t': /* HT */
X move_to(tp->tty_column, c_row);
X break;
X
X /* line feed (down) */
X case '\n': /* NL */
X if (c_row >= SCR_LINES-1)
X scroll_screen(GO_FORWARD);
X else
X c_row++;
X move_to(tp->tty_column, c_row);
X break;
X
X /* vertical tab - (up) */
X case 0x0B: /* VT */
X c_row--;
X move_to(tp->tty_column, c_row);
X break;
X
X /* form feed - (right) */
X case 0x0C: /* FF */
X move_to(tp->tty_column+1, c_row);
X break;
X
X /* carriage return */
X case '\r': /* CR */
X move_to(0, c_row);
X break;
X
X /* ESC - start of an escape sequence */
X case ESC: /* ESC */
X c_estate = 0;
X parse_escape(c);
X break;
X
X /* All other control codes are ignored */
X
X } else if (c_estate != 0) { /* Handle Escape Sequences */
X parse_escape(c);
X } else { /* Normal Chars */
X /* printable chars are stored in outqueue */
X /* They are being used as words (not bytes) */
X if (cons_rwords >= CONS_RAM_WORDS) ofl_con();
X
X if (tp->tty_column < LINE_WIDTH)
X cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X else if (tp->tty_ddmod&CON_WRAP) { /* Long Lines */
X cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X move_to(0, c_row); /* Implied \r */
X rout_con(tp,'\n',prio); /* Implied \n */
X }
X }
X
X /* Handle ^S processing and ECHO_OUT priority */
X if (tp->tty_state&INHIBITED || prio==ECHO_OUT) ofl_con();
X return (tp->tty_state&INHIBITED);
X}
X
X/*===========================================================================*
X * scroll_screen *
X *===========================================================================*/
XPRIVATE void scroll_screen(dir)
Xint dir; /* GO_FORWARD or GO_BACKWARD */
X{
X register offset;
X
X /* Hardware Scrolling. It is up to the video routines to ensure the screen is
X * written in such a way that scrolling over the ram boundary works on
X * both CGA,MONO (which support ram wrap) and EGA (which may not support
X * ram wrap).
X */
X ofl_con(); /* Flush the output stream */
X if (dir == GO_FORWARD) { /* Calculate the new video origin */
X c_org += 2 * LINE_WIDTH;
X c_org &= vid_mask;
X offset = c_org + 2*(SCR_LINES-1)*LINE_WIDTH;
X } else {
X c_org -= 2 * LINE_WIDTH;
X c_org &= vid_mask;
X offset = c_org;
X }
X
X /* Blank the new line at top or bottom. */
X vid_fill(c_blank, offset, LINE_WIDTH);
X set_6845(VID_ORG, c_org >> 1); /* 6845 thinks in words */
X}
X
X/*===========================================================================*
X * ofl_con *
X *===========================================================================*/
XPRIVATE void ofl_con()
X{
X/* Have the characters in 'outqueue' transferred to the screen. */
Xregister unsigned i;
X
X if (cons_rwords == 0) return;
X
X /* Do insert mode processing */
X if (tty_struct[CON1].tty_ddmod&CON_INSERT) {
X i = c_org + c_row*2*LINE_WIDTH + (2*LINE_WIDTH-2); /* end of line */
X vid_bmove(i - cons_rwords*2, i
X , LINE_WIDTH - MIN(tty_struct[CON1].tty_column,LINE_WIDTH));
X }
X
X /* Write the chars to the screen */
X vid_write(cons_ramqueue, c_vid, cons_rwords);
X
X /* Update the video parameters and cursor. */
X c_vid += 2*cons_rwords;
X set_6845(CURSOR, c_vid >> 1); /* cursor counts in words */
X cons_rwords = 0;
X}
X
X
X/*===========================================================================*
X * move_to *
X *===========================================================================*/
XPRIVATE void move_to(x, y)
Xint x; /* column (0 <= x <= 79) */
Xint y; /* c_row (0 <= y <= 24, 0 at top) */
X{
X/* Move the cursor to (x, y). */
X
X ofl_con(); /* flush any pending characters */
X x = between(0, x, LINE_WIDTH-1); /* ensure x & y are valid */
X y = between(0, y, SCR_LINES -1);
X tty_struct[CON1].tty_column = x; /* set x co-ordinate */
X c_row = y; /* set y co-ordinate */
X c_vid = c_org + y*2*LINE_WIDTH + 2*x;
X set_6845(CURSOR, c_vid >> 1); /* cursor counts in words */
X}
X
X/*===========================================================================*
X * set_6845 *
X *===========================================================================*/
XPRIVATE void set_6845(reg, val)
Xregister reg; /* which register pair to set */
Xregister val; /* 16-bit value to set it to */
X{
X/* Set a register pair inside the 6845.
X * Registers 10-11 control the format of the cursor (how high it is, etc).
X * Registers 12-13 tell the 6845 where in video ram to start (in WORDS)
X * Registers 14-15 tell the 6845 where to put the cursor (in WORDS)
X *
X * Note that registers 12-15 work in words, i.e. 0x0000 is the top left
X * character, but 0x0001 (not 0x0002) is the next character. This addressing
X * is different from the way the 8088 addresses the video ram, where 0x0002
X * is the address of the next character.
X */
X port_out(c_port + INDEX, reg); /* set the index register */
X port_out(c_port + DATA, (val>>8) & BYTE); /* output high byte */
X port_out(c_port + INDEX, reg + 1); /* again */
X port_out(c_port + DATA, val&BYTE); /* output low byte */
X}
X
X
X/*===========================================================================*
X * beep_on *
X *===========================================================================*/
XPRIVATE void beep_on(f,d)
Xregister f; /* this value determines beep frequency */
Xregister d; /* this value is the time to sound in ticks */
X{
X/* Making a beeping sound on the speaker (output for CRTL-G). This routine
X * works by turning on the bits in port B of the 8255 chip that drive the
X * speaker and sending a clock message to time the beep.
X */
X int x, s;
X message m;
X
X if (tty_struct[CON1].tty_state & BEEPING) return;
X s = lock(); /* disable interrupts */
X port_out(TIMER3,0xB6); /* set up timer channel 2 mode */
X port_out(TIMER2, f&BYTE); /* load low-order bits of frequency in timer */
X port_out(TIMER2,(f>>8)&BYTE); /* now high-order bits of frequency in timer */
X port_in(PORT_B,&x); /* acquire status of port B */
X port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */
X tty_struct[CON1].tty_state |= BEEPING;
X restore(s); /* re-enable interrupts */
X
X m.m_type = SET_ALARM; /* set up the duration */
X m.CLOCK_PROC_NR = TTY;
X m.DELTA_TICKS = d; /* beep for d ticks */
X m.FUNC_TO_CALL = (int (*)()) beep_off; /* func to switch off beep */
X sendrec(CLOCK, &m);
X}
X
X/*===========================================================================*
X * beep_off *
X *===========================================================================*/
XPRIVATE void beep_off()
X{
X/* Turn off the beep on the speaker (output for CRTL-G). This routine
X * is called only by the CLOCK task.
X */
Xint s,x;
X
X s = lock(); /* disable interrupts */
X port_in(PORT_B, &x); /* get status of port B */
X port_out(PORT_B, x & 0xFFFC); /* turn bits 0 and 1 off to stop beep */
X tty_struct[CON1].tty_state &= ~BEEPING;
X restore(s); /* restore interrupts */
X}
X
X
X/*===========================================================================*
X * func_key *
X *===========================================================================*/
XPRIVATE func_key(ch)
Xchar ch; /* scan code for a function key */
X{
X/* This procedure traps function keys for debugging purposes. When MINIX is
X * fully debugged, it should be removed.
X */
X
X switch (ch) {
X
X case FUNC_KEY+1: /* print process table */
X p_dmp();
X break;
X
X case FUNC_KEY+2: /* print memory map */
X map_dmp();
X break;
X
X case FUNC_KEY+3: /* Switch between EGA (with no */
X color ^= 2; /* retrace checking) and CGA/MONO. */
X printf("\n\rVideo Card = %s\n\r"
X ,(color&2 ? "EGA": (color&1 ? "CGA":"MONO")));
X break; /* This is useful to control the */
X /* scrolling speed of EGA cards. */
X
X#ifdef AM_KERNEL
X#ifndef NONET
X case FUNC_KEY+4: /* re-initialise the ethernet card */
X net_init();
X break;
X#endif NONET
X#endif AM_KERNEL
X
X case FUNC_KEY+9: /* kill all process */
X sigchar(&tty_struct[CON1], SIGKILL);
X break;
X }
X}
X
X/*===========================================================================*
X * trans_con *
X *===========================================================================*/
XPRIVATE unsigned trans_con(c)
Xunsigned c; /* scan code of key just struck or released */
X{
X/* This routine handles the console keyboard scan-code to ascii conversion.
X * It has some ANSI sequences and various macros hardwired to certain keys.
X * E.g. Arrow keys and Function Keys. At the moment there is no way to
X * change the macros at run-time but lator the console output routines
X * may define ANSI sequences to do this.
X * This is a general translation routine with no hardware dependancies
X * except for keyboard leds (on an AT).
X * Note: The type of scan-code translation (Olivetti or IBM) is determined
X * during initialization (not here).
X */
X
X unsigned char code;
X bool make;
X static char *seq_str= "";
X
X /* Do Macro Key Sequences (including ANSI keys) */
X switch (c>>8) {
X case 0: /* Non Macro Key */
X break;
X case 1: /* Macro String */
X if (*seq_str)
X return *seq_str++ | 0x100;
X return MARKER;
X default: /* Unknown - ignore */
X return MARKER;
X }
X
X /* Start a Arrow Key ANSI macro */
X if (c > NUM_PAD && c <= NUM_PGDN && !((shift1|shift2)^numlock)) {
X seq_str= arrow_macros[c - (NUM_PAD+1)];
X return ESC | 0x100; /* Send the escape */
X }
X
X /* Start a Funtion Key macro */
X if(c > FUNC_KEY && c <= F10) {
X if (control && alt) { /* Special CONSOLE DEBUG routines */
X func_key(c);
X return MARKER;
X }
X
X /* Handle other combinations of shift, control & alt */
X /* There is no possiblility of control when alt is on */
X seq_str= (alt ? fn_a_macros[shift1|shift2]
X : fn_macros[shift1|shift2|(control<<1)]) [c - (FUNC_KEY+1)];
X if (*seq_str)
X return *seq_str++ | 0x100;
X return MARKER;
X }
X
X make = !(c & 0200); /* 1 when key depressed, 0 when key released */
X c &= 0177; /* high-order bit set on key release */
X
X /* Standard IBM keyboard. Do shift processing */
X code = ((shift1 | shift2)^ (
X /* Check capslock for alpha */
X (capslock && c_key_ush[c] >= 'a' && c_key_ush[c] <= 'z') ||
X /* Check numlock for number pad */
X (c > NUM_PAD && numlock) ))
X ? c_key_sh[c] : c_key_ush[c];
X if (control && c < TOP_ROW) code = c_key_sh[c]; /* CTRL-(top row) */
X
X /* Process ordinary keys, i.e. not shift, control, alt, etc. */
X if (code < 0200 || code > 0205) {
X if (!make) return MARKER; /* key release */
X if (control) code &= 037;
X if (alt) code |= 0200; /* alt key ORs 0200 into code */
X return code;
X }
X
X /* Table entries 0200 - 0205 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) capslock = 1-capslock;
X set_leds(); break; /* caps lock */
X case 5: if (make) numlock = 1-numlock;
X set_leds(); break; /* num lock */
X }
X return MARKER; /* No high level processing to do */
X}
X
X/*===========================================================================*
X * escape *
X *===========================================================================*/
XPRIVATE void parse_escape(c)
Xchar c; /* next character in escape sequence */
X{
X/* Parse and build an escape sequence.
X * Formats understood ...
X *
X * ESC char : state = 0x01
X * ESC '[' [num] char : state = 0x02
X *
X * where num is from 1 to MAX_ESC_PARMS decimal strings seperated by ';'s.
X * more than MAX_ESC_PARMS decimal strings are ignored.
X */
Xregister i;
X
X /* This char is not printable but the column has been incremented */
X /* fix this by decrementing it */
X tty_struct[CON1].tty_column--;
X
X if (c_estate == 0) { /* ESC seen - initialize sequence */
X c_estate = 1;
X c_p_enum = c_enum;
X for(i=0; i= '0' && c <= '9') {
X if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X *c_p_enum = *c_p_enum * 10 + (c - '0');
X return;
X }
X /* Start a new number in sequence */
X if (c == ';') {
X if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X c_p_enum++;
X return;
X }
X }
X
X /* A char has arrived - process it */
X switch (c_estate) {
X case 0x01: /* "ESC char" sequence */
X if (c == '[') { /* "ESC '['" sequence is starting */
X c_estate = 0x02;
X return;
X }
X break;
X
X case 0x02: /* "ESC '[' [num] char" sequence */
X break;
X
X default: /* illegal state */
X c_estate = 0;
X return;
X }
X
X /* A syntacticly valid ESC sequence has arrived - process it */
X do_escape(c);
X c_estate = 0; /* The sequence is finished */
X}
X
X
X/*===========================================================================*
X * do_escape *
X *===========================================================================*/
XPRIVATE void do_escape(c)
Xchar c; /* next character in escape sequence */
X{
X/* The following ANSI escape sequences are currently supported:
X * ESC D index the screen
X * ESC M reverse index the screen
X * ESC E next line
X * ESC 7 save cursor position
X * ESC 8 restore cursor position
X * ESC [ n A Cursor Up [default 1]
X * ESC [ n B Cursor Down [default 1]
X * ESC [ n C Cursor Right [default 1]
X * ESC [ n D Cursor Left [default 1]
X * ESC [ y ; x f move cursor to (x, y) [default (1,1)]
X * ESC [ y ; x H move cursor to (x, y) [default (1,1)]
X * ESC [ n J clear a section of screen [default 0]
X * n: 0 = cursor to bottom of screen
X * 1 = cursor to top of screen
X * 2 = top to bottom of screen
X * ESC [ n K clear a section of line [default 0]
X * n: 0 = cursor to end of line
X * 1 = cursor to start of line
X * 2 = start to end of line
X * ESC [ n L insert n lines at cursor [default 1]
X * ESC [ n M delete n lines at cursor [default 1]
X * ESC [ n @ insert n chars at cursor [default 1]
X * ESC [ n P delete n chars at cursor [default 1]
X * ESC [ n h set mode [default 0]
X * ESC [ n l reset mode [default 0]
X * n: 2 = Keyboard Lock [pwr up Off]
X * 4 = Insert Mode [pwr up Off]
X * 7 = Auto Wrap [pwr up ON]
X * ESC [ n m set the screen rendition [default 0]
X * n: 0 = normal
X * 1 = bold
X * 4 = underline
X * 5 = blink
X * 7 = reverse
X */
Xregister unsigned i, j;
X
X switch (c_estate) {
X case 0x01: /* ESC char */
X switch (c) {
X case 'M': /* Reverse Index */
X if (c_row == 0)
X scroll_screen(GO_BACKWARD);
X else {
X c_row--;
X move_to(tty_struct[CON1].tty_column, c_row);
X }
X return;
X
X case '7':
X c_s_row = c_row;
X c_s_col = tty_struct[CON1].tty_column;
X return;
X
X case '8':
X move_to(c_s_col, c_s_row);
X return;
X
X case 'E':
X move_to(0, c_row);
X case 'D':
X rout_con(&tty_struct[CON1],'\n',ECHO_OUT);
X return;
X
X default: /* Illegal ESC char sequence */
X return;
X }
X
X case 0x02: /* ESC '[' [num] char */
X switch (c) {
X case 'A': /* Cursor Up */
X move_to(tty_struct[CON1].tty_column
X , c_row - MAX(1,c_enum[0]));
X return;
X case 'B': /* Cursor Down */
X move_to(tty_struct[CON1].tty_column
X , c_row + MAX(1,c_enum[0]));
X return;
X case 'C': /* Cursor Right */
X move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X , c_row);
X return;
X case 'D': /* Cursor Left */
X move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X , c_row);
X return;
X
X case 'f': /* Position cursor */
X case 'H':
X move_to(c_enum[1]-1, c_enum[0]-1);
X return;
X
X case 'J':
X ofl_con(); /* Flush pending chars */
X switch (c_enum[0]) {
X case 1: /* Clear start of screen to cursor */
X vid_fill(c_blank, c_org
X , c_row * LINE_WIDTH
X + tty_struct[CON1].tty_column + 1);
X return;
X case 2: /* Clear entire screen */
X vid_fill(c_blank, c_org, SCR_LINES*LINE_WIDTH);
X return;
X case 0: /* Clear cursor to end of screen*/
X vid_fill(c_blank, c_vid
X , (SCR_LINES - c_row) * LINE_WIDTH
X - tty_struct[CON1].tty_column);
X return;
X }
X return;
X
X case 'K':
X ofl_con(); /* Flush pending chars */
X switch(c_enum[0]) {
X case 0: /* Clear cursor to end of line */
X vid_fill(c_blank, c_vid
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X return;
X case 1: /* Clear start of line to cursor */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , tty_struct[CON1].tty_column + 1);
X return;
X case 2: /* Clear entire line */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , LINE_WIDTH);
X return;
X }
X return;
X
X case 'L': /* Insert Lines */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0],SCR_LINES - c_row); /* No. lines */
X j = c_org + (SCR_LINES*LINE_WIDTH*2-2); /* end of screen */
X
X /* Do the line moving */
X vid_bmove(j - i*2*LINE_WIDTH, j
X , (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X /* Clear the inserted lines */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , i*LINE_WIDTH);
X return;
X
X case 'M': /* Delete Lines */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0],SCR_LINES - c_row); /* No. lines */
X j = c_org + c_row*2*LINE_WIDTH; /* Destination */
X
X /* Do the line moving */
X vid_fmove(j + i*2*LINE_WIDTH, j
X , (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X /* Clear the new lines */
X vid_fill(c_blank, c_org + (SCR_LINES - i)*LINE_WIDTH*2
X , i*LINE_WIDTH);
X return;
X
X case '@': /* Insert Chars */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0] /* No. chars */
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X j = c_org + c_row*2*LINE_WIDTH /* end of line */
X + (2*LINE_WIDTH-2);
X
X /* Do the char moving */
X vid_bmove(j - i*2, j
X , LINE_WIDTH - tty_struct[CON1].tty_column);
X
X /* Clear the new chars */
X vid_fill(c_blank, c_vid, i);
X return;
X
X case 'P': /* Delete Chars */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0] /* No. chars */
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X j = c_org + c_row*2*LINE_WIDTH /* Destination */
X + tty_struct[CON1].tty_column;
X
X /* Do the char moving */
X vid_fmove(j + i*2, j
X , LINE_WIDTH - tty_struct[CON1].tty_column - i);
X
X /* Clear the new chars */
X vid_fill(c_blank, c_org + (c_row+1)*LINE_WIDTH*2 - i*2, i);
X return;
X
X case 'h': /* Set mode */
X switch (c_enum[0]) {
X case 2: /* Keyboard Lock */
X tty_struct[CON1].tty_ddmod |= CON_LOCK;
X return;
X case 4: /* Insert Mode */
X tty_struct[CON1].tty_ddmod |= CON_INSERT;
X return;
X case 7: /* Auto Wrap */
X tty_struct[CON1].tty_ddmod |= CON_WRAP;
X return;
X }
X return;
X
X case 'l': /* Reset mode */
X switch (c_enum[0]) {
X case 2: /* Keybaord Unlock */
X tty_struct[CON1].tty_ddmod &= ~CON_LOCK;
X return;
X case 4: /* Overwrite Mode */
X tty_struct[CON1].tty_ddmod &= ~CON_INSERT;
X return;
X case 7: /* No Auto Wrap */
X tty_struct[CON1].tty_ddmod &= ~CON_WRAP;
X return;
X }
X return;
X
X case 'm': /* Set graphic rendition */
X switch (c_enum[0]) {
X case 1: /* BOLD (light green on black) */
X c_attr = 0x0A00;
X return;
X
X case 4: /* UNDERLINE (blue on red) */
X c_attr = 0x4100;
X return;
X
X case 5: /* BLINKING (light grey on black) */
X c_attr = 0x8700;
X return;
X
X case 7: /* REVERSE (black on light grey) */
X c_attr = 0x7000;
X return;
X
X default: c_attr = 0x0700;
X return;
X }
X
X default: /* Illegal ESC [ sequence */
X return;
X }
X
X default: /* Illegal state */
X return;
X }
X}
X
X/*===========================================================================*
X * set_leds *
X *===========================================================================*/
XPRIVATE void set_leds()
X{
X/* Set the LEDs on the caps lock and num lock keys */
X
X int leds, dummy, i;
X
X if (pc_at == 0) return; /* PC/XT doesn't have LEDs */
X leds = (numlock<<1) | (capslock<<2); /* encode LED bits */
X port_out(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X for (i = 0; i < LED_DELAY; i++) ; /* delay needed */
X port_out(KEYBD, leds); /* give keyboard LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X}
X
X/*===========================================================================*
X * check_reboot *
X *===========================================================================*/
XPRIVATE void check_reboot()
X{
X/* High Level Reboot (Here because int routines can't print) */
X
X if (tty_struct[CON1].tty_state & REBOOT) {
X printf("\r\n\033[H\033[J\033[12;27HPress any key to Reboot :");
X ofl_con(); /* Flush the string */
X wreboot();
X }
X}
*-*-END-of-tty2.c-*-*
echo x - tty3.c
sed 's/^X//' >tty3.c <<'*-*-END-of-tty3.c-*-*'
X/* tty3.c - device dependant code for RS232 tty driver (using 8250)
X *
X * Written by: A.Hannam (Feb 1988)
X *
X * Modifications:
X * 7/9/88 - Modified for MINIX V1.3 on IBM-PC
X * Improved interrupt handling
X * Improved efficiency of compiled code
X * 19/9/88 - Added flow control (handshaking) & many ioctl calls
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/**************************** 8250 SERIAL DRIVER *****************************/
X/*****************************************************************************/
X
X#if NR_8250S < 1
XError:- 8250 Driver: "NR_8250S" < 1
X#endif
X
XPUBLIC void int_8250(), init_8250();
X
Xextern void do_nothing(), restore();
Xextern int lock();
X
XPRIVATE bool rout_8250();
XPRIVATE void dset_8250(), oclr_8250(), iflow_8250();
X
X /* Some space and variables for the raw Output routines */
XGEN_S_BUF_TYPE(char,128)
XGEN_S_BUF_TYPE(char,32)
X
X#define BUSY DD_FLAG1 /* 1 when tty busy on output */
X#define RX_FLOW DD_FLAG2 /* 1 when input doing flow cntrl */
X#define TX_FLOW DD_FLAG3 /* 1 when output doing flow cntrl */
X
X#define WOUT_THRESHOLD 4 /* when to start trying to get more chars */
X#define XONCHAR 17 /* ^Q to restart with XONXOFF control */
X#define XOFFCHAR 19 /* ^S to stop with XONXOFF control */
X
X /* interrupt identification register bits */
X#define IPENDING 1 /* 1 when no interrupt pending */
X#define ITYPEMASK 6 /* mask to isolate interrupt causes */
X#define RXREADY 4 /* reciever is ready interrupt */
X#define TXREADY 2 /* transmitter ready interrupt */
X#define LSTATUS 6 /* line status event interrupt */
X#define MSTATUS 0 /* modem status event interrupt */
X /* line control register bits */
X/* bits 0,1 are number of databits as defined in sgtty.h */
X/* bit 2 is the number of stopbits as defined in sgtty.h */
X#define P_ENABLE 8 /* enable parity bit */
X#define P_EVEN 16 /* even parity bit */
X#define P_STICK 32 /* the parity sticks to 1 on P_EVEN else 0 */
X#define P_BRK 64 /* break enable bit */
X#define P_BAUD 128 /* set up for baud divisor input */
X /* line status register bits */
X#define L_DR 1 /* data recieved status bit */
X#define L_OE 2 /* overrun error status bit */
X#define L_PE 4 /* parity error status bit */
X#define L_FE 8 /* framing error status bit */
X#define L_BI 16 /* break detected status bit */
X#define L_HRE 32 /* holding reg empty status bit */
X#define L_TE 64 /* transmitter empty status bit */
X /* interrupt enable register bits */
X#define I_DR 1 /* enable recieved data interrupt */
X#define I_TE 2 /* enable transmit reg empty interrupt */
X#define I_LS 4 /* reciever line status interrupt */
X#define I_MS 8 /* modem status interrupt */
X /* modem control register bits */
X#define M_DTR 1 /* DTR output bit */
X#define M_RTS 2 /* RTS output bit */
X#define M_OUT1 4 /* OUT1 output bit */
X#define M_OUT2 8 /* OUT2 output bit */
X#define M_LOOP 16 /* enable loopback mode bit */
X /* modem status register bits */
X#define M_CTSC 1 /* CTS input has changed bit */
X#define M_DSRC 2 /* DSR input has changed bit */
X#define M_RIT 4 /* RI input (low to high transition) bit */
X#define M_DCDC 8 /* DCD input has changed bit */
X#define M_CTS 16 /* CTS input bit */
X#define M_DSR 32 /* DSR input bit */
X#define M_RI 64 /* RI input bit */
X#define M_DCD 128 /* DCD input bit */
X
XPRIVATE message mess_8250; /* our message buffer */
XPRIVATE char modem_bits; /* bits for RTS, CTS status etc. */
X
XPRIVATE struct rs_struct {
X int ldata; /* Tx/Rx data register */
X int lreg; /* Line control register */
X int intreg; /* Interrupt control register */
X int intid; /* Interrupt status register */
X int baud; /* Register (& +1) for baud */
X int lstat; /* Line status register */
X int modreg; /* Modem line control register */
X int mstat; /* Modem status register */
X char32 eout; /* Pointer to the echo out buffer */
X char128 wout; /* Pointer to the write out buffer */
X charfbuf in; /* Pointer to the input buffer */
X } rs[NR_8250S] = {{
X 0x3F8, 0x3FB, 0x3F9, 0x3FA, 0x3F8, 0x3FD, 0x3FC, 0x3FE
X , {"",0,0,0}, {"",0,0,0}, {"",0}
X#if NR_8250S >= 2
X },{
X 0x2F8, 0x2FB, 0x2F9, 0x2FA, 0x2F8, 0x2FD, 0x2FC, 0x2FE
X , {"",0,0,0}, {"",0,0,0}, {"",0}
X#endif
X#if NR_8250S >= 3
XError:- Need Extra port tables for COM3 ...
X#endif
X }};
X
X/*===========================================================================*
X * init_8250 *
X *===========================================================================*/
XPUBLIC void init_8250(tp)
Xregister tty_entry *tp;
X{
Xregister i = tp - &tty_struct[COM1];
X
X mess_8250.TTY_LINE= COM1; /* The interrupt message */
X mess_8250.m_type= TTY_CHAR_INT; /* Could have been TTY_O_DONE */
X
X tp->tty_devraw= rout_8250;
X tp->tty_devclr= oclr_8250;
X tp->tty_devflush= do_nothing;
X tp->tty_devioctl= dset_8250;
X tp->tty_devtrans= (unsigned (*)()) do_nothing;
X tp->tty_devempty= iflow_8250;
X
X#ifdef NXONXOFF
X /* 8 Data, 1 Stop bits, No Parity, Hardware handshaking */
X tp->tty_ddmod= D_SERIAL | SER_8DATA;
X#else
X /* 8 Data, 1 Stop bits, No Parity, XONXOFF handshaking */
X tp->tty_ddmod = D_SERIAL | SER_8DATA | TX_XONXOFF | RX_XONXOFF;
X#endif
X tp->tty_mode &= ~(EVENP|ODDP);
X
X#ifdef SLOW
X tp->tty_ispeed = tp->tty_ospeed = B1200;
X#else
X tp->tty_ispeed = tp->tty_ospeed = B4800;
X#endif
X
X tp->tty_fbuf = &rs[i].in;
X fbufinit(rs[i].in);
X bufinit(rs[i].wout);
X bufinit(rs[i].eout);
X modem_bits = (M_DTR|M_RTS|M_OUT2); /* DTR, RTS on, ints enabled */
X
X dset_8250(tp, 0);
X}
X
X
X
X/*===========================================================================*
X * int_8250 *
X *===========================================================================*/
XPUBLIC void int_8250(unit)
X{ /* Interrupts are off */
X /* Called when an interrupt occurs on the RS232 a port */
Xchar c;
Xregister tty_entry *tp= &tty_struct[COM1+unit];
Xregister struct rs_struct *r = &rs[unit];
X
X /* Ignore any interrupts on lines we don't know about */
X if (unit >= NR_8250S) return;
X
X while(TRUE) {
X port_in(r->intid, &c);
X
X if (c&IPENDING) break; /* no interrupt to process */
X
X switch (c & ITYPEMASK) {
X case RXREADY: /* Get a character */
X port_in(r->ldata,&c);
X
X /* Store the char if possible */
X if ( bufnfull(r->in) ) {
X /* Enough room so store the char */
X putfobj(r->in,c);
X }
X
X /* Tell other routines we have chars available */
X tp->tty_state |= IN_FLUSH;
X flush_flag |= IN_FLUSH;
X
X /* Send the int message to tty task only if abs. needed */
X if (bufcount(r->in) >= CHAR_BUF_THRESHOLD) {
X /* Do Flow Control */
X tp->tty_state |= RX_FLOW;
X if (tp->tty_ddmod & RX_XONXOFF)
X /* jam a ^S into the output stream */
X port_out(r->ldata,XOFFCHAR);
X else {
X /* hardware hanshaking */
X modem_bits &= ~M_DTR;
X port_out(r->modreg,modem_bits);
X }
X interrupt(TTY, &mess_8250);
X }
X /* The high level routine must turn back on the flow control */
X break;
X
X case TXREADY: /* Transmit more data */
X /* XT and some clones generate spurious ints */
X port_in(r->lstat,&c);
X if (!(c&L_HRE)) break;
X
X tp->tty_state &= ~BUSY; /* Assume port now free */
X
X /* Get data from the echo stream */
X if (bufnempty(r->eout)) {
X port_out(r->ldata,getobj(r->eout));
X advgetobj(r->eout);
X tp->tty_state |= BUSY;
X break;
X }
X
X /* If inhibited don't get data from write stream */
X if (tp->tty_state&(INHIBITED|TX_FLOW)) break;
X
X /* get data from write stream */
X if (bufnempty(r->wout)) {
X port_out(r->ldata,getobj(r->wout));
X advgetobj(r->wout);
X tp->tty_state |= BUSY;
X }
X
X /* If nearly empty make an attempt at getting more */
X if (bufcount(r->wout) <= WOUT_THRESHOLD
X && tp->tty_writers) {
X tp->tty_state |= OUT_FLUSH;
X flush_flag |= OUT_FLUSH;
X }
X
X /* No more data available, urgently try to get more */
X if (bufempty(r->wout) && tp->tty_writers) {
X tp->tty_state |= OUT_FLUSH;
X interrupt(TTY,&mess_8250);
X }
X break;
X
X case LSTATUS: /* line status event */
X port_in(r->lstat, &c); /* disabled */
X break;
X
X case MSTATUS: /* modem status event */
X port_in(r->mstat, &c);
X /* XONXOFF output flow cntrl in device indep driver */
X if (tp->tty_ddmod & TX_XONXOFF) break;
X
X if ((c&(M_CTS|M_DSR)) == (M_CTS|M_DSR))
X tp->tty_state &= ~TX_FLOW;
X else
X tp->tty_state |= TX_FLOW;
X break;
X }
X }
X port_out(INT_CTL,ENABLE);
X}
X
X
X/*===========================================================================*
X * rout_8250 *
X *===========================================================================*/
XPRIVATE bool rout_8250(tp,c,prio)
Xregister tty_entry *tp;
Xchar c;
X{
X/* Fill up the buffers in FIFO manner according to the priority */
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X save_st = lock();
X /* If not busy then send echo's straight to the hardware */
X if (!(tp->tty_state&BUSY) && (prio==ECHO_OUT)) {
X port_out(r->ldata,c);
X tp->tty_state |= BUSY;
X restore(save_st);
X return 0;
X }
X
X /* Transmitter currently busy or char in write stream. Queue it FIFO */
X /* If ECHO_OUT and not enough space then try in write stream */
X if (prio==ECHO_OUT && bufnfull(r->eout)) {
X putobj(r->eout,c);
X restore(save_st);
X return 0;
X }
X
X /* Place in write stream if there is enough room */
X if (bufnfull(r->wout)) {
X putobj(r->wout,c);
X }
X
X /* If still not busy try to restart IO.
X * This is subject to characters being writable (^S processing).
X */
X if (!(tp->tty_state&(INHIBITED|BUSY|TX_FLOW)) && bufnempty(r->wout)) {
X port_out(r->ldata,getobj(r->wout));
X advgetobj(r->wout);
X tp->tty_state |= BUSY;
X }
X
X /* Warn the user if the stream is filling up */
X restore(save_st);
X return (prio==ECHO_OUT
X || (int)bufcount(r->wout) >= (int)bufsize(r->wout)*7/8);
X}
X
Xstatic unsigned char SBHigh[]= {0,9,9,6,4,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0}
X ,SBLow[]={0,0xE4,0,0,0x17,0x59,0,0x40,0x80,0xC0
X ,0x60,0x40,0x3A,0x30,0x18,0xC,6,3,2,1};
X
X/*===========================================================================*
X * dset_8250 *
X *===========================================================================*/
XPRIVATE void dset_8250(tp, m)
Xregister tty_entry *tp;
Xmessage *m;
X{
Xint c, save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X/* set baud rate, bits/char, etc
X */
X if (m)
X switch(m->TTY_REQUEST) {
X case TIOCSETN:
X case TIOCSETP:
X /* Don't support split baud */
X tp->tty_ospeed= tp->tty_ispeed;
X break;
X
X case TIOCSETM:
X /* Only keep Valid Mode bits */
X tp->tty_ddmod &= SER_2STOP|SER_DATABITS|RX_XONXOFF|TX_XONXOFF;
X tp->tty_ddmod |= D_SERIAL;
X break;
X
X case TIOCMODS:
X port_in(r->modreg, &c);
X c &= ~(M_DTR|M_RTS);
X if (((int)m->TTY_FLAGS) & TIOCM_DTR) c |= M_DTR;
X if (((int)m->TTY_FLAGS) & TIOCM_RTS) c |= M_RTS;
X port_out(r->modreg, c);
X return;
X
X case TIOCMODG:
X port_in(r->modreg, &c);
X m->TTY_FLAGS = (long)((unsigned) TIOCM_LE
X | ((c&M_DTR) ? TIOCM_DTR : 0)
X | ((c&M_RTS) ? TIOCM_RTS : 0));
X port_in(r->mstat, &c);
X m->TTY_FLAGS |= (long)((unsigned) ((c&M_CTS) ? TIOCM_CTS : 0)
X | ((c&M_DCD) ? TIOCM_CAR : 0)
X | ((c&M_DSR) ? TIOCM_DSR : 0)
X | ((c&M_RI ) ? TIOCM_RNG : 0));
X m->TTY_SPEK = 0;
X return;
X
X case TIOCSBRK:
X port_in(r->lreg, &c);
X c |= P_BRK;
X port_out(r->lreg, c);
X return;
X
X case TIOCCBRK:
X port_in(r->lreg, &c);
X c &= ~P_BRK;
X port_out(r->lreg, c);
X return;
X
X case TIOCSDTR:
X port_in(r->modreg, &c);
X c |= M_DTR;
X port_out(r->modreg, c);
X return;
X
X case TIOCCDTR:
X port_in(r->modreg, &c);
X c &= ~M_DTR;
X port_out(r->modreg, c);
X return;
X
X case TIOCSMLB:
X port_in(r->modreg, &c);
X c |= M_LOOP;
X port_out(r->modreg, c);
X return;
X
X case TIOCCMLB:
X port_in(r->modreg, &c);
X c &= ~M_LOOP;
X port_out(r->modreg, c);
X return;
X
X default: /* Ignore all other ioctl calls */
X return;
X }
X
X /* set up c with line control params i.e. data,stop,parity */
X c = tp->tty_ddmod & (SER_2STOP|SER_DATABITS);
X if (tp->tty_mode&ANYP) {
X c |= P_ENABLE;
X if (tp->tty_mode&EVENP) c |= P_EVEN;
X }
X
X /* Now set according to the modes */
X save_st = lock();
X
X port_out(r->lreg,P_BAUD); /* Set up for baud */
X port_out(r->baud+1,SBHigh[tp->tty_ospeed]); /* set Baud rate */
X port_out(r->baud,SBLow[tp->tty_ospeed]);
X
X port_out(r->lreg,c); /* set data, stop & parity */
X
X port_in(r->lstat, &c); /* Clear any data from controller */
X if (c & L_DR) port_in(r->ldata,&c);
X
X port_in(r->mstat,&c); /* Check output flow control */
X tp->tty_state &= ~TX_FLOW;
X if (!(tp->tty_ddmod&TX_XONXOFF) && (c&(M_CTS|M_DSR)) != (M_CTS|M_DSR))
X tp->tty_state |= TX_FLOW;
X
X if (tp->tty_state & RX_FLOW) { /* cancel input flow control */
X modem_bits |= M_DTR; /* set up DTR etc */
X port_out(r->ldata,XONCHAR); /* jam ^Q in output */
X tp->tty_state &= ~RX_FLOW;
X }
X port_out(r->modreg,modem_bits);
X if (tp->tty_ddmod&TX_XONXOFF)
X port_out(r->intreg, I_DR|I_TE ); /* TX & RX ints */
X else
X port_out(r->intreg, I_DR|I_TE|I_MS); /* TX, RX & MS ints */
X
X restore(save_st);
X}
X
X/*===========================================================================*
X * oclr_8250 *
X *===========================================================================*/
XPRIVATE void oclr_8250(tp)
Xregister tty_entry *tp;
X{
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X save_st = lock();
X bufinit(r->eout);
X bufinit(r->wout);
X restore(save_st);
X}
X
X/*===========================================================================*
X * iflow_8250 *
X *===========================================================================*/
XPRIVATE void iflow_8250(tp)
Xregister tty_entry *tp;
X{
X/* The input buffers have been cleared ...
X * Handle flow control for the input stream
X */
X if (tp->tty_state & RX_FLOW) {
X if (tp->tty_ddmod & RX_XONXOFF) /* XON-XOFF handshaking */
X rout_8250(tp, XONCHAR, ECHO_OUT);
X else { /* Hardware handshaking */
X modem_bits |= M_DTR;
X port_out(rs[tp - &tty_struct[COM1]].modreg,modem_bits);
X }
X tp->tty_state &= ~RX_FLOW;
X }
X}
*-*-END-of-tty3.c-*-*
exit