bing@galbp.LBP.HARRIS.COM (Bing Bang) (08/04/87)
this is the tty.c file cut it here and at the bottom /* >From: hubble@cae780.UUCP If anyone is interested, I have included a new tty.c driver with this message which implements virtual terminals for MINIX. By using this and setting things up properly, you can have several virtual terminals by simply pressing ALT-1,2,3,4 to see four separate login screens or terminals. To get this to work, you must have: 1) An EGA or CGA graphics device 2) Installed the SIGNAL handling fixes just posted 3) Installed the scrolling mechanism that I posted a while ago 4) Modify your /etc/ttys files to look like: 100 101 102 103 One caveat. The way MINIX handles CNTL-S/Q and terminal interrupts is not very graceful (or is dangerous, or doesn't work, ...). I had to kludge the interrupt handling to work at all. MINIX assumes that the main process dealing with a particular terminal can be found simply by looking at the process resulting from the following computation: LOW_USER + 1 + line. Unfortunately, this is not true since /etc/rc is run by INIT before the other tty's are initialized and /etc/rc leaves the /etc/update process around. In addition, it is possible to shuffle process order if you have several processes active and someone CNTL-D's their login shell. I choose to ignore this and just plan on having /etc/update taking up one process slot after the first tty. So, BEWARE if you change /etc/rc or CNTL-D your login shell with lots of other process activity. With that in mind, try it if you feel the desire. -------------------------------------------------------------------------- Larry R. Hubble Tektronix/CAE Systems Division (408) 296-3593 5302 Betsy Ross Dr. {hplabs,tektronix}!hubble@cae780 Santa Clara, CA 95054 cut here for tty.c: -------------------------------------------------------------------------- */ /* This file contains the terminal driver, both for the IBM console and regular * ASCII terminals. It is split into two sections, a device-independent part * and a device-dependent part. The device-independent part accepts * characters to be printed from programs and queues them in a standard way * for device-dependent output. It also accepts input and queues it for * programs. This file contains 2 main entry points: tty_task() and keyboard(). * When a key is struck on a terminal, an interrupt to an assembly language * routine is generated. This routine saves the machine state and registers * and calls keyboard(), which enters the character in an internal table, and * then sends a message to the terminal task. The main program of the terminal * task is tty_task(). It accepts not only messages about typed input, but * also requests to read and write from terminals, etc. * * The device-dependent part interfaces with the IBM console and ASCII * terminals. The IBM keyboard is unusual in that keystrokes yield key numbers * rather than ASCII codes, and furthermore, an interrupt is generated when a * key is depressed and again when it is released. The IBM display is memory * mapped, so outputting characters such as line feed, backspace and bell are * tricky. * * The valid messages and their parameters are: * * TTY_CHAR_INT: a character has been typed on a terminal (input interrupt) * TTY_O_DONE: a character has been output (output completed interrupt) * TTY_READ: a process wants to read from a terminal * TTY_WRITE: a process wants to write on a terminal * TTY_IOCTL: a process wants to change a terminal's parameters * CANCEL: terminate a previous incomplete system call immediately * * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS * --------------------------------------------------------------------------- * | TTY_CHAR_INT| | | | | |array ptr| * |-------------+---------+---------+---------+---------+---------+---------| * | TTY_O_DONE |minor dev| | | | | | * |-------------+---------+---------+---------+---------+---------+---------| * | TTY_READ |minor dev| proc nr | count | | | buf ptr | * |-------------+---------+---------+---------+---------+---------+---------| * | TTY_WRITE |minor dev| proc nr | count | | | buf ptr | * |-------------+---------+---------+---------+---------+---------+---------| * | TTY_IOCTL |minor dev| proc nr |func code|erase etc| flags | | * |-------------+---------+---------+---------+---------+---------+---------| * | CANCEL |minor dev| proc nr | | | | | * --------------------------------------------------------------------------- */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "../h/sgtty.h" #include "../h/signal.h" #include "const.h" #include "type.h" #include "glo.h" #include "proc.h" #define NR_TTYS 6 /* how many terminals can system handle */ #define TTY_IN_BYTES 200 /* input queue size */ #define TTY_RAM_WORDS 320 /* ram buffer size */ #define TTY_BUF_SIZE 256 /* unit for copying to/from queues */ #define TAB_SIZE 8 /* distance between tabs */ #define TAB_MASK 07 /* mask for tty_column when tabbing */ #define MAX_OVERRUN 127 /* size of overrun input buffer */ #define ERASE_CHAR '\b' /* default erase character */ #define KILL_CHAR '@' /* default kill character */ #define INTR_CHAR (char)0177 /* default interrupt character */ #define QUIT_CHAR (char) 034 /* default quit character */ #define XOFF_CHAR (char) 023 /* default x-off character (CTRL-S) */ #define XON_CHAR (char) 021 /* default x-on character (CTRL-Q) */ #define EOT_CHAR (char) 004 /* CTRL-D */ #define MARKER (char) 000 /* non-escaped CTRL-D stored as MARKER */ #define DEL_CODE (char) 83 /* DEL for use in CTRL-ALT-DEL reboot */ #define AT_SIGN 0220 /* code to yield for CTRL-@ */ #define F1 59 /* scan code for function key F1 */ #define F2 60 /* scan code for function key F2 */ #define F10 68 /* scan code for function key F9 */ #define TOP_ROW 14 /* codes below this are shifted if CTRL */ PRIVATE struct tty_struct { /* Input queue. Typed characters are stored here until read by a program. */ char tty_inqueue[TTY_IN_BYTES]; /* array used to store the characters */ char *tty_inhead; /* pointer to place where next char goes */ char *tty_intail; /* pointer to next char to be given to prog */ int tty_incount; /* # chars in tty_inqueue */ int tty_lfct; /* # line feeds in tty_inqueue */ /* Output section. */ int tty_ramqueue[TTY_RAM_WORDS]; /* buffer for video RAM */ int tty_rwords; /* number of WORDS (not bytes) in outqueue */ int tty_org; /* location in RAM where 6845 base points */ int tty_vid; /* current position of cursor in video RAM */ char tty_esc_state; /* 0=normal, 1 = ESC seen, 2 = ESC + x seen */ char tty_echar; /* first character following an ESC */ int tty_attribute; /* current attribute byte << 8 */ int (*tty_devstart)(); /* routine to start actual device output */ /* Terminal parameters and status. */ int tty_mode; /* terminal mode set by IOCTL */ int tty_column; /* current column number (0-origin) */ int tty_row; /* current row (0 at bottom of screen) */ char tty_busy; /* 1 when output in progress, else 0 */ char tty_escaped; /* 1 when '\' just seen, else 0 */ char tty_inhibited; /* 1 when CTRL-S just seen (stops output) */ char tty_makebreak; /* 1 for terminals that interrupt twice/key */ char tty_waiting; /* 1 when output process waiting for reply */ /* User settable characters: erase, kill, interrupt, quit, x-on; x-off. */ char tty_erase; /* char used to erase 1 char (init ^H) */ char tty_kill; /* char used to erase a line (init @) */ char tty_intr; /* char used to send SIGINT (init DEL) */ char tty_quit; /* char used for core dump (init CTRL-\) */ char tty_xon; /* char used to start output (init CTRL-Q)*/ char tty_xoff; /* char used to stop output (init CTRL-S) */ char tty_eof; /* char used to stop output (init CTRL-D) */ /* Information about incomplete I/O requests is stored here. */ char tty_incaller; /* process that made the call (usually FS) */ char tty_inproc; /* process that wants to read from tty */ char *tty_in_vir; /* virtual address where data is to go */ int tty_inleft; /* how many chars are still needed */ char tty_otcaller; /* process that made the call (usually FS) */ char tty_outproc; /* process that wants to write to tty */ char *tty_out_vir; /* virtual address where data comes from */ phys_bytes tty_phys; /* physical address where data comes from */ int tty_outleft; /* # chars yet to be copied to tty_outqueue */ int tty_cum; /* # chars copied to tty_outqueue so far */ /* Miscellaneous. */ int tty_ioport; /* I/O port number for this terminal */ char tty_speed; /* serial i/o speed */ char tty_cdwait; /* process waiting for CD to go high */ char tty_cdkill; /* proc to send SIGKILL to when CD goes low */ } tty_struct[NR_TTYS]; /* Values for the fields. */ #define NOT_ESCAPED 0 /* previous character on this line not '\' */ #define ESCAPED 1 /* previous character on this line was '\' */ #define RUNNING 0 /* no CRTL-S has been typed to stop the tty */ #define STOPPED 1 /* CTRL-S has been typed to stop the tty */ #define INACTIVE 0 /* the tty is not printing */ #define BUSY 1 /* the tty is printing */ #define ONE_INT 0 /* regular terminals interrupt once per char */ #define TWO_INTS 1 /* IBM console interrupts two times per char */ #define NOT_WAITING 0 /* no output process is hanging */ #define WAITING 1 /* an output process is waiting for a reply */ #define SCREEN_1 2 #define SCREEN_N (SCREEN_1 + NR_TTYS - 3) #define COM_TTY (NR_TTYS-2) /* last two tty for com1 com2 */ PRIVATE char tty_driver_buf[2*MAX_OVERRUN+2]; /* driver collects chars here */ PRIVATE char tty_copy_buf[2*MAX_OVERRUN]; /* copy buf used to avoid races */ PRIVATE char tty_buf[TTY_BUF_SIZE]; /* scratch buffer to/from user space */ PRIVATE int shift1, shift2, capslock, numlock; /* keep track of shift keys */ PRIVATE int control, alt; /* keep track of key statii */ PRIVATE char tty_line; /* current tty line for input */ PRIVATE struct tty_struct *current_tp; /* current tty_struct pointer */ PRIVATE int tty_sent = 0; /* only interrupt once */ PUBLIC int color; /* 1 if console is color, 0 if it is mono */ PUBLIC scan_code; /* scan code for '=' saved by bootstrap */ /* Scan codes to ASCII for unshifted keys */ PRIVATE char unsh[] = { 0,033,'1','2','3','4','5','6', '7','8','9','0','-','=','\b','\t', 'q','w','e','r','t','y','u','i', 'o','p','[',']',015,0202,'a','s', 'd','f','g','h','j','k','l',';', 047,0140,0200,0134,'z','x','c','v', 'b','n','m',',','.','/',0201,'*', 0203,' ',0204,0241,0242,0243,0244,0245, 0246,0247,0250,0251,0252,0205,0210,0267, 0270,0271,0211,0264,0265,0266,0214 ,0261, 0262,0263,'0',0177 }; /* Scan codes to ASCII for shifted keys */ PRIVATE char sh[] = { 0,033,'!','@','#','$','%','^', '&','*','(',')','_','+','\b','\t', 'Q','W','E','R','T','Y','U','I', 'O','P','{','}',015,0202,'A','S', 'D','F','G','H','J','K','L',':', 042,'~',0200,'|','Z','X','C','V', 'B','N','M','<','>','?',0201,'*', 0203,' ',0204,0221,0222,0223,0224,0225, 0226,0227,0230,0231,0232,0204,0213,'7', '8','9',0211,'4','5','6',0214,'1', '2','3','0',0177 }; /* Scan codes to ASCII for Olivetti M24 for unshifted keys. */ PRIVATE char unm24[] = { 0,033,'1','2','3','4','5','6', '7','8','9','0','-','^','\b','\t', 'q','w','e','r','t','y','u','i', 'o','p','@','[','\r',0202,'a','s', 'd','f','g','h','j','k','l',';', ':',']',0200,'\\','z','x','c','v', 'b','n','m',',','.','/',0201,'*', 0203,' ',0204,0241,0242,0243,0244,0245, 0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261, 0262,0263,'0','.',' ',014,0212,'\r', 0264,0262,0266,0270,032,0213,' ','/', 0253,0254,0255,0256,0257,0215,0216,0217 }; /* Scan codes to ASCII for Olivetti M24 for shifted keys. */ PRIVATE char m24[] = { 0,033,'!','"','#','$','%','&', 047,'(',')','_','=','~','\b','\t', 'Q','W','E','R' ,'T','Y','U','I', 'O','P',0140,'{','\r',0202,'A','S', 'D','F','G','H','J','K','L','+', '*','}',0200,'|','Z','X','C','V', 'B','N','M','<','>','?',0201,'*', 0203,' ',0204,0221,0222,0223,0224,0225, 0226,0227,0230,0231,0232,0270,023,'7', '8','9',0211,'4','5','6',0214,'1', '2','3',0207,0177,0271,014,0272,'\r', '\b','\n','\f',036,032,0273,0274,'/', 0233,0234,0235,0236,0237,0275,0276,0277 }; /*===========================================================================* * tty_task * *===========================================================================*/ PUBLIC tty_task() { /* Main routine of the terminal task. */ message tty_mess; /* buffer for all incoming messages */ register struct tty_struct *tp; tty_init(); /* initialize */ while (TRUE) { receive(ANY, &tty_mess); tp = &tty_struct[tty_mess.TTY_LINE]; switch(tty_mess.m_type) { case TTY_CHAR_INT: do_charint(&tty_mess); break; case TTY_READ: do_read(tp, &tty_mess); break; case TTY_WRITE: do_write(tp, &tty_mess); break; case TTY_IOCTL: do_ioctl(tp, &tty_mess); break; case CANCEL: do_cancel(tp, &tty_mess); break; case TTY_O_DONE: finish(tp, tp->tty_cum); break; default: tty_reply(TASK_REPLY, tty_mess.m_source, tty_mess.PROC_NR, EINVAL, 0L, 0L); } } } /*===========================================================================* * do_charint * *===========================================================================*/ PRIVATE do_charint(m_ptr) message *m_ptr; /* message containing pointer to char(s) */ { /* A character has been typed. If a character is typed and the tty task is * not able to service it immediately, the character is accumulated within * the tty driver. Thus multiple chars may be accumulated. A single message * to the tty task may have to process several characters. */ int m, n, count, replyee, caller; char *ptr, *copy_ptr, ch; struct tty_struct *tp; lock(); /* prevent races by disabling interrupts */ ptr = m_ptr->ADDRESS; /* pointer to accumulated char array */ copy_ptr = tty_copy_buf; /* ptr to shadow array where chars copied */ n = *ptr; /* how many chars have been accumulated */ count = n; /* save the character count */ n = n + n; /* each char occupies 2 bytes */ ptr += 2; /* skip count field at start of array */ while (n-- > 0) *copy_ptr++ = *ptr++; /* copy the array to safety */ ptr = m_ptr->ADDRESS; *ptr = 0; /* accumulation count set to 0 */ tty_sent = 0; unlock(); /* re-enable interrupts */ /* Loop on the accumulated characters, processing each in turn. */ copy_ptr = tty_copy_buf; while (count-- > 0) { ch = *copy_ptr++; /* get the character typed */ n = *copy_ptr++; /* get the line number it came in on */ in_char(n, ch); /* queue the char and echo it */ /* See if a previously blocked reader can now be satisfied. */ tp = &tty_struct[n]; /* pointer to struct for this character */ if (tp->tty_inleft > 0 ) { /* does anybody want input? */ m = tp->tty_mode & (CBREAK | RAW); if (tp->tty_lfct > 0 || (m != 0 && tp->tty_incount > 0)) { m = rd_chars(tp); /* Tell hanging reader that chars have arrived. */ replyee = (int) tp->tty_incaller; caller = (int) tp->tty_inproc; if(m != SUSPEND) tty_reply(REVIVE, replyee, caller, m, 0L, 0L); } } } } /*===========================================================================* * in_char * *===========================================================================*/ PRIVATE in_char(line, ch) int line; /* line number on which char arrived */ char ch; /* scan code for character that arrived */ { /* A character has just been typed in. Process, save, and echo it. */ register struct tty_struct *tp; int mode, sig, interrupt_proc; char make_break(); tp = &tty_struct[line]; /* set 'tp' to point to proper struct */ mode = tp->tty_mode & (RAW | CBREAK); if(line < COM_TTY) { if (ch >= F1 && ch <= F10) /* Check for function keys F1, F2, ... F10 */ { func_key(ch); /* process function key */ return; } /* An ALT-1,2,3,4 selects the virtual screen to send input to */ if ( alt && (ch >= SCREEN_1 && ch <= SCREEN_N) ) { vir_screen_change(ch - SCREEN_1); return; } /* Function keys are temporarily being used for debug dumps. */ if(tp->tty_makebreak) ch = make_break(ch); /* console give 2 ints/ch */ else if (mode != RAW) ch &= 0177; /* 7-bit chars except in raw mode */ if (ch == 0) return; } if (tp->tty_incount >= TTY_IN_BYTES) return; /* no room, discard char */ /* Processing for COOKED and CBREAK mode contains special checks. */ if (mode == COOKED || mode == CBREAK) { /* Handle erase, kill and escape processing. */ if (mode == COOKED) { /* First erase processing (rub out of last character). */ if (ch == tp->tty_erase && tp->tty_escaped == NOT_ESCAPED) { if (chuck(tp) == OK) { /* remove last char entered */ echo(tp, '\b'); /* remove from the screen */ echo(tp, ' '); echo(tp, '\b'); } return; } /* Now do kill processing (remove current line). */ if (ch == tp->tty_kill && tp->tty_escaped == NOT_ESCAPED) { while( chuck(tp) == OK) { /* keep looping */ echo(tp, '\b'); /* remove from the screen */ echo(tp, ' '); echo(tp, '\b'); } return; } /* Handle EOT and the escape symbol (backslash). */ if (tp->tty_escaped == NOT_ESCAPED) { /* Normal case: previous char was not backslash. */ if (ch == '\\') { /* An escaped symbol has just been typed. */ tp->tty_escaped = ESCAPED; echo(tp, ch); return; /* do not store the '\' */ } /* CTRL-D means end-of-file, unless it is escaped. It * is stored in the text as MARKER, and counts as a * line feed in terms of knowing whether a full line * has been typed already. */ if (ch == tp->tty_eof) ch = MARKER; } else { /* Previous character was backslash. */ tp->tty_escaped = NOT_ESCAPED; /* turn escaping off */ if (ch != tp->tty_erase && ch != tp->tty_kill && ch != tp->tty_eof) { /* Store the escape previously skipped over */ *tp->tty_inhead++ = '\\'; tp->tty_incount++; if (tp->tty_inhead == &tp->tty_inqueue[TTY_IN_BYTES]) tp->tty_inhead = tp->tty_inqueue; } } } /* Both COOKED and CBREAK modes come here; first map CR to LF. */ if (ch == '\r' && (tp->tty_mode & CRMOD)) ch = '\n'; /* Check for interrupt and quit characters. */ if (ch == tp->tty_intr || ch == tp->tty_quit) { sig = (ch == tp->tty_intr ? SIGINT : SIGQUIT); tp->tty_inhibited = RUNNING; /* do implied CRTL-Q */ interrupt_proc = LOW_USER + 1 + line; if (line > 0) interrupt_proc++; finish(tp, EINTR); /* send reply */ tty_signal(tp, interrupt_proc, sig); return; } /* Check for and process CTRL-S (terminal stop). */ if (ch == tp->tty_xoff) { tp->tty_inhibited = STOPPED; return; } /* Check for and process CTRL-Q (terminal start). */ if (ch == tp->tty_xon) { tp->tty_inhibited = RUNNING; (*tp->tty_devstart)(tp); /* resume output */ return; } } /* All 3 modes come here. */ if (ch == '\n' || ch == MARKER) tp->tty_lfct++; /* count line feeds */ *tp->tty_inhead++ = ch; /* save the character in the input queue */ if (tp->tty_inhead == &tp->tty_inqueue[TTY_IN_BYTES]) tp->tty_inhead = tp->tty_inqueue; /* handle wraparound */ tp->tty_incount++; echo(tp, ch); } tty_signal(tp, tproc, sig) struct tty_struct *tp; int tproc, sig; { tp->tty_inhead = tp->tty_inqueue; /* discard input */ tp->tty_intail = tp->tty_inqueue; tp->tty_incount = 0; tp->tty_lfct = 0; cause_sig(tproc, sig); } #ifdef i8088 /*===========================================================================* * make_break * *===========================================================================*/ PRIVATE char make_break(ch) char ch; /* scan code of key just struck or released */ { /* This routine can handle keyboards that interrupt only on key depression, * as well as keyboards that interrupt on key depression and key release. * For efficiency, the interrupt routine filters out most key releases. */ int c, make, code; c = ch & 0177; /* high-order bit set on key release */ make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */ if (olivetti == FALSE) { /* Standard IBM keyboard. */ code = (shift1 || shift2 || capslock ? sh[c] : unsh[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ if (c > 70 && numlock) code = sh[c]; /* numlock depressed */ } else { /* (Olivetti M24 or AT&T 6300) with Olivetti-style keyboard. */ code = (shift1 || shift2 || capslock ? m24[c] : unm24[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ if (c > 70 && numlock) code = m24[c]; /* numlock depressed */ } code &= BYTE; if (code < 0200 || code >= 0206) { /* Ordinary key, i.e. not shift, control, alt, etc. */ if (alt) code |= 0200; /* alt key ORs 0200 into code */ if (control) code &= 037; if (code == 0) code = AT_SIGN; /* @ is 0100, so CTRL-@ = 0 */ if (make == 0) code = 0; /* key release */ return(code); } /* Table entries 0200 - 0206 denote special actions. */ switch(code - 0200) { case 0: shift1 = make; break; /* shift key on left */ case 1: shift2 = make; break; /* shift key on right */ case 2: control = make; break; /* control */ case 3: alt = make; break; /* alt key */ case 4: if (make) capslock = 1 - capslock; break; /* caps lock */ case 5: if (make) numlock = 1 - numlock; break; /* num lock */ } return(0); } #endif /*===========================================================================* * echo * *===========================================================================*/ PRIVATE echo(tp, c) register struct tty_struct *tp; /* terminal on which to echo */ register char c; /* character to echo */ { /* Echo a character on the terminal. */ if ( (tp->tty_mode & ECHO) == 0) return; /* if no echoing, don't echo */ if (c != MARKER) out_char(tp, c); flush(tp); /* force character out onto the screen */ } /*===========================================================================* * chuck * *===========================================================================*/ PRIVATE int chuck(tp) register struct tty_struct *tp; /* from which tty should chars be removed */ { /* Delete one character from the input queue. Used for erase and kill. */ char *prev; /* If input queue is empty, don't delete anything. */ if (tp->tty_incount == 0) return(-1); /* Don't delete '\n' or '\r'. */ prev = (tp->tty_inhead != tp->tty_inqueue ? tp->tty_inhead - 1 : &tp->tty_inqueue[TTY_IN_BYTES-1]); if (*prev == '\n' || *prev == '\r') return(-1); tp->tty_inhead = prev; tp->tty_incount--; return(OK); /* char erasure was possible */ } /*===========================================================================* * do_read * *===========================================================================*/ PRIVATE do_read(tp, m_ptr) register struct tty_struct *tp; /* pointer to tty struct */ message *m_ptr; /* pointer to message sent to the task */ { /* A process wants to read from a terminal. */ int code; if (tp->tty_inleft > 0) { /* if someone else is hanging, give up */ tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L); return; } /* Copy information from the message to the tty struct. */ tp->tty_incaller = m_ptr->m_source; tp->tty_inproc = m_ptr->PROC_NR; tp->tty_in_vir = m_ptr->ADDRESS; tp->tty_inleft = m_ptr->COUNT; /* Try to get chars. This call either gets enough, or gets nothing. */ code = rd_chars(tp); if(code != SUSPEND) tty_reply(TASK_REPLY, m_ptr->m_source, tp->tty_inproc, code, 0L, 0L); } /*===========================================================================* * rd_chars * *===========================================================================*/ PRIVATE int rd_chars(tp) register struct tty_struct *tp; /* pointer to terminal to read from */ { /* A process wants to read from a terminal. First check if enough data is * available. If so, pass it to the user. If not, send FS a message telling * it to suspend the user. When enough data arrives later, the tty driver * copies it to the user space directly and notifies FS with a message. */ int cooked, ct, user_ct, buf_ct, cum, enough, eot_seen; vir_bytes in_vir, left; phys_bytes user_phys, tty_phys; char ch, *tty_ptr; struct proc *rp; extern phys_bytes umap(); cooked = ( (tp->tty_mode & (RAW | CBREAK)) ? 0 : 1); /* 1 iff COOKED mode */ if (tp->tty_incount == 0 || (cooked && tp->tty_lfct == 0)) return(SUSPEND); rp = proc_addr(tp->tty_inproc); in_vir = (vir_bytes) tp-> tty_in_vir; left = (vir_bytes) tp->tty_inleft; if ( (user_phys = umap(rp, D, in_vir, left)) == 0) return(E_BAD_ADDR); tty_phys = umap(proc_addr(TTY), D, (vir_bytes) tty_buf, TTY_BUF_SIZE); cum = 0; enough = 0; eot_seen = 0; /* The outer loop iterates on buffers, one buffer load per iteration. */ while (tp->tty_inleft > 0) { buf_ct = MIN(tp->tty_inleft, tp->tty_incount); buf_ct = MIN(buf_ct, TTY_BUF_SIZE); ct = 0; tty_ptr = tty_buf; /* The inner loop fills one buffer. */ while(buf_ct-- > 0) { ch = *tp->tty_intail++; if (tp->tty_intail == &tp->tty_inqueue[TTY_IN_BYTES]) tp->tty_intail = tp->tty_inqueue; *tty_ptr++ = ch; ct++; if (ch == '\n' || ch == MARKER) { tp->tty_lfct--; if (cooked && ch == MARKER) eot_seen++; enough++; /* exit loop */ if (cooked) break; /* only provide 1 line */ } } /* Copy one buffer to user space. Be careful about CTRL-D. In cooked * mode it is not transmitted to user programs, and is not counted as * a character as far as the count goes, but it does occupy space in * the driver's tables and must be counted there. */ user_ct = (eot_seen ? ct - 1 : ct); /* bytes to copy to user */ phys_copy(tty_phys, user_phys, (phys_bytes) user_ct); user_phys += user_ct; cum += user_ct; tp->tty_inleft -= ct; tp->tty_incount -= ct; if (tp->tty_incount == 0 || enough) break; } tp->tty_inleft = 0; return(cum); } /*===========================================================================* * finish * *===========================================================================*/ PRIVATE finish(tp, code) register struct tty_struct *tp; /* pointer to tty struct */ int code; /* reply code */ { /* A command has terminated (possibly due to DEL). Tell caller. */ tp->tty_rwords = 0; tp->tty_outleft = 0; if (tp->tty_waiting == NOT_WAITING) return; tty_reply(REVIVE, tp->tty_otcaller, tp->tty_outproc, code, 0L, 0L); tp->tty_waiting = NOT_WAITING; } /*===========================================================================* * do_write * *===========================================================================*/ PRIVATE do_write(tp, m_ptr) register struct tty_struct *tp; /* pointer to tty struct */ register message *m_ptr; /* pointer to message sent to the task */ { /* A process wants to write on a terminal. */ vir_bytes out_vir, out_left; struct proc *rp; extern phys_bytes umap(); if (tp->tty_waiting == WAITING) { /* if someone else is hanging, give up */ tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L); return; } /* Copy message parameters to the tty structure. */ tp->tty_otcaller = m_ptr->m_source; tp->tty_outproc = m_ptr->PROC_NR; tp->tty_out_vir = m_ptr->ADDRESS; tp->tty_outleft = m_ptr->COUNT; tp->tty_waiting = WAITING; tp->tty_cum = 0; /* Compute the physical address where the data is in user space. */ rp = proc_addr(tp->tty_outproc); out_vir = (vir_bytes) tp->tty_out_vir; out_left = (vir_bytes) tp->tty_outleft; if ( (tp->tty_phys = umap(rp, D, out_vir, out_left)) == 0) { /* Buffer address provided by user is outside its address space. */ tp->tty_cum = E_BAD_ADDR; tp->tty_outleft = 0; } /* Copy characters from the user process to the terminal. */ (*tp->tty_devstart)(tp); /* copy data to queue and start I/O */ } /*===========================================================================* * do_ioctl * *===========================================================================*/ PRIVATE do_ioctl(tp, m_ptr) register struct tty_struct *tp; /* pointer to tty_struct */ message *m_ptr; /* pointer to message sent to task */ { /* Perform IOCTL on this terminal. */ long flags, erki, erase, kill, intr, quit, xon, xoff, eof; int r, d, p; r = OK; flags = 0; erki = 0; switch(m_ptr->TTY_REQUEST) { case TIOCSETP: /* Set erase, kill, and flags. */ tp->tty_speed = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE); tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE); /* erase */ tp->tty_kill = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE); /* kill */ tp->tty_mode = (int) m_ptr->TTY_FLAGS; /* mode word */ set_port(tp); break; case TIOCSETC: /* Set intr, quit, xon, xoff, eof (brk not used). */ tp->tty_intr = (char) ((m_ptr->TTY_SPEK >> 24) & BYTE); /* interrupt */ tp->tty_quit = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE); /* quit */ tp->tty_xon = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE); /* CTRL-S */ tp->tty_xoff = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE); /* CTRL-Q */ tp->tty_eof = (char) ((m_ptr->TTY_FLAGS >> 8) & BYTE); /* CTRL-D */ break; case TIOCGETP: /* Get erase, kill, and flags. */ erase = ((long) tp->tty_erase) & BYTE; kill = ((long) tp->tty_kill) & BYTE; intr = ((long) tp->tty_speed) & BYTE; erki = (intr << 16) | (erase << 8) | kill; flags = (long) tp->tty_mode; break; case TIOCGETC: /* Get intr, quit, xon, xoff, eof. */ intr = ((long) tp->tty_intr) & BYTE; quit = ((long) tp->tty_quit) & BYTE; xon = ((long) tp->tty_xon) & BYTE; xoff = ((long) tp->tty_xoff) & BYTE; eof = ((long) tp->tty_eof) & BYTE; erki = (intr << 24) | (quit << 16) | (xon << 8) | (xoff << 0); flags = (eof <<8); break; case TIOCDTRL: case TIOCDTRH: d= m_ptr->TTY_REQUEST & DTRCTL; tp->tty_mode &= ~DTRCTL; tp->tty_mode |= d; if(p = tp->tty_ioport) port_out(p + 4, 0x0a | (d? 1 : 0)); break; case TIOCCARW: lock(); if(tp->tty_mode & CDLINE) { unlock(); break; /* no need to wait */ } tp->tty_cdwait = m_ptr->PROC_NR; unlock(); return; case TIOCCARK: lock(); tp->tty_cdkill = m_ptr->PROC_NR; unlock(); case TIOCCARC: lock(); tp->tty_cdkill = 0; unlock(); case TIOCICNT: r = tp->tty_incount; break; default: r = EINVAL; } /* Send the reply. */ tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r, flags, erki); } /*===========================================================================* * do_cancel * *===========================================================================*/ PRIVATE do_cancel(tp, m_ptr) register struct tty_struct *tp; /* pointer to tty_struct */ message *m_ptr; /* pointer to message sent to task */ { /* A signal has been sent to a process that is hanging trying to read or write. * The pending read or write must be finished off immediately. */ /* First check to see if the process is indeed hanging. If it is not, don't * reply (to avoid race conditions). */ tp->tty_cdkill = 0; if (tp->tty_inleft == 0 && tp->tty_outleft == 0 && tp->tty_cdkill == 0) return; /* Kill off input and output. */ tp->tty_inhead = tp->tty_inqueue; /* discard all input */ tp->tty_intail = tp->tty_inqueue; tp->tty_cdwait = 0; tp->tty_incount = 0; tp->tty_lfct = 0; tp->tty_inleft = 0; tp->tty_outleft = 0; tp->tty_mode &= ~TXING; tp->tty_waiting = NOT_WAITING; /* don't send reply */ tp->tty_inhibited = RUNNING; tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR, 0L, 0L); } /*===========================================================================* * tty_reply * *===========================================================================*/ PRIVATE tty_reply(code, replyee, proc_nr, status, extra, other) int code; /* TASK_REPLY or REVIVE */ int replyee; /* destination address for the reply */ int proc_nr; /* to whom should the reply go? */ int status; /* reply code */ long extra; /* extra value */ long other; /* used for IOCTL replies */ { /* Send a reply to a process that wanted to read or write data. */ message tty_mess; tty_mess.m_type = code; tty_mess.REP_PROC_NR = proc_nr; tty_mess.REP_STATUS = status; tty_mess.TTY_FLAGS = extra; /* used by IOCTL for flags (mode) */ tty_mess.TTY_SPEK = other; /* used by IOCTL for erase and kill chars */ send(replyee, &tty_mess); } /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ #ifdef i8088 /* Now begins the code and data for the device-dependent tty drivers. */ /* Definitions used by the *console driver. */ #define COLOR_BASE 0xB800 /* video ram paragraph for color display */ #define MONO_BASE 0xB000 /* video ram address for mono display */ #define C_VID_MASK 0x7FFF /* mask for 16K video RAM */ #define M_VID_MASK 0x0FFF /* mask for 4K video RAM */ #define C_RETRACE 0x0300 /* how many characters to display at once */ #define M_RETRACE 0x7000 /* how many characters to display at once */ #define WORD_MASK 0xFFFF /* mask for 16 bits */ #define OFF_MASK 0x000F /* mask for 4 bits */ #define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ #define B_TIME 0x2000 /* how long to sound the CTRL-G `beep tone */ #define BLANK 0x0700 /* determines cursor color on blank screen */ #define LINE_WIDTH 80 /* # characters on a line */ #define SCR_LINES 25 /* # lines on the screen */ #define CTRL_S 31 /* scan code for letter S (for CRTL-S) */ #define MONOCHROME 1 /* value for tty_ioport tells color vs. mono */ #define CONSOLE 0 /* line number for console */ #define GO_FORWARD 0 /* scroll forward */ #define GO_BACKWARD 1 /* scroll backward */ #define TIMER2 0x42 /* I/O port for timer channel 2 */ #define TIMER3 0x43 /* I/O port for timer channel 3 */ #define KEYBD 0x60 /* I/O port for keyboard data */ #define PORT_B 0x61 /* I/O port for 8255 port B */ #define KBIT 0x80 /* bit used to ack characters to keyboard */ /* Constants relating to the video RAM and 6845. */ #define M_6845 0x3B0 /* port for 6845 mono */ #define C_6845 0x3D0 /* port for 6845 color */ #define INDEX 4 /* 6845's index register */ #define DATA 5 /* 6845's data register */ #define CUR_SIZE 10 /* 6845's cursor size register */ #define VID_ORG 12 /* 6845's origin register */ #define CURSOR 14 /* 6845's cursor register */ /* Definitions used for determining if the keyboard is IBM or Olivetti type. */ #define KB_STATUS 0x64 /* Olivetti keyboard status port */ #define BYTE_AVAIL 0x01 /* there is something in KEYBD port */ #define KB_BUSY 0x02 /* KEYBD port ready to accept a command */ #define DELUXE 0x01 /* this bit is set up iff deluxe keyboard */ #define GET_TYPE 5 /* command to get keyboard type */ #define OLIVETTI_EQUAL 12 /* the '=' key is 12 on olivetti, 13 on IBM */ /* Global variables used by the console driver. */ PUBLIC message keybd_mess; /* message used for console input chars */ PRIVATE vid_retrace; /* how many characters to display per burst */ PRIVATE unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */ PUBLIC int vid_mask; /* 037777 for color (16K) or 07777 for mono */ PRIVATE int vid_port; /* I/O port for accessing 6845 */ PRIVATE int com_ports[]={0x3f8,0x2f8}; /* com port addresses */ PRIVATE int baudrate[]= { 384, /* 300 baud */ 96, /* 1200 */ 48, /* 2400 */ 24, /* 4800 */ 12 /* 9600 */ }; PRIVATE char uart_tbl[]= { 0x2, 0x3, 0x0a, 0x0b, 0x2, 0x3, 0x1a, 0x1b, 0x6, 0x7, 0x0e, 0x0f, 0x6, 0x7, 0x1e, 0x1f }; #define xmode(m) (uart_tbl[UARTMASK & ((m) >> 12)]) /*===========================================================================* * keyboard * *===========================================================================*/ PUBLIC keyboard() { /* A keyboard interrupt has occurred. Process it. */ int val, code, k, raw_bit, x, i; char stopc; /* Fetch the character from the keyboard hardware and acknowledge it. */ port_in(KEYBD, &code); /* get the scan code for the key struck */ port_in(PORT_B, &val); /* strobe the keyboard to ack the char */ port_out(PORT_B, val | KBIT); /* strobe the bit high */ port_out(PORT_B, val); /* now strobe it low */ port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */ /* The IBM keyboard interrupts twice per key, once when depressed, once when * released. Filter out the latter, ignoring all but the shift-type keys. * The shift-type keys, 29, 42, 54, 56, and 69 must be processed normally. */ k = code - 0200; /* codes > 0200 mean key release */ if (k > 0) { /* A key has been released. */ if (k != 29 && k != 42 && k != 54 && k != 56 && k != 69) { return; /* don't call tty_task() */ } } else { /* Check to see if character is CTRL-S, to stop output. Setting xoff * to anything other than CTRL-S will not be detected here, but will * be detected later, in the driver. A general routine to detect any * xoff character here would be complicated since we only have the * scan code here, not the ASCII character. */ port_out(TIMER3,0xB6); /* klick the keyboard */ port_out(TIMER2, 0x33); /* load low-order bits of frequency in timer */ port_out(TIMER2,0x03); /* now high-order bits of frequency in timer */ port_in(PORT_B,&x); /* acquire status of port B */ port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */ for(i=0x090;i--;); port_out(PORT_B, x); /* restore port B the way it was */ raw_bit = tty_struct[tty_line].tty_mode & RAW; stopc = tty_struct[tty_line].tty_xoff; if (raw_bit == 0 && control && code == CTRL_S && stopc == XOFF_CHAR) { tty_struct[tty_line].tty_inhibited = STOPPED; return; } } /* Check for CTRL-ALT-DEL, and if found, reboot the computer. */ if (control && alt && code == DEL_CODE) reboot(); /* CTRL-ALT-DEL */ tty_inque(code, tty_line); } /*===========================================================================* * coms_int * *===========================================================================*/ coms_int(line) int line; { /* serial port interrupt handler */ int k,stat,intstat,port; struct tty_struct *tp; port_out(INT_CTL, ENABLE); line+=COM_TTY; tp= &tty_struct[line]; port=tp->tty_ioport; loop: port_in(port + 2, &intstat); if(intstat & 1) return; switch(intstat & 0x06) { case 4: /* receiver full */ port_in(port, &stat); /* get the char */ if (!(tp->tty_mode & RAW) && stat == CTRL_S && tp->tty_xoff == XOFF_CHAR) { tp->tty_inhibited = STOPPED; break; } tty_inque(stat, line); break; case 2: /* transmiter empty */ if(tp->tty_mode & TXING) com_ch_out(port, tp, line); break; case 0: /* modem status */ port_in(port + 6, &stat); if(stat & 0x08) /* delta to carrier detect */ { if(stat & 0x80) /* carrier high? */ { tp->tty_mode |= CDLINE; if(k = tp->tty_cdwait) { tp->tty_cdwait=0; tty_reply(TASK_REPLY, FS_PROC_NR, k, OK, 0L, 0L); } } else /* carrier just fell */ { tp->tty_mode &= ~CDLINE; if(k = tp->tty_cdkill) { tp->tty_cdkill=0; tty_signal(tp, k, SIGKILL); } } } break; case 6: /* receive line status */ port_in(port + 5, &stat); /* clear status */ port_in(port, &stat); /* throw out the junk byte */ break; } goto loop; /* horrors of edge triggered multiple interrupts, and the bug-that-is-a-feature 8250, 8250A, 8250B can you say "bad design?" */ } tty_inque(code, line) int code, line; { int k; /* Store the character in memory so the task can get at it later. */ if((k = tty_driver_buf[0]) < tty_driver_buf[1]) { k = k + k + 2; /* each entry contains two bytes */ tty_driver_buf[k++] = code; /* store the scan code */ tty_driver_buf[k] = line; /* tell which line it came from */ tty_driver_buf[0]++; /* increment counter */ } if(tty_sent) return; /* no need to send interrupt */ /* Build and send the interrupt message. */ keybd_mess.m_type = TTY_CHAR_INT; keybd_mess.ADDRESS = tty_driver_buf; mini_send(TTY, TTY, &keybd_mess); /* send a message to the tty task */ tty_sent = 1; } /*===========================================================================* * com_out * *===========================================================================*/ PRIVATE com_out(tp) register struct tty_struct *tp; /* tells which terminal is to be used */ { /* start serial output by sending out first byte if transmiter is empty. */ int count; char c; unsigned port, line; port = tp->tty_ioport; port_in(port + 5, &line); if(!(line & 0x60)) return; tp->tty_mode |= TXING; com_ch_out(port, tp, tp - &tty_struct[0]); } com_ch_out(port, tp, dev) int port; struct tty_struct *tp; int dev; { phys_bytes p; p = tp->tty_phys; if(tp->tty_outleft == 0) { keybd_mess.m_type = TTY_O_DONE; keybd_mess.TTY_LINE = dev; mini_send(TTY, TTY, &keybd_mess); tp->tty_mode &= ~TXING; return; } if(tp->tty_inhibited == RUNNING) { port_out(port, get_byte((int)((p >> 4) & WORD_MASK), (int)(p & OFF_MASK))); tp->tty_phys++; /* move pointer */ tp->tty_outleft--; /* decrement count */ tp->tty_cum++; /* number of chars printed */ } } out_comport(tp, c) register struct tty_struct *tp; char c; { int s, p; p = tp->tty_ioport + 5; lock(); do { port_in(p, &s); } while((s & 0x60) == 0); port_out(p - 5, c); unlock(); } /*===========================================================================* * console * *===========================================================================*/ PRIVATE console(tp) register struct tty_struct *tp; /* tells which terminal is to be used */ { /* Copy as much data as possible to the output queue, then start I/O. On * memory-mapped terminals, such as the IBM console, the I/O will also be * finished, and the counts updated. Keep repeating until all I/O done. */ int count; char c; unsigned segment, offset, offset1; /* Loop over the user bytes one at a time, outputting each one. */ segment = (tp->tty_phys >> 4) & WORD_MASK; offset = tp->tty_phys & OFF_MASK; offset1 = offset; count = 0; while (tp->tty_outleft > 0 && tp->tty_inhibited == RUNNING) { c = get_byte(segment, offset); /* fetch 1 byte from user space */ out_char(tp, c); /* write 1 byte to terminal */ offset++; /* advance one character in user buffer */ tp->tty_outleft--; /* decrement count */ } flush(tp); /* clear out the pending characters */ /* Update terminal data structure. */ count = offset - offset1; /* # characters printed */ tp->tty_phys += count; /* advance physical data pointer */ tp->tty_cum += count; /* number of characters printed */ /* If all data has been copied to the terminal, send the reply. */ if (tp->tty_outleft == 0) finish(tp, tp->tty_cum); } /*===========================================================================* * out_char * *===========================================================================*/ PRIVATE out_char(tp, c) register struct tty_struct *tp; /* pointer to tty struct */ char c; /* character to be output */ { /* Output a character on the console. Check for escape sequences, including * ESC 32+x 32+y to move cursor to (x, y) * ESC ~ 0 to clear from cursor to end of screen * ESC ~ 1 to reverse scroll the screen 1 line * ESC z x to set the attribute byte to x (z is a literal here) */ if(tp->tty_ioport) /* com1 or com2? */ { out_comport(tp, c); return; } /* Check to see if we are part way through an escape sequence. */ if (tp->tty_esc_state == 1) { tp->tty_echar = c; tp->tty_esc_state = 2; return; } if (tp->tty_esc_state == 2) { escape(tp, tp->tty_echar, c); tp->tty_esc_state = 0; return; } switch(c) { case 007: /* ring the bell */ flush(tp); /* print any chars queued for output */ beep(BEEP_FREQ);/* BEEP_FREQ gives bell tone */ return; case 013: /* CTRL-K */ move_to(tp, tp->tty_column, tp->tty_row + 1); return; case 014: /* CTRL-L */ move_to(tp, tp->tty_column + 1, tp->tty_row); return; case 016: /* CTRL-N */ move_to(tp, tp->tty_column + 1, tp->tty_row); return; case '\b': /* backspace */ move_to(tp, tp->tty_column - 1, tp->tty_row); return; case '\n': /* line feed */ if (tp->tty_mode & CRMOD) out_char(tp, '\r'); if (tp->tty_row == 0) scroll_screen(tp, GO_FORWARD); else tp->tty_row--; move_to(tp, tp->tty_column, tp->tty_row); return; case '\r': /* carriage return */ move_to(tp, 0, tp->tty_row); return; case '\t': /* tab */ if ( (tp->tty_mode & XTABS) == XTABS) { do { out_char(tp, ' '); } while (tp->tty_column & TAB_MASK); return; } /* Ignore tab is XTABS is off--video RAM has no hardware tab */ return; case 033: /* ESC - start of an escape sequence */ flush(tp); /* print any chars queued for output */ tp->tty_esc_state = 1; /* mark ESC as seen */ return; default: /* printable chars are stored in ramqueue */ if (tp->tty_column >= LINE_WIDTH) return; /* long line */ if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp); tp->tty_ramqueue[tp->tty_rwords++] = tp->tty_attribute | (c & 0x00ff); tp->tty_column++; /* next column */ return; } } /*===========================================================================* * scroll_screen * *===========================================================================*/ PRIVATE scroll_screen(tp, dir) register struct tty_struct *tp; /* pointer to tty struct */ int dir; /* GO_FORWARD or GO_BACKWARD */ { int video_base; video_base = vid_base + (tp->tty_org >> 4); if (dir == GO_FORWARD) { scr_up(video_base); vid_copy(NIL_PTR, video_base,2*(SCR_LINES-1)*LINE_WIDTH, LINE_WIDTH); } else { scr_dn(video_base); vid_copy(NIL_PTR, video_base, 0, LINE_WIDTH); } } /*===========================================================================* * flush * *===========================================================================*/ PRIVATE flush(tp) register struct tty_struct *tp; /* pointer to tty struct */ { /* Have the characters in 'ramqueue' transferred to the screen. */ if (tp->tty_rwords == 0) return; vid_copy(tp->tty_ramqueue, vid_base, tp->tty_vid, tp->tty_rwords); /* Update the video parameters and cursor. */ tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords); if (tp == current_tp) set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ tp->tty_rwords = 0; } /*===========================================================================* * move_to * *===========================================================================*/ PRIVATE move_to(tp, x, y) struct tty_struct *tp; /* pointer to tty struct */ int x; /* column (0 <= x <= 79) */ int y; /* row (0 <= y <= 24, 0 at bottom) */ { /* Move the cursor to (x, y). */ flush(tp); /* flush any pending characters */ if (x < 0 || x >= LINE_WIDTH || y < 0 || y >= SCR_LINES) return; tp->tty_column = x; /* set x co-ordinate */ tp->tty_row = y; /* set y co-ordinate */ tp->tty_vid = (tp->tty_org + 2*(SCR_LINES-1-y)*LINE_WIDTH + 2*x); if (tp == current_tp) set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ } /*===========================================================================* * escape * *===========================================================================*/ PRIVATE escape(tp, x, y) register struct tty_struct *tp; /* pointer to tty struct */ char x; /* escape sequence is ESC x y; this is x */ char y; /* escape sequence is ESC x y; this is y */ { /* Handle an escape sequence. */ int n, ct, vx; /* Check for ESC z attribute - used to change attribute byte. */ if (x == 'z') { /* Set attribute byte */ tp->tty_attribute = y << 8; return; } /* Check for ESC ~ n - used for clear screen, reverse scroll. */ if (x == '~') { if (y == '0') { /* Clear from cursor to end of screen */ n = 2 * LINE_WIDTH * (tp->tty_row + 1) - 2 * tp->tty_column; vx = tp->tty_vid; while (n > 0) { ct = MIN(n, vid_retrace); vid_copy(NIL_PTR, vid_base, vx, ct/2); vx += ct; n -= ct; } } else if (y == '1') { /* Reverse scroll. */ scroll_screen(tp, GO_BACKWARD); } return; } /* Must be cursor movement (or invalid). */ move_to(tp, x - 32, y - 32); } /*===========================================================================* * set_6845 * *===========================================================================*/ PRIVATE set_6845(reg, val) int reg; /* which register pair to set */ int val; /* 16-bit value to set it to */ { /* Set a register pair inside the 6845. * Registers 10-11 control the format of the cursor (how high it is, etc). * Registers 12-13 tell the 6845 where in video ram to start (in WORDS) * Registers 14-15 tell the 6845 where to put the cursor (in WORDS) * * Note that registers 12-15 work in words, i.e. 0x0000 is the top left * character, but 0x0001 (not 0x0002) is the next character. This addressing * is different from the way the 8088 addresses the video ram, where 0x0002 * is the address of the next character. */ port_out(vid_port + INDEX, reg); /* set the index register */ port_out(vid_port + DATA, (val>>8) & BYTE); /* output high byte */ port_out(vid_port + INDEX, reg + 1); /* again */ port_out(vid_port + DATA, val&BYTE); /* output low byte */ } /*===========================================================================* * beep * *===========================================================================*/ PRIVATE beep(f) int f; /* this value determines beep frequency */ { /* Making a beeping sound on the speaker (output for CRTL-G). The beep is * kept short, because interrupts must be disabled during beeping, and it * is undesirable to keep them off too long. This routine works by turning * on the bits in port B of the 8255 chip that drive the speaker. */ int x, k; lock(); /* disable interrupts */ port_out(TIMER3,0xB6); /* set up timer channel 2 mode */ port_out(TIMER2, f&BYTE); /* load low-order bits of frequency in timer */ port_out(TIMER2,(f>>8)&BYTE); /* now high-order bits of frequency in timer */ port_in(PORT_B,&x); /* acquire status of port B */ port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */ for (k = 0; k < B_TIME; k++); /* delay loop while beeper sounding */ port_out(PORT_B, x); /* restore port B the way it was */ unlock(); /* re-enable interrupts */ } /*===========================================================================* * tty_init * *===========================================================================*/ PRIVATE tty_init() { /* Initialize the tty tables. */ register struct tty_struct *tp; unsigned video_origin = 0, k; for (tp = &tty_struct[0], k = 0; tp < &tty_struct[NR_TTYS];++k, tp++) { tp->tty_inhead = tp->tty_inqueue; tp->tty_intail = tp->tty_inqueue; tp->tty_mode = CRMOD | XTABS | ECHO | DATALEN8 | DTRCTL | CDLINE; tp->tty_erase = ERASE_CHAR; tp->tty_kill = KILL_CHAR; tp->tty_intr = INTR_CHAR; tp->tty_quit = QUIT_CHAR; tp->tty_xon = XON_CHAR; tp->tty_xoff = XOFF_CHAR; tp->tty_eof = EOT_CHAR; tp->tty_speed = B1200; tp->tty_cdwait = tp->tty_cdkill=0; if(k < COM_TTY) { tp->tty_ioport = 0; tp->tty_org = video_origin; tp->tty_devstart = console; move_to(tp, 0, 24); video_origin += 4096; tp->tty_makebreak = TWO_INTS; tp->tty_attribute = BLANK; } else { tp->tty_devstart = com_out; tp->tty_makebreak = 0; tp->tty_ioport = com_ports[k - COM_TTY]; set_port(tp); } } if (color) { vid_base = COLOR_BASE; vid_mask = C_VID_MASK; vid_port = C_6845; vid_retrace = C_RETRACE; } else { vid_base = MONO_BASE; vid_mask = M_VID_MASK; vid_port = M_6845; vid_retrace = M_RETRACE; } tty_driver_buf[1] = MAX_OVERRUN; /* set up limit on keyboard buffering */ set_6845(CUR_SIZE, 31); /* set cursor shape */ set_6845(VID_ORG, 0); /* use page 0 of video ram */ tty_line = 0; /* force to first virtual screen */ current_tp = &tty_struct[0]; /* remember current tty pointer */ move_to(current_tp, 0, 0); /* move cursor to lower left corner */ /* Determine which keyboard type is attached. The bootstrap program asks * the user to type an '='. The scan codes for '=' differ depending on the * keyboard in use. */ if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE; } set_port(tp) struct tty_struct *tp; { int port, *tmode, stat, speed; if(!(port = tp->tty_ioport)) return; /* not a com port tty */ tmode = &tp->tty_mode; speed = tp->tty_speed; port_out(port + 3, stat = xmode(*tmode)); /* DLAB low */ port_out(port + 1, 0); /* no ints for now */ port_out(port + 4, 0x0a | (((*tmode) & DTRCTL) ? 1 : 0)); /* out2 must be high for ints to work */ if(speed >= B300 && speed <= B9600) { speed = baudrate[speed]; port_out(port + 3, 0x80); /* DLAB high */ port_out(port + 1, speed >> 8); /* high byte */ port_out(port, speed); /* low byte */ port_out(port + 3, stat); /* DLAB low */ } port_in(port + 6, &stat); *tmode &= ~CDLINE; if(stat & 0x80) *tmode |= CDLINE; port_out(port + 1, 0x0f); /* all ints are now on */ } /*===========================================================================* * putc * *===========================================================================*/ PUBLIC putc(c) char c; /* character to print */ { /* This procedure is used by the version of printf() that is linked with * the kernel itself. The one in the library sends a message to FS, which is * not what is needed for printing within the kernel. This version just queues * the character and starts the output. */ out_char(&tty_struct[0], c); } /*===========================================================================* * func_key * *===========================================================================*/ PRIVATE func_key(ch) char ch; /* scan code for a function key */ { /* This procedure traps function keys for debugging purposes. When MINIX is * fully debugged, it should be removed. */ if (ch == F1) p_dmp(); /* print process table */ if (ch == F2) map_dmp(); /* print memory map */ } #endif /*===========================================================================* * vir_screen_change * *===========================================================================*/ PRIVATE vir_screen_change(screen_number) int screen_number; /* Virtual screen number to select for i/o */ { /* Remember the screen number to keep input characters straight */ tty_line = screen_number; current_tp = &tty_struct[screen_number]; /* Select appropriate page of video memory */ set_6845(VID_ORG, current_tp->tty_org >> 1); /* Update cursor */ set_6845(CURSOR, current_tp->tty_vid >> 1); } -- Bing H. Bang +-------------------+ Harris/Lanier |MSDOS: just say no.| Atlanta GA +-------------------+