evans@ditsyda.oz (Bruce Evans) (01/02/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 3 (of 3)." # Contents: tty.c # Wrapped by sys@besplex on Mon Jan 2 04:34:30 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'tty.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tty.c'\" else echo shar: Extracting \"'tty.c'\" \(37486 characters\) sed "s/^X//" >'tty.c' <<'END_OF_FILE' X/* This file contains the terminal driver, both for the IBM console and regular X * ASCII terminals. It is split into two sections, a device-independent part X * and a device-dependent part. The device-independent part accepts X * characters to be printed from programs and queues them in a standard way X * for device-dependent output. It also accepts input and queues it for X * programs. This file contains 2 main entry points: tty_task() and keyboard(). X * When a key is struck on a terminal, an interrupt to an assembly language X * routine is generated. This routine saves the machine state and registers X * and calls keyboard(), which enters the character in an internal table, and X * then sends a message to the terminal task. The main program of the terminal X * task is tty_task(). It accepts not only messages about typed input, but X * also requests to read and write from terminals, etc. X * X * The device-dependent part interfaces with the IBM console and ASCII X * terminals. The IBM keyboard is unusual in that keystrokes yield key numbers X * rather than ASCII codes, and furthermore, an interrupt is generated when a X * key is depressed and again when it is released. The IBM display is memory X * mapped, so outputting characters such as line feed, backspace and bell are X * tricky. X * X * The valid messages and their parameters are: X * X * TTY_CHAR_INT: a character has been typed (obsolete) X * TTY_O_DONE: output has been completed or input has arrived (HARD_INT) X * TTY_READ: a process wants to read from a terminal X * TTY_WRITE: a process wants to write on a terminal X * TTY_IOCTL: a process wants to change a terminal's parameters X * TTY_SETPGRP: indicate a change in a control terminal X * CANCEL: terminate a previous incomplete system call immediately X * X * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS X * --------------------------------------------------------------------------- X * | TTY_CHAR_INT| | | | | | | X * |-------------+---------+---------+---------+---------+---------+---------| X * | TTY_O_DONE | | | | | | | X * |-------------+---------+---------+---------+---------+---------+---------| X * | TTY_READ |minor dev| proc nr | count | | | buf ptr | X * |-------------+---------+---------+---------+---------+---------+---------| X * | TTY_WRITE |minor dev| proc nr | count | | | buf ptr | X * |-------------+---------+---------+---------+---------+---------+---------| X * | TTY_IOCTL |minor dev| proc nr |func code|erase etc| flags | | X * |-------------+---------+---------+---------+---------+---------+---------| X * | TTY_SETPGRP |minor dev| proc nr | | | | | X * |-------------+---------+---------+---------+---------+---------+--------- X * | CANCEL |minor dev| proc nr | | | | | X * --------------------------------------------------------------------------- X */ X X#include "../h/const.h" X#include "../h/type.h" X#include "../h/callnr.h" X#include "../h/com.h" X#include "../h/error.h" X#include "../h/sgtty.h" X#include "../h/signal.h" X#include "const.h" X#include "type.h" X#include "glo.h" X#include "proc.h" X#include "tty.h" X#include "ttymaps.h" X X/* Array and macros to convert line numbers to structure pointers. */ XPRIVATE struct tty_struct *p_tty_addr[NR_CONS + NR_RS_LINES]; X#define ctty_addr(line) (&tty_struct[(line)]) /* faster if line is const */ X#define tty_addr(line) (p_tty_addr[(line)]) X X/* Macros for magic tty types. */ X#define isconsole(tp) ((tp) < ctty_addr(NR_CONS)) X#define isrs232(tp) ((tp) >= ctty_addr(NR_CONS)) X X/* Macros for magic tty line numbers. */ X#define isttyline(line) ((unsigned) (line) < NR_CONS + NR_RS_LINES) X X/* Macros for magic tty structure pointers. */ X#define FIRST_TTY (ctty_addr(0)) X#define END_TTY (ctty_addr(NR_CONS + NR_RS_LINES)) X X/* Miscellaneous. */ X#define LF '\012' /* '\n' is not portablly a LF */ X XPRIVATE unsigned reply_count; /* counts tty_reply() calls */ XPRIVATE unsigned tty_awake; /* nonzero after wakeup till do_int() exits */ X X X/*===========================================================================* X * tty_task * X *===========================================================================*/ XPUBLIC tty_task() X{ X/* Main routine of the terminal task. */ X X message tty_mess; /* buffer for all incoming messages */ X register struct tty_struct *tp; X X tty_init(); X while (TRUE) { X receive(ANY, &tty_mess); X if (!isttyline(tty_mess.TTY_LINE)) { X tty_mess.m_type = -1; /* force error */ X tty_mess.TTY_LINE = 0; /* so hardware ints can get through */ X } X tp = tty_addr(tty_mess.TTY_LINE); X switch(tty_mess.m_type) { X case TTY_O_DONE: /* same action as TTY_CHAR_INT */ X case TTY_CHAR_INT: do_int(); break; X case TTY_READ: do_read(tp, &tty_mess); break; X case TTY_WRITE: do_write(tp, &tty_mess); break; X case TTY_IOCTL: do_ioctl(tp, &tty_mess); break; X case TTY_SETPGRP: do_setpgrp(tp, &tty_mess); break; X case CANCEL: do_cancel(tp, &tty_mess); break; X default: tty_reply(TASK_REPLY, tty_mess.m_source, X tty_mess.PROC_NR, EINVAL); X } X } X} X X X/*===========================================================================* X * do_int * X *===========================================================================*/ XPRIVATE do_int() X{ X/* The TTY task can generate two kinds of interrupts: X * - a character has been received from the console or an RS232 line. X * - an RS232 line has completed a write request (on behalf of a user). X * The interrupt handler may delay the interrupt message at its discretion X * to avoid swamping the TTY task. Messages may be overwritten when the X * lines are fast or when there are races between different lines, input X * and output, because MINIX only provides single buffering for interrupt X * messages (in proc.c). This is handled by explicitly checking each line X * for fresh input and completed output on each interrupt. Input is given X * priority so signal characters are not delayed by lots of small output X * requests. This does not signifigantly delay the detection of output X * completions, since TTY will be scheduled to handle the output before X * any new user can request input. X * X * If a reply is sent (to FS), further input/output must not be processed X * for fear of sending a second message to FS, which would be lost under X * certain race conditions. E.g. when FS is now ready and is about to X * sendrec() to TTY (usually from rw_dev()). FS handles the deadlock X * resulting from the _first_ send() from TTY clashing with the sendrec() X * from FS. But then the scheduling causes the retried sendrec() to get X * through, so the second send() fails with an E_LOCKED error. This might X * be avoided by preempting tasks like TTY over servers like FS, or giving X * preference to senders over receivers. In practice, TTY relies on being X * woken at a later clock tick. X */ X X char *buf; X static struct tty_struct *last_tp = FIRST_TTY; /* round-robin service */ X unsigned char odone; X register char *rbuf; X unsigned remaining; X register struct tty_struct *tp; X unsigned wrapcount; X X tp = last_tp; X do { X if (++tp >= END_TTY) X tp = FIRST_TTY; X X /* Transfer any fresh input to TTY's buffer, and test output done. */ X remaining = (*tp->tty_devread)(tp->tty_line, &buf, &odone); X if (remaining == 0) X goto check_output; /* avoid even uglier indentantion */ X X rbuf = buf; X if (!isconsole(tp) && tp->tty_mode & RAW) { X /* Avoid grotesquely inefficient in_char() except for console X * which needs further (misplaced) translation. X * Line feeds need not be counted. X */ X X /* If queue becomes too full, ask external device to stop. */ X if (tp->tty_incount < tp->tty_ihighwater && X tp->tty_incount + remaining >= tp->tty_ihighwater) X rs_istop(tp->tty_line); X X if (remaining > tp->tty_insize - tp->tty_incount) X /* not all fit, discard */ X remaining = tp->tty_insize - tp->tty_incount; X wrapcount = tp->tty_inbufend - tp->tty_inhead; X if (wrapcount < remaining) { X memcpy(tp->tty_inhead, rbuf, wrapcount); X tp->tty_inhead = tp->tty_inbuf; X rbuf += wrapcount; X tp->tty_incount += wrapcount; X remaining -= wrapcount; X } X memcpy(tp->tty_inhead, rbuf, remaining); X tp->tty_inhead += remaining; X tp->tty_incount += remaining; X } else { X reply_count = 0; /* detect any reply */ X do X in_char(tp, *rbuf++); X while (--remaining != 0); X if (reply_count != 0) X break; /* already cancelled, avoid replying twice */ X } X X /* Possibly restart output (in case there were xoffs or echoes). */ X (*tp->tty_devstart)(tp); X X /* See if a previously blocked reader can now be satisfied. */ X if (tp->tty_inleft != 0 && tp->tty_incount != 0 && X (tp->tty_mode & (RAW | CBREAK) || tp->tty_lfct != 0)) { X /* Tell hanging reader that chars have arrived. */ X tty_reply(REVIVE, (int) tp->tty_incaller, X (int) tp->tty_inproc, rd_chars(tp)); X break; /* avoid replying twice */ X } X Xcheck_output: X /* Finish off any completed block of output. */ X if (odone) { X if (tp->tty_rwords > 0) { X /* not echo */ X tp->tty_phys += tp->tty_rwords; X tp->tty_cum += tp->tty_rwords; X tp->tty_outleft -= tp->tty_rwords; X if (tp->tty_outleft == 0) { X finish(tp, tp->tty_cum); X break; /* avoid replying twice */ X } X } X tp->tty_rwords = 0; X rs_ocancel(tp->tty_line); /* tty_ocancel does too much*/ X (*tp->tty_devstart)(tp); /* maybe continue output */ X } X } X while (tp != last_tp || tty_events >= EVENT_THRESHOLD); X tty_awake = FALSE; X last_tp = tp; X} X X X/*===========================================================================* X * in_char * X *===========================================================================*/ XPRIVATE in_char(tp, ch) Xregister struct tty_struct *tp; /* terminal on which char arrived */ Xregister char ch; /* scan code for character that arrived */ X{ X/* A character has just been typed in. Process, save, and echo it. */ X X int mode, sig, scode, c; X int make_break(); X X scode = ch; /* save the scan code */ X X /* Function keys are temporarily being used for debug dumps. */ X if (isconsole(tp) && ch >= F1 && ch <= F10) { /* Check for function keys */ X func_key(ch); /* process function key */ X return; X } X mode = tp->tty_mode & (RAW | CBREAK); X if (tp->tty_makebreak == TWO_INTS) { X c = make_break(ch); /* console give 2 ints/ch */ X if (c == -1) return; X ch = c; X } X else X if (mode != RAW) ch &= 0177; /* 7-bit chars except in raw mode */ X X /* Processing for COOKED and CBREAK mode contains special checks. */ X if (mode == COOKED || mode == CBREAK) { X /* Handle erase, kill and escape processing. */ X if (mode == COOKED) { X /* First erase processing (rub out of last character). */ X if (ch == tp->tty_erase && tp->tty_escaped == NOT_ESCAPED) { X if (chuck(tp) != -1) /* remove last char entered */ X backover(tp); X return; X } X X /* Now do kill processing (remove current line). */ X if (ch == tp->tty_kill && tp->tty_escaped == NOT_ESCAPED) { X while( chuck(tp) == OK) /* keep looping */ ; X echo(tp, tp->tty_kill); X echo (tp, '\n'); X return; X } X X /* Handle EOT and the escape symbol (backslash). */ X if (tp->tty_escaped == NOT_ESCAPED) { X /* Normal case: previous char was not backslash. */ X if (ch == '\\') { X /* An escaped symbol has just been typed. */ X tp->tty_escaped = ESCAPED; X echo(tp, ch); X return; /* do not store the '\' */ X } X /* CTRL-D means end-of-file, unless it is escaped. It X * is stored in the text as MARKER, and counts as a X * line feed in terms of knowing whether a full line X * has been typed already. X */ X if (ch == tp->tty_eof) { X ch = MARKER; X if (tp->tty_incount < tp->tty_insize) X tp->tty_lfct++; /* counts as LF */ X } X } else { X /* Previous character was backslash. */ X tp->tty_escaped = NOT_ESCAPED; /* turn escaping off */ X backover(tp); /* to overwrite or re-echo */ X if (ch != tp->tty_erase && ch != tp->tty_kill && X ch != tp->tty_eof) X /* Store the escape previously skipped over */ X in1_char(tp, '\\'); X } X } X /* Both COOKED and CBREAK modes come here; first map CR to LF. */ X if (ch == '\r' && (tp->tty_mode & CRMOD)) ch = '\n'; X X /* Check for interrupt and quit characters. */ X if (ch == tp->tty_intr || ch == tp->tty_quit) { X sig = (ch == tp->tty_intr ? SIGINT : SIGQUIT); X sigchar(tp, sig); X return; X } X X /* Check for and process CTRL-S (terminal stop). */ X if (ch == tp->tty_xoff) { X tp->tty_inhibited = STOPPED; X if (isrs232(tp)) X rs_inhibit(tp->tty_line, TRUE); /* sync avoid races */ X return; X } X X /* Check for and process terminal start character, now anything. */ X if (tp->tty_inhibited == STOPPED) X uninhibit(tp); X X /* Check for and discard xon (terminal start). */ X if (ch == tp->tty_xon) X return; X } X X /* All 3 modes come here. */ X if (ch == '\n' && tp->tty_incount < tp->tty_insize) X tp->tty_lfct++; /* count line feeds */ X X /* The numeric pad generates ASCII escape sequences: ESC [ letter */ X if (isconsole(tp) && scode >= SCODE1 && scode <= SCODE2 && X shift1 == 0 && shift2 == 0 && numlock == 0) { X /* This key is to generate a three-character escape sequence. */ X in1_char(tp, ESC); X in1_char(tp, BRACKET); X ch = scode_map[scode-SCODE1]; /* generate the letter */ X } X X in1_char(tp, ch); X} X X X#ifdef i8088 X/*===========================================================================* X * make_break * X *===========================================================================*/ XPRIVATE int make_break(ch) Xchar ch; /* scan code of key just struck or released */ X{ X/* This routine can handle keyboards that interrupt only on key depression, X * as well as keyboards that interrupt on key depression and key release. X * For efficiency, the interrupt routine filters out most key releases. X */ X X int c, make, code; X X /* Check for CTRL-ALT-DEL, and if found, reboot the computer. This would X * be better done in keyboard() in case TTY is hung, except control and X * alt are set in the high level code. X */ X if (control && alt && ch == DEL_CODE) reboot(); /* CTRL-ALT-DEL */ X X c = ch & 0177; /* high-order bit set on key release */ X make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */ X X if (alt && keyb_type == DUTCH_EXT) X code = alt_c[c]; X else X code = (shift1 || shift2 ? sh[c] : unsh[c]); X X if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ X if (numlock && c > 70 && c < 0x56) X code = (shift1 || shift2 ? unsh[c] : sh[c]); X X code &= BYTE; X if (code < 0200 || code >= 0206) { X /* Ordinary key, i.e. not shift, control, alt, etc. */ X if (capslock) X if (code >= 'A' && code <= 'Z') X code += 'a' - 'A'; X else if (code >= 'a' && code <= 'z') X code -= 'a' - 'A'; X if (alt && keyb_type != DUTCH_EXT) code |= 0200; /* alt ORs in 0200 */ X if (control) code &= 037; X if (make == 0) code = -1; /* key release */ X return(code); X } X X /* Table entries 0200 - 0206 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 && caps_off) { X capslock = 1 - capslock; X set_leds(); X } X caps_off = 1 - make; X break; /* caps lock */ X case 5: if (make && num_off) { X numlock = 1 - numlock; X set_leds(); X } X num_off = 1 - make; X break; /* num lock */ X } X return(-1); X} X#endif X X X/*===========================================================================* X * echo * X *===========================================================================*/ XPRIVATE echo(tp, c) Xregister struct tty_struct *tp; /* terminal on which to echo */ Xregister char c; /* character to echo */ X{ X/* Echo a character on the terminal. */ X X if ( (tp->tty_mode & ECHO) == 0) return; /* if no echoing, don't echo */ X/* MARKER is meaningful only in cooked mode */ X if (c != MARKER || tp->tty_mode & (CBREAK | RAW)) { X if (isconsole(tp)) { X out_char(tp, c); /* echo to console */ X flush(tp); /* force character out onto screen */ X } X else if (tp->tty_etail < tp->tty_ebufend) X *tp->tty_etail++ = c; /* echo to RS232 line */ X } X} X X X/*===========================================================================* X * chuck * X *===========================================================================*/ XPRIVATE int chuck(tp) Xregister struct tty_struct *tp; /* from which tty should chars be removed */ X{ X/* Delete one character from the input queue. Used for erase and kill. */ X X char *prev; X X /* If input queue is empty, don't delete anything. */ X if (tp->tty_incount == 0) return(-1); X X /* Don't delete '\n' or '\r'. */ X prev = (tp->tty_inhead != tp->tty_inbuf ? tp->tty_inhead - 1 : X tp->tty_inbufend - 1); X if (*prev == '\n' || *prev == '\r') return(-1); X tp->tty_inhead = prev; X X /* If queue becomes empty enough, tell external device it can start. */ X if (--tp->tty_incount == tp->tty_ilow_water && isrs232(tp)) X rs_istart(tp->tty_line); X return(OK); /* char erasure was possible */ X} X X X/*===========================================================================* X * do_read * X *===========================================================================*/ XPRIVATE do_read(tp, m_ptr) Xregister struct tty_struct *tp; Xmessage *m_ptr; /* pointer to message sent to the task */ X{ X/* A process wants to read from a terminal. */ X X if (tp->tty_inleft > 0) { /* if someone else is hanging, give up */ X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO); X return; X } X X /* Copy information from the message to the tty struct. */ X tp->tty_incaller = m_ptr->m_source; X tp->tty_inproc = m_ptr->PROC_NR; X tp->tty_in_vir = m_ptr->ADDRESS; X tp->tty_inleft = m_ptr->COUNT; X X /* Try to get chars. This call either gets enough, or gets nothing. */ X tty_reply(TASK_REPLY, m_ptr->m_source, (int) tp->tty_inproc, rd_chars(tp)); X} X X X/*===========================================================================* X * rd_chars * X *===========================================================================*/ XPRIVATE int rd_chars(tp) Xregister struct tty_struct *tp; /* pointer to terminal to read from */ X{ X/* A process wants to read from a terminal. First check if enough data is X * available. If so, pass it to the user. If not, send FS a message telling X * it to suspend the user. When enough data arrives later, the tty driver X * copies it to the user space directly and notifies FS with a message. X */ X X char *bufend; X int ct; X register char *rtail; X int user_ct; X int user_cum; X phys_bytes user_phys; X extern phys_bytes umap(); X X if (tp->tty_incount == 0 || X !(tp->tty_mode & (RAW | CBREAK)) && tp->tty_lfct == 0) X return(SUSPEND); X if ( (user_phys = umap(proc_addr(tp->tty_inproc), D, X (vir_bytes) tp->tty_in_vir, X (vir_bytes) tp->tty_inleft)) == 0) X return(E_BAD_ADDR); X if (tp->tty_inleft > tp->tty_incount) X tp->tty_inleft = tp->tty_incount; X user_cum = 0; X X do { X rtail = tp->tty_intail; X if ( (ct = tp->tty_inleft) > tp->tty_inbufend - rtail) X ct = tp->tty_inbufend - rtail; X X /* Be careful about CTRL-D. In cooked X * mode it is not transmitted to user programs, and is not counted as X * a character as far as the count goes, but it does occupy space in X * the driver's tables and must be counted there. X */ X user_ct = ct; X if (!(tp->tty_mode & (RAW | CBREAK))) { X /* COOKED mode. X * Don't bother counting lines in CBREAK and RAW modes. X */ X for (bufend = rtail + ct; rtail < bufend;) { X if (*rtail++ == '\n') { X user_ct = X tp->tty_inleft = X ct = rtail - tp->tty_intail; X tp->tty_lfct--;; X break; X } X if (rtail[-1] == MARKER) { X tp->tty_inleft = X ct = rtail - tp->tty_intail; X user_ct = ct - 1; X tp->tty_lfct--; X break; X } X } X } X X /* Copy at least half of buffer to user space. */ X phys_copy(tp->tty_inphys + (tp->tty_intail - tp->tty_inbuf), X user_phys, (phys_bytes) user_ct); X user_phys += user_ct; X user_cum += user_ct; X if ( (tp->tty_intail += ct) == tp->tty_inbufend) X tp->tty_intail = tp->tty_inbuf; X tp->tty_inleft -= ct; X if ( (tp->tty_incount -= ct) <= tp->tty_ilow_water && X tp->tty_incount + ct > tp->tty_ilow_water && isrs232(tp)) X rs_istart(tp->tty_line); X } X while (tp->tty_inleft != 0); X return(user_cum); X} X X X/*===========================================================================* X * finish * X *===========================================================================*/ XPUBLIC finish(tp, code) Xregister struct tty_struct *tp; Xint code; /* reply code */ X{ X/* A command has terminated (possibly due to DEL). Tell caller. */ X X if (tp->tty_waiting != NOT_WAITING) X tty_reply(tp->tty_waiting == SUSPENDED ? REVIVE : TASK_REPLY, X (int) tp->tty_otcaller, (int) tp->tty_outproc, code); X tty_ocancel(tp); X} X X X/*===========================================================================* X * do_write * X *===========================================================================*/ XPRIVATE do_write(tp, m_ptr) Xregister struct tty_struct *tp; Xmessage *m_ptr; /* pointer to message sent to the task */ X{ X/* A process wants to write on a terminal. */ X X vir_bytes out_vir, out_left; X struct proc *rp; X extern phys_bytes umap(); X X /* If the slot is already in use, better return an error than mess it up. */ X if (tp->tty_outleft > 0) { /* if someone else is hanging, give up */ X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO); X return; X } X X /* Copy message parameters to the tty structure. */ X tp->tty_otcaller = m_ptr->m_source; X tp->tty_outproc = m_ptr->PROC_NR; X tp->tty_out_vir = m_ptr->ADDRESS; X tp->tty_outleft = m_ptr->COUNT; X tp->tty_waiting = WAITING; X tp->tty_cum = 0; X X /* Compute the physical address where the data is in user space. */ X rp = proc_addr(tp->tty_outproc); X out_vir = (vir_bytes) tp->tty_out_vir; X out_left = (vir_bytes) tp->tty_outleft; X if ( (tp->tty_phys = umap(rp, D, out_vir, out_left)) == 0) { X /* Buffer address provided by user is outside its address space. */ X tp->tty_cum = E_BAD_ADDR; X tp->tty_outleft = 0; X } X X /* Copy characters from the user process to the terminal. */ X (*tp->tty_devstart)(tp); /* copy data to queue and start I/O */ X X /* If output is for a bitmapped terminal as the IBM-PC console, the output- X * routine will return at once so there is no need to suspend the caller, X * on ascii terminals however, the call is suspended and later revived. X * Oops, even bitmapped terminals need suspension after an XOFF. X */ X if (tp->tty_outleft > 0) { X tty_reply(TASK_REPLY, (int) tp->tty_otcaller, (int) tp->tty_outproc, X SUSPEND); X tp->tty_waiting = SUSPENDED; X } X} X X X/*===========================================================================* X * do_ioctl * X *===========================================================================*/ XPRIVATE do_ioctl(tp, m_ptr) Xregister struct tty_struct *tp; Xmessage *m_ptr; /* pointer to message sent to task */ X{ X/* Perform IOCTL on this terminal. */ X X long flags, erki, erase, kill, intr, quit, xon, xoff, eof; X int r; X int argn; X message ioctl_mess; X X r = OK; X flags = 0; X erki = 0; X switch(m_ptr->TTY_REQUEST) { X case TIOCSETP: X /* Set erase, kill, and flags. */ X tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE); /* erase */ X tp->tty_kill = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE); /* kill */ X tp->tty_mode = (int) m_ptr->TTY_FLAGS; /* mode word */ X if (!(tp->tty_mode & (RAW | CBREAK))) { X /* (Re)calculate the line count. The logic of rd_chars() X * requires newlines and MARKERs returned in cooked mode X * to be interpreted as line ends, even if they were X * received in another mode. X */ X int ct; X register char *rtail; X X tp->tty_lfct = 0; X for (rtail = tp->tty_intail, ct = tp->tty_incount; X ct-- != 0;) { X if (*rtail == '\n' || *rtail == MARKER) X ++tp->tty_lfct; X if (++rtail == tp->tty_inbufend) X rtail = tp->tty_inbuf; X } X /* The column should really be recalculated for RS232, but X * is too much trouble. X */ X } X if (tp->tty_mode & RAW) X /* Inhibited RAW mode makes no sense since there is no way X * to uninhibit it. The inhibition flag must be cleared X * explicitly since the drivers check it in all modes. X */ X uninhibit(tp); X if (m_ptr->TTY_SPEED != 0) tp->tty_speed = m_ptr->TTY_SPEED; X if (isrs232(tp)) X tp->tty_speed = rs_ioctl(tp->tty_line, tp->tty_mode, X tp->tty_speed); X break; X X case TIOCSETC: X /* Set intr, quit, xon, xoff, eof (brk not used). */ X tp->tty_intr = (char) ((m_ptr->TTY_SPEK >> 24) & BYTE); /* interrupt */ X tp->tty_quit = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE); /* quit */ X tp->tty_xon = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE); /* CTRL-S */ X tp->tty_xoff = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE); /* CTRL-Q */ X tp->tty_eof = (char) ((m_ptr->TTY_FLAGS >> 8) & BYTE); /* CTRL-D */ X if (isrs232(tp)) X rs_setc(tp->tty_line, tp->tty_xoff); X break; X X case TIOCGETP: X /* Get erase, kill, and flags. */ X erase = ((long) tp->tty_erase) & BYTE; X kill = ((long) tp->tty_kill) & BYTE; X erki = (erase << 8) | kill; X flags = ( (long) tp->tty_speed << 16) | (long) tp->tty_mode; X break; X X case TIOCGETC: X /* Get intr, quit, xon, xoff, eof. */ X intr = ((long) tp->tty_intr) & BYTE; X quit = ((long) tp->tty_quit) & BYTE; X xon = ((long) tp->tty_xon) & BYTE; X xoff = ((long) tp->tty_xoff) & BYTE; X eof = ((long) tp->tty_eof) & BYTE; X erki = (intr << 24) | (quit << 16) | (xon << 8) | (xoff << 0); X flags = (eof <<8); X break; X X#ifdef TIOCFLUSH X case TIOCFLUSH: X /* Discard current input and output. */ X tty_icancel(tp); X tty_ocancel(tp); X break; X#endif X } X X /* Send the reply. Like tty_reply() with extra arguments flags and erki. */ X ioctl_mess.m_type = TASK_REPLY; X ioctl_mess.REP_PROC_NR = m_ptr->PROC_NR; X ioctl_mess.REP_STATUS = r; X ioctl_mess.TTY_FLAGS = flags; X ioctl_mess.TTY_SPEK = erki; X send(m_ptr->m_source, &ioctl_mess); X} X X X/*===========================================================================* X * do_setpgrp * X *===========================================================================*/ XPRIVATE do_setpgrp(tp, m_ptr) Xregister struct tty_struct *tp; Xmessage *m_ptr; /* pointer to message sent to task */ X{ X/* A control process group has changed */ X X tp->tty_pgrp = m_ptr->TTY_PGRP; X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK); X} X X X/*===========================================================================* X * do_cancel * X *===========================================================================*/ XPRIVATE do_cancel(tp, m_ptr) Xregister struct tty_struct *tp; Xmessage *m_ptr; /* pointer to message sent to task */ X{ X/* A signal has been sent to a process that is hanging trying to read or write. X * The pending read or write must be finished off immediately. X */ X X int caller; X int mode; X X /* Check the parameters carefully, to avoid cancelling twice, but don't X * generate error replies since it is normal for sigchar() to have X * already done the cancellation. X */ X caller = m_ptr->PROC_NR; X mode = m_ptr->COUNT; X if (mode & R_BIT && tp->tty_inleft != 0 && caller == tp->tty_inproc) X /* Process was reading when killed. Clean up input. */ X tty_icancel(tp); X if (mode & W_BIT && tp->tty_outleft != 0 && caller == tp->tty_outproc) X /* Process was writing when killed. Clean up output. */ X tty_ocancel(tp); X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR); X} X X X/*===========================================================================* X * tty_reply * X *===========================================================================*/ XPRIVATE tty_reply(code, replyee, proc_nr, status) Xint code; /* TASK_REPLY or REVIVE */ Xint replyee; /* destination address for the reply */ Xint proc_nr; /* to whom should the reply go? */ Xint status; /* reply code */ X{ X/* Send a reply to a process that wanted to read or write data. */ X X message tty_mess; X X tty_mess.m_type = code; X tty_mess.REP_PROC_NR = proc_nr; X tty_mess.REP_STATUS = status; X if ((status = send(replyee, &tty_mess)) != OK) X printf("\r\ntty_reply failed with status\r\n", status); X ++reply_count; X} X X X/*===========================================================================* X * sigchar * X *===========================================================================*/ XPUBLIC sigchar(tp, sig) Xregister struct tty_struct *tp; Xint sig; /* SIGINT, SIGQUIT, or SIGKILL */ X{ X/* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard */ X X uninhibit(tp); /* do implied CRTL-Q */ X finish(tp, EINTR); /* reply and/or cancel output if necessary */ X tty_icancel(tp); X if (tp->tty_pgrp) cause_sig(tp->tty_pgrp, sig); X} X X X/*==========================================================================* X * backover * X *==========================================================================*/ XPRIVATE backover(tp) Xregister struct tty_struct *tp; X{ X/* Backspace to previous character on screen and erase it. */ X X echo(tp, '\b'); X echo(tp, ' '); X echo(tp, '\b'); X} X X X/*==========================================================================* X * in1_char * X *==========================================================================*/ XPRIVATE in1_char(tp, ch) Xregister struct tty_struct *tp; Xchar ch; /* character to be queued */ X{ X/* Put character in terminal input queue without preprocessing, and echo. */ X X if (tp->tty_incount >= tp->tty_insize) X return; /* no room, discard char */ X *tp->tty_inhead++ = ch; /* save the character in the input queue */ X if (tp->tty_inhead == tp->tty_inbufend) X tp->tty_inhead = tp->tty_inbuf; /* handle wraparound */ X if (++tp->tty_incount == tp->tty_ihighwater && isrs232(tp)) X rs_istop(tp->tty_line); X echo(tp, ch); X} X X X/*==========================================================================* X * oprocess * X *==========================================================================*/ XPRIVATE int oprocess(tp, ubuf, ucount) Xregister struct tty_struct *tp; Xchar *ubuf; /* input buffer */ Xint ucount; /* size of input buffer */ X{ X/* Perform output processing on a buffer, translating it into tty_ramqueue. X * The "RAM" queue is now mis-named and has a poorly chosen type even for RAM. X */ X X unsigned char ch; X int spacecount; X register char *tbuf; X char *tbufend; X char *ubufstart; X X tbuf = (char *) tp->tty_ramqueue; X tbufend = tbuf + (sizeof tp->tty_ramqueue - TAB_SIZE); X ubufstart = ubuf; X while (ucount-- != 0 && tbuf < tbufend) { X if ( (ch = *ubuf++) >= ' ') { X ++tp->tty_column; X *tbuf++ = ch; X continue; X } X switch(ch) { X case '\b': X if (tp->tty_column != 0 ) X --tp->tty_column; X break; X case '\r': X tp->tty_column = 0; X break; X case LF: X if (tp->tty_mode & CRMOD) { X /* Map LF to CR+LF. */ X tp->tty_column = 0; X *tbuf++ = '\r'; X } X break; X case '\t': X if (tp->tty_mode & XTABS) { X /* Tabs must be expanded, best guess. */ X spacecount = TAB_SIZE - (tp->tty_column & TAB_MASK); X tp->tty_column += spacecount; X do X *tbuf++ = ' '; X while (--spacecount != 0); X continue; X } X /* Tabs are output directly, don't need column. */ X break; X default: X /* Can't tell if column will change. */ X break; X } X *tbuf++ = ch; X } X tp->tty_rwords = ubuf - ubufstart; X return(tbuf - (char *) tp->tty_ramqueue); X} X X X/*==========================================================================* X * rs_start * X *==========================================================================*/ XPRIVATE rs_start(tp) Xregister struct tty_struct *tp; X{ X/* (*devstart)() routine for RS232. */ X X int count; X X if (tp->tty_rwords != 0) X return; /* already going - xon handled at lower level */ X X if ( (count = tp->tty_etail - tp->tty_ebuf) > 0) { X /* Do output processing on echo buffer and write result. */ X if (tp->tty_mode & RAW) X memcpy((char *) tp->tty_ramqueue, tp->tty_ebuf, count); X else X count = oprocess(tp, tp->tty_ebuf, count); X rs_write(tp->tty_line, (char *) tp->tty_ramqueue, count); X tp->tty_etail = tp->tty_ebuf; /* small ebuf all fitted */ X tp->tty_rwords = -1; /* kludge echo flag */ X } X else if ( (count = tp->tty_outleft) != 0) { X /* Do output processing on user buffer and write result. */ X if (tp->tty_mode & RAW) { X if (count > sizeof tp->tty_ramqueue) X count = sizeof tp->tty_ramqueue; X phys_copy(tp->tty_phys, tp->tty_outphys, (phys_bytes) count); X tp->tty_rwords = count; X } else { X if (count > sizeof tty_buf) X count = sizeof tty_buf; X phys_copy(tp->tty_phys, tty_bphys, (phys_bytes) count); X count = oprocess(tp, tty_buf, count); X } X rs_write(tp->tty_line, (char *) tp->tty_ramqueue, count); X } X} X X X/*==========================================================================* X * tty_icancel * X *==========================================================================*/ XPRIVATE tty_icancel(tp) Xregister struct tty_struct *tp; X{ X/* Discard all data in tty input buffer and driver buffers. */ X X char *buf; X unsigned char odone; X X tp->tty_intail = tp->tty_inhead = tp->tty_inbuf; X if (tp->tty_incount > tp->tty_ilow_water && isrs232(tp)) X rs_istart(tp->tty_line); X tp->tty_incount = 0; X tp->tty_inleft = 0; X tp->tty_lfct = 0; X (*tp->tty_devread)(tp->tty_line, &buf, &odone); /* read (fast) to discard */ X} X X X/*==========================================================================* X * tty_init * X *==========================================================================*/ XPRIVATE tty_init() X{ X/* Initialize tty structure and call driver initialization routines. */ X X int line; X register struct tty_struct *tp; X extern phys_bytes umap(); X X /* Set up wakeup message. */ X wakeup_mess.m_type = TTY_O_DONE; X X for (line = 0; line < NR_CONS + NR_RS_LINES; ++line) { X tp = &tty_struct[line]; X tp->tty_line = line - NR_CONS; X p_tty_addr[line] = tp; X tty_bphys = umap(proc_addr(TTY), D, (vir_bytes) tty_buf, X sizeof tty_buf); X if (isconsole(tp)) { X tp->tty_inbuf = kb_inbuf[line]; X tp->tty_inbufend = tp->tty_inbuf + KB_IN_BYTES; X tp->tty_ihighwater = KB_IN_BYTES; X tp->tty_ilow_water = KB_IN_BYTES; X tp->tty_insize = KB_IN_BYTES; X } else { X tp->tty_inbuf = rs_inbuf[tp->tty_line]; X tp->tty_inbufend = tp->tty_inbuf + RS_IN_BYTES; X tp->tty_ihighwater = RS_IN_BYTES - 2 * RS_IBUFSIZE; X tp->tty_ilow_water = (RS_IN_BYTES - 2 * RS_IBUFSIZE) * 7 / 8; X tp->tty_insize = RS_IN_BYTES; X } X tp->tty_inphys = umap(proc_addr(TTY), D, (vir_bytes)tp->tty_inbuf, X tp->tty_insize); X tp->tty_intail = tp->tty_inhead = tp->tty_inbuf; X tp->tty_outphys = umap(proc_addr(TTY), D, X (vir_bytes) tp->tty_ramqueue, X sizeof tp->tty_ramqueue); X tp->tty_etail = tp->tty_ebuf; X tp->tty_ebufend = tp->tty_ebuf + sizeof tp->tty_ebuf; X tp->tty_erase = ERASE_CHAR; X tp->tty_kill = KILL_CHAR; X tp->tty_intr = INTR_CHAR; X tp->tty_quit = QUIT_CHAR; X tp->tty_xon = XON_CHAR; X tp->tty_xoff = XOFF_CHAR; X tp->tty_eof = EOT_CHAR; X if (isconsole(tp)) { X tp->tty_devread = kb_read; X tp->tty_devstart = console; X tp->tty_mode = CRMOD | XTABS | ECHO; X tp->tty_makebreak = TWO_INTS; X con_init(tp->tty_line); X } else { X tp->tty_devread = rs_read; X tp->tty_devstart = rs_start; X tp->tty_mode = RAW | BITS8; X tp->tty_makebreak = ONE_INT; X tp->tty_speed = rs_init(tp->tty_line); X rs_setc(tp->tty_line, tp->tty_xoff); X } X } X} X X X/*==========================================================================* X * tty_ocancel * X *==========================================================================*/ XPRIVATE tty_ocancel(tp) Xregister struct tty_struct *tp; X{ X/* Discard all data in tty output buffer and driver buffers. */ X X tp->tty_waiting = NOT_WAITING; X tp->tty_outleft = 0; X tp->tty_rwords = 0; X tp->tty_etail = tp->tty_ebuf; X if (isrs232(tp)) X rs_ocancel(tp->tty_line); X} X X X/*==========================================================================* X * tty_wakeup * X *==========================================================================*/ XPUBLIC void tty_wakeup() X{ X/* Wake up TTY when the threshold is reached, or when there is something to X * do but no new events (slow typist), or after a timeout. The threshold X * dominates for fast terminal input and all keyboard input and output X * completions. The timeout smooths slow terminal input. X */ X X#define WAKEUP_TIMEOUT (HZ/20) /* adjust to taste, 1 for fast processor */ X X static unsigned previous_events; X static unsigned wakeup_timeout = WAKEUP_TIMEOUT; X X if (tty_events != 0 && !tty_awake) { X if (tty_events >= EVENT_THRESHOLD || tty_events == previous_events || X --wakeup_timeout == 0) { X interrupt(TTY, &wakeup_mess); X tty_awake = TRUE; X wakeup_timeout = WAKEUP_TIMEOUT; X } X previous_events = tty_events; X } X} X X X/*==========================================================================* X * uninhibit * X *==========================================================================*/ XPRIVATE uninhibit(tp) Xregister struct tty_struct *tp; X{ X/* (Re)allow terminal output. */ X X tp->tty_inhibited = RUNNING; X if (isrs232(tp)) X rs_inhibit(tp->tty_line, FALSE); X} END_OF_FILE if test 37486 -ne `wc -c <'tty.c'`; then echo shar: \"'tty.c'\" unpacked with wrong size! fi # end of 'tty.c' fi echo shar: End of archive 3 \(of 3\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 Bruce Evans evans@ditsyda.oz.au D