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