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