hedrick@athos.rutgers.edu (Charles Hedrick) (08/26/88)
Here is a reasonably stable version of my tty changes. There were three major goals: - to improve performance on RS232 connections so that I could use the system as a terminal emulator dialed up to Unix - to support scrolling on an EGA - to provide enough additional ANSI escape sequences so that the system is a reasonable terminal emulator. (It's still sparse compared to most real terminals, but adequate.) EGA support: use EGA facilities to do hardware scrolling. This causes screen glitches unless the EGA registers are only changed during vertical retrace. However if I wait for retrace every time a line is scrolled, it's as slow as software scrolling. So instead of actually setting the registers, my scroll code puts the new values into global variables, and sets a flag for the clock process. The clock process then calls a routine that waits for retrace and changes the registers. Originally this resulted in scrolling that was too fast: when I did "more" or something similar, the whole screen changed instantly. I prefer to see some visible evidence that text is scrolling off the top. So I compromise. Every 8 lines I wait for retrace and set the registers. The clock code still calls the routine, in case somebody doesn't do an even multiple of 8 scrolls. This results in scrolling that is very fast but still visible. klib88 changes: add get_ega, which tests whether your screen is an EGA, wait_retrace, which is used to wait for vert retrace interval. Remove a bunch of cli instructions, so that various copy loops can be interrupted. (In order to get reliable 2400 baud RS232 service, it is critical to reduce interrupt latency from what it is in unmodified 1.3.) Change vid_copy so that it uses a global "blank_color" to say what character to fill with. Thus if the user has chosen to set up the screen as black on white, when he clears the screen he'll get all white instead of all black. Generalize scr_up and scr_down so they take arguments to specify what regions to copy. This allows us to implement insert and delete line. mpx88: add a cld in "save". This may not be needed. It was one of several changes done to clean up RS232 interrupt handling. Together they work, but I don't know that this specific one was needed. The theory is to make sure that the direction flag has a definite value at interrupt level, rather than inheriting the current value from whatever procedure was interrupted. printer: cleared interrupts but never restored them. tty: many, many changes: make ^@ generate 200, i.e. a null with parity bit on. Should really be a null, but that's harder. Most programs accept this as a null. Was needed to generate the "set mark" command in elle and emacs. add a new translation table appropriate for the IBM "extended" keyboard, which has caps lock where control should be, and tilde where escape should be. If user types space instead of = in startup screen, he gets this. NB: also turns the backspace key into rubout, because the Rutgers convention is to use rubout for erasing. You may prefer not to do this. EGA support: see above. a couple of calls to "flush" were missing from the display code. If something outputed LF CR, you'd get the LF in the middle of random text. Found a few other places that seemed to have similar errors. added escape codes. Designed to be sufficient for the terminal emulator to work over 1200 or 2400 baud lines. It should work with the "ansi" terminal type defined in Unix termcap, though you'd be better with a special termcap entry that includes insert/delete line. A, B, C, D - ansi cursor movement K - clear to end of line L - insert lines M - delete lines m - redid attributes so they work better on color screens. Added codes 3x and 4x which are used to set colors. Note by the way that colors are more "permanent" than attributes. E.g. if you set a yellow foreground color and then do boldface, bold will change foreground to red. When you do normal (i.e. undo the bold) it will go back to yellow foreground, not white. fix beep. It was looping with interrupts off in order to get a fixed delay. Use a SET_ALARM message to the clock instead, so that we don't have to disable interrupts. A few other bug fixes taken from previous usenet postings. Note that one of them causes nulls to be read correctly from RS232 ports. If you have a termcap entry that uses null for padding, you'll get very odd results, since the display code displays null as a blank. Probably the display code should be changed to ignore null. However you still should fix termcap entries so they don't generate padding. If you're going to lose characters, you'll lose them on input. Padding can't be discarded safely until the data gets through to the display process. So adding padding will probably actually make character dropping problems worse. fsck: allow user to type "space" for extended keyboard fixup *** clock.c.ORIG Thu Jan 1 00:12:49 1970 --- clock.c Thu Jan 1 00:11:23 1970 *************** *** 54,59 **** --- 54,60 ---- PRIVATE message mc; /* message buffer for both input and output */ PRIVATE int (*watch_dog[NR_TASKS+1])(); /* watch_dog functions to call */ extern int flush_flag; /* tells clock when to flush the tty buf */ + extern int need_ega_int; /* tells clock to do ega adjust */ /*===========================================================================* * clock_task * *************** *** 198,204 **** prev_ptr = bill_ptr; /* new previous process */ /* If characters are accumulating, call the TTY task. */ ! if (flush_flag) rs_flush(); /* flush accumulated tty input */ /* Check if printer is hung up, and if so, restart it. */ if (pr_busy && pcount > 0 && cum_count == prev_ct) pr_char(); --- 199,209 ---- prev_ptr = bill_ptr; /* new previous process */ /* If characters are accumulating, call the TTY task. */ ! if (flush_flag) ! rs_flush(); /* flush accumulated tty input */ ! /* Does ega need adjustment? */ ! if (need_ega_int) ! ega_int(); /* Check if printer is hung up, and if so, restart it. */ if (pr_busy && pcount > 0 && cum_count == prev_ct) pr_char(); *** klib88.s.ORIG Thu Jan 1 00:12:58 1970 --- klib88.s Thu Jan 1 00:12:21 1970 *************** *** 11,16 **** --- 11,17 ---- | csv: procedure prolog to save the registers | cret: procedure epilog to restore the registers | get_chrome: returns 0 if display is monochrome, 1 if it is color + | get_ega: returns 1 if display is EGA, 0 otherwise | vid_copy: copy data to video ram (on color display during retrace only) | scr_up: scroll screen a line up (in software, by copying) | scr_down: scroll screen a line down (in software, by copying) *************** *** 20,37 **** | dma_read: transfer data between HD controller and memory | dma_write: transfer data between memory and HD controller | em_xfer: read or write AT extended memory using the BIOS | The following procedures are defined in this file and called from outside it. .globl _phys_copy, _cp_mess, _port_out, _port_in, _lock, _restore .globl _build_sig, csv, cret, _get_chrome, _vid_copy, _get_byte, _reboot .globl _wreboot, _dma_read, _dma_write, _em_xfer, _scr_up, _scr_down | The following external procedure is called in this file. .globl _panic | Variables and data structures ! .globl _color, _cur_proc, _proc_ptr, splimit, _vec_table, _vid_mask ! |*===========================================================================* |* phys_copy * --- 21,40 ---- | dma_read: transfer data between HD controller and memory | dma_write: transfer data between memory and HD controller | em_xfer: read or write AT extended memory using the BIOS + | wait_retrace: waits for retrace interval, and returns int disabled | The following procedures are defined in this file and called from outside it. .globl _phys_copy, _cp_mess, _port_out, _port_in, _lock, _restore .globl _build_sig, csv, cret, _get_chrome, _vid_copy, _get_byte, _reboot .globl _wreboot, _dma_read, _dma_write, _em_xfer, _scr_up, _scr_down + .globl _get_ega, _wait_retrace | The following external procedure is called in this file. .globl _panic | Variables and data structures ! .globl _color, _cur_proc, _proc_ptr, splimit, _vec_table, _vid_mask, _ega ! .globl _blank_color |*===========================================================================* |* phys_copy * *************** *** 41,47 **** _phys_copy: pushf | save flags ! cli | disable interrupts cld | clear direction flag push bp | save the registers push ax | save ax --- 44,50 ---- _phys_copy: pushf | save flags ! | cli | disable interrupts cld | clear direction flag push bp | save the registers push ax | save ax *************** *** 149,155 **** push ds | save ds mov bp,sp | index off bp because machine can't use sp pushf | save flags ! cli | disable interrupts cld | clear direction flag push cx | save cx push si | save si --- 152,158 ---- push ds | save ds mov bp,sp | index off bp because machine can't use sp pushf | save flags ! | cli | disable interrupts cld | clear direction flag push cx | save cx push si | save si *************** *** 332,337 **** --- 335,357 ---- ret | monochrome return |*===========================================================================* + |* get_ega * + |*===========================================================================* + | This routine calls the BIOS to find out if the display is ega. This + | is needed because scrolling is different. + _get_ega: + movb bl,*0x10 + movb ah,*0x12 + int 0x10 | call the BIOS to get equipment type + + cmpb bl,*0x10 | if reg is unchanged, it failed + je notega + mov ax,#1 | color = 1 + ret | color return + notega: xor ax,ax | mono = 0 + ret | monochrome return + + |*===========================================================================* |* dma_read * |*===========================================================================* _dma_read: *************** *** 392,400 **** | 'videobase' is 0xB800 for color and 0xB000 for monochrome displays | 'offset' tells where within video ram to copy the data | 'words' tells how many words to copy ! | if buffer is zero, the fill char (BLANK) is used ! ! BLANK = 0x0700 | controls color of cursor on blank screen _vid_copy: push bp | we need bp to access the parameters --- 412,418 ---- | 'videobase' is 0xB800 for color and 0xB000 for monochrome displays | 'offset' tells where within video ram to copy the data | 'words' tells how many words to copy ! | if buffer is zero, the fill char (blank_color) is used _vid_copy: push bp | we need bp to access the parameters *************** *** 423,428 **** --- 441,448 ---- vid.1: test _color,*1 | skip vertical retrace test if display is mono jz vid.4 | if monochrome then go to vid.2 + test _ega,*1 | if ega also don't need to wait + jnz vid.4 |vid.2: in | with a color display, you can only copy to | test al,*010 | the video ram during vertical retrace, so *************** *** 432,438 **** jz vid.3 | until it comes on (start of retrace) vid.4: pushf | copying may now start; save flags ! cli | interrupts just get in the way: disable them cld | clear direction flag mov es,6(bp) | load es now: int routines may ruin it --- 452,458 ---- jz vid.3 | until it comes on (start of retrace) vid.4: pushf | copying may now start; save flags ! | cli | interrupts just get in the way: disable them cld | clear direction flag mov es,6(bp) | load es now: int routines may ruin it *************** *** 464,481 **** pop bp | restore bp ret | return to caller ! vid.7: mov ax,#BLANK | ax = blanking character rep | copy loop stow | blank screen jmp vid.5 | done |*===========================================================================* |* scr_up * |*===========================================================================* | This routine scrolls the screen up one line on an EGA display | | The call is: ! | scr_up(org) | where | 'org' is the video segment origin of the desired page --- 484,522 ---- pop bp | restore bp ret | return to caller ! vid.7: mov ax,_blank_color | ax = blanking character rep | copy loop stow | blank screen jmp vid.5 | done |*===========================================================================* + |* wait_retrace * + |*===========================================================================* + | Wait until we're in the retrace interval. Return locked (ints off). + | But enable then during the wait. + + _wait_ret: push dx + pushf + mov dx,#0x3DA | prepare to see if color display is retracing + wtre.3: sti + nop + nop + cli + in | 0x3DA is set during retrace. First wait + testb al,*010 | until it is off (no retrace), then wait + jz wtre.3 | until it comes on (start of retrace) + + pop ax | return flags for restoration later + pop dx + ret | return to caller + + |*===========================================================================* |* scr_up * |*===========================================================================* | This routine scrolls the screen up one line on an EGA display | | The call is: ! | scr_up(org,source,dest,count) | where | 'org' is the video segment origin of the desired page *************** *** 487,498 **** push cx | save cx push es | save es push ds | save ds ! mov si,#160 | si = pointer to data to be copied ! mov di,#0 | di = offset within video ram ! mov cx,#1920 | cx = word count for copy loop ! ! pushf | copying may now start; save flags ! cli | interrupts just get in the way: disable them cld | clear diretion flag mov ax,4(bp) mov es,ax | load es now: int routines may ruin it --- 528,539 ---- push cx | save cx push es | save es push ds | save ds ! mov si,6(bp) | si = pointer to data to be copied ! mov di,8(bp) | di = offset within video ram ! mov cx,10(bp) | cx = word count for copy loop ! ! pushf | copying may now start; save flags ! | cli | interrupts just get in the way: disable them cld | clear diretion flag mov ax,4(bp) mov es,ax | load es now: int routines may ruin it *************** *** 528,539 **** push cx | save cx push es | save es push ds | save ds ! mov si,#3838 | si = pointer to data to be copied ! mov di,#3998 | di = offset within video ram ! mov cx,#1920 | cx = word count for copy loop ! ! pushf | copying may now start; save flags ! cli | interrupts just get in the way: disable them mov ax,4(bp) mov es,ax | load es now: int routines may ruin it mov ds,ax --- 569,580 ---- push cx | save cx push es | save es push ds | save ds ! mov si,6(bp) | si = pointer to data to be copied ! mov di,8(bp) | di = offset within video ram ! mov cx,10(bp) | cx = word count for copy loop ! ! pushf | copying may now start; save flags ! | cli | interrupts just get in the way: disable them mov ax,4(bp) mov es,ax | load es now: int routines may ruin it mov ds,ax *** main.c.ORIG Thu Jan 1 00:13:01 1970 --- main.c Thu Jan 1 00:13:06 1970 *************** *** 54,60 **** int stack_size; int * ktsb; /* kernel task stack base */ extern unsigned sizes[8]; /* table filled in by build */ ! extern int color, vec_table[], get_chrome(); extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int(); extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int(); extern phys_bytes umap(); --- 54,60 ---- int stack_size; int * ktsb; /* kernel task stack base */ extern unsigned sizes[8]; /* table filled in by build */ ! extern int color, ega, vec_table[], get_chrome(), get_ega(); extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int(); extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int(); extern phys_bytes umap(); *************** *** 141,146 **** --- 141,147 ---- /* Determine if display is color or monochrome and CPU type (from BIOS). */ color = get_chrome(); /* 0 = mono, 1 = color */ + ega = get_ega(); t = (int)get_byte(CPU_TY1, CPU_TY2) & 0xFF; /* is this PC, XT, AT ... ? */ if (t == PC_AT) pc_at = TRUE; *** mpx88.s.ORIG Thu Jan 1 00:12:46 1970 --- mpx88.s Thu Jan 1 00:12:52 1970 *************** *** 300,305 **** --- 300,306 ---- add sp,#K_STACK_BYTES | set sp to top of temporary stack mov splimit,#_k_stack | limit for temporary stack add splimit,#8 | splimit checks for stack overflow + cld mov ax,ret_save | ax = address to return to jmp (ax) | return to caller; Note: sp points to saved ax *** printer.c.ORIG Thu Jan 1 00:12:23 1970 --- printer.c Thu Jan 1 00:13:03 1970 *************** *** 134,139 **** --- 134,140 ---- break; } } + restore(old_state); } /* Reply to FS, no matter what happened. */ *** tty.c.ORIG Thu Jan 1 00:12:05 1970 --- tty.c Thu Jan 1 00:11:12 1970 *************** *** 75,81 **** #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 AT_SIGN 0220 /* code to yield for CTRL-@ */ #define SCODE1 71 /* scan code for Home on numeric pad */ #define SCODE2 81 /* scan code for PgDn on numeric pad */ #define DEL_CODE (char) 83 /* DEL for use in CTRL-ALT-DEL reboot */ --- 75,81 ---- #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 AT_SIGN 0200 /* code to yield for CTRL-@ */ #define SCODE1 71 /* scan code for Home on numeric pad */ #define SCODE2 81 /* scan code for PgDn on numeric pad */ #define DEL_CODE (char) 83 /* DEL for use in CTRL-ALT-DEL reboot */ *************** *** 171,178 **** PRIVATE int softscroll = 0; /* 1 = software scrolling, 0 = hardware */ PRIVATE int output_done; /* number of RS232 output messages to be sent*/ PUBLIC int color; /* 1 if console is color, 0 if it is mono */ ! PUBLIC int scan_code; /* scan code for '=' saved by bootstrap */ ! /* Scan codes to ASCII for unshifted keys */ PRIVATE char unsh[] = { --- 171,182 ---- PRIVATE int softscroll = 0; /* 1 = software scrolling, 0 = hardware */ PRIVATE int output_done; /* number of RS232 output messages to be sent*/ PUBLIC int color; /* 1 if console is color, 0 if it is mono */ ! PUBLIC int ega; /* 1 if console is EGA, 0 if not */ ! PUBLIC int scan_code; /* scan code for '=' saved by bootstrap */ ! PUBLIC int ext_kbd = FALSE; /* TRUE if user wants fixups for ext kbd */ ! PUBLIC int need_ega_int = 0; /* ask clock for ega interrupt */ ! PRIVATE int ega_origin; /* origin to set at next ega int */ ! PRIVATE int ega_line; /* line to set at next ega int */ /* Scan codes to ASCII for unshifted keys */ PRIVATE char unsh[] = { *************** *** 194,199 **** --- 198,223 ---- '2','3','0','.' }; + /* Unshifted extended kbd */ + PRIVATE char unshx[] = { + 0,'`','1','2','3','4','5','6', '7','8','9','0','-','=',0177,'\t', + 'q','w','e','r','t','y','u','i', 'o','p','[',']',015,0202,'a','s', + 'd','f','g','h','j','k','l',';', 047,033,0200,0134,'z','x','c','v', + 'b','n','m',',','.','/',0201,'*', 0203,' ',0202,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 + }; + + /* Shifted extended kbd */ + PRIVATE char shx[] = { + 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,' ',0202,0221,0222,0223,0224,0225, + 0226,0227,0230,0231,0232,0204,0213,'7', '8','9',0211,'4','5','6',0214,'1', + '2','3','0','.' + }; + /* Scan codes to ASCII for Olivetti M24 for unshifted keys. */ PRIVATE char unm24[] = { *************** *** 378,388 **** } if (tp->tty_incount >= TTY_IN_BYTES) return; /* no room, discard char */ mode = tp->tty_mode & (RAW | CBREAK); ! if (tp->tty_makebreak == TWO_INTS) ! 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; /* Processing for COOKED and CBREAK mode contains special checks. */ if (mode == COOKED || mode == CBREAK) { --- 402,413 ---- } if (tp->tty_incount >= TTY_IN_BYTES) return; /* no room, discard char */ mode = tp->tty_mode & (RAW | CBREAK); ! if (tp->tty_makebreak == TWO_INTS) { ! ch = make_break(ch); /* console give 2 ints/ch */ ! if (ch == 0) return; ! } ! else ! if (mode != RAW) ch &= 0177; /* 7-bit chars except in raw mode */ /* Processing for COOKED and CBREAK mode contains special checks. */ if (mode == COOKED || mode == CBREAK) { *************** *** 504,510 **** 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 ? sh[c] : unsh[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ --- 529,542 ---- c = ch & 0177; /* high-order bit set on key release */ make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */ ! if (ext_kbd) { ! /* IBM "extended" kbd with ctrl and esc hard to find */ ! /* Standard IBM keyboard. */ ! code = (shift1 || shift2 ? shx[c] : unshx[c]); ! if (control && c < TOP_ROW) code = shx[c]; /* CTRL-(top row) */ ! if (c > 70 && numlock) /* numlock depressed */ ! code = (shift1 || shift2 ? unshx[c] : shx[c]); ! } else if (olivetti == FALSE) { /* Standard IBM keyboard. */ code = (shift1 || shift2 ? sh[c] : unsh[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ *************** *** 957,966 **** #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 */ --- 989,999 ---- #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 3 /* length of CTRL-G beep is ticks */ #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 SCR_BYTES 8000 /* size video RAM. multiple of 2*LINE_WIDTH */ #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 */ *************** *** 980,988 **** --- 1013,1023 ---- #define EGA 0x3C0 /* port for EGA card */ #define INDEX 4 /* 6845's index register */ #define DATA 5 /* 6845's data register */ + #define OVRFL_REG 7 /* EGA overflow 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 */ + #define LINE_CMP 0x18 /* EGA line compare register */ /* Definitions used for determining if the keyboard is IBM or Olivetti type. */ #define KB_STATUS 0x64 /* Olivetti keyboard status port */ *************** *** 991,996 **** --- 1026,1032 ---- #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 */ + #define SPACE_SCAN 57 /* a space */ /* Global variables used by the console driver. */ PUBLIC message keybd_mess; /* message used for console input chars */ *************** *** 998,1004 **** 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 */ ! /*===========================================================================* * keyboard * --- 1034,1040 ---- 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 */ ! PUBLIC int blank_color = 0x0700; /* display code for blank */ /*===========================================================================* * keyboard * *************** *** 1146,1155 **** case '\n': /* line feed */ if (tp->tty_mode & CRMOD) out_char(tp, '\r'); ! if (tp->tty_row == SCR_LINES-1) scroll_screen(tp, GO_FORWARD); else tp->tty_row++; move_to(tp, tp->tty_column, tp->tty_row); return; --- 1182,1192 ---- case '\n': /* line feed */ if (tp->tty_mode & CRMOD) out_char(tp, '\r'); ! if (tp->tty_row == SCR_LINES-1) scroll_screen(tp, GO_FORWARD); else tp->tty_row++; + move_to(tp, tp->tty_column, tp->tty_row); return; *************** *** 1188,1195 **** register struct tty_struct *tp; /* pointer to tty struct */ int dir; /* GO_FORWARD or GO_BACKWARD */ { ! int amount, offset, bytes; ! bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH; /* 2 * 24 * 80 bytes */ /* Scrolling the screen is a real nuisance due to the various incompatible --- 1225,1233 ---- register struct tty_struct *tp; /* pointer to tty struct */ int dir; /* GO_FORWARD or GO_BACKWARD */ { ! int amount, offset, bytes, old_state; ! ! flush(tp); bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH; /* 2 * 24 * 80 bytes */ /* Scrolling the screen is a real nuisance due to the various incompatible *************** *** 1199,1225 **** if (softscroll) { /* Software scrolling for non-IBM compatible EGA cards. */ if (dir == GO_FORWARD) { ! scr_up(vid_base); ! vid_copy(NIL_PTR, vid_base, tp->tty_org+bytes, LINE_WIDTH); ! } else { ! scr_down(vid_base); ! vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH); ! } ! } else { ! /* Normal scrolling using the 6845 registers. */ ! amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); ! tp->tty_org = (tp->tty_org + amount) & vid_mask; ! if (dir == GO_FORWARD) ! offset = (tp->tty_org + bytes) & vid_mask; else offset = tp->tty_org; /* Blank the new line at top or bottom. */ vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */ } } /*===========================================================================* * flush * --- 1237,1370 ---- if (softscroll) { /* Software scrolling for non-IBM compatible EGA cards. */ if (dir == GO_FORWARD) { ! scr_up(vid_base, LINE_WIDTH * 2, 0, ! (SCR_LINES - 1) * LINE_WIDTH); ! vid_copy(NIL_PTR, vid_base, tp->tty_org+bytes, LINE_WIDTH); ! } else { ! scr_down(vid_base, ! (SCR_LINES - 1) * LINE_WIDTH * 2 - 2, ! SCR_LINES * LINE_WIDTH * 2 - 2, ! (SCR_LINES - 1) * LINE_WIDTH); ! vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH); ! } ! } else if (ega) { ! int lines; ! /* ! * EGA scrolling. CGA and MDA scrolling is based on the fact ! * fact that the older adapters wrap around at 4K or whatever. ! * not all EGA's do. So instead we use the line compare ! * register. This is a scan line. Everything after this ! * line is displayed starting at the beginning of the display ! * RAM, ignoring the display start. So the top of the screen ! * starts whereover tty_org says it should in RAM. We compute ! * the scan line where the first page of RAM ends, and force ! * wraparound to the top using line compare. Since this uses ! * nothing beyond the first page of display RAM, and line ! * compare is a documented feature, it should work on all EGA ! * emulators. To keep arithmetic easier, we use a "page size" ! * of SCR_BYTES, which is exactly one screen full. ! */ ! ! amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); ! tp->tty_org = (tp->tty_org + amount); /* top of screen in buffer */ ! if (tp->tty_org >= SCR_BYTES) /* see if we wrapped around */ ! tp->tty_org -= SCR_BYTES; ! else if (tp->tty_org < 0) /* wrap around the other way */ ! tp->tty_org += SCR_BYTES; ! if (dir == GO_FORWARD) { /* compute line to clear */ ! offset = tp->tty_org + bytes; ! if (offset >= SCR_BYTES) ! offset -= SCR_BYTES; ! } else offset = tp->tty_org; /* Blank the new line at top or bottom. */ vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); + + /* Figure out where to wrap around to top of display mem */ + lines = SCR_BYTES - tp->tty_org; + lines = 14 * (lines / (LINE_WIDTH * 2)) - 1; + if (lines > (14 * SCR_LINES)) + lines = 14 * SCR_LINES; + /* 14 is scan lines per line of text. Ideally we should find + * a way to ask the display controller or the BIOS about this, */ + /* Now for the fun. Set the wraparound line. This is one of + * the wierd registers where the high-order bit is in the + * overflow register. Note that we're hardcoding the other bits + * in it. This is another potential problem if a new model needs + * extra bits. Unfortunately I couldn't figure out any way to + * read this register. */ + + ega_line = lines; + ega_origin = tp->tty_org; + + /* + * We now have the settings for the EGA registers. However + * we don't want to do them now. The problem is that in + * order to avoid flicker we have to wait for vertical + * retrace. We don't want to do that for every line, because + * it slows things like "more" down to the point where they + * are about as slow as with software scrolling. So we + * do the actual register update in ega_int, which is called + * from the clock when need_ega_int is non-zero. If you + * just increment need_ega_int in the next line, but don't + * call ega_int, when you're cating to the terminal, you'll + * get a whole screen at once. We choose to do it every + * 8 lines in order to give some visual impression of + * scrolling. So this is a compromise between a pure + * clock driven approach, which is too fast, and updating + * for each line, which is too slow. + */ + + if (need_ega_int++ > 8) + ega_int(); + } else { + /* Normal scrolling using the 6845 registers. */ + amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); + tp->tty_org = (tp->tty_org + amount) & vid_mask; + if (dir == GO_FORWARD) + offset = (tp->tty_org + bytes) & vid_mask; + else + offset = tp->tty_org; + + /* Blank the new line at top or bottom. */ + vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */ } } + /*===========================================================================* + * ega_int * + *===========================================================================*/ + PUBLIC ega_int() + { + /* + * Need to change ega registers for scrolling. Called from clock + * when need_ega_int is set. Done this way because we only want to + * do this every so often, because we have to wait for a vert + * retrace interval. + */ + + int old_state; + + /* + * wait_retrace returns noint, to make sure we don't get descheduled + * before we have a change to do our thing. Note that the code that + * sets these variables and this code are both running at process + * level, so there's no danger of race conditions. + */ + old_state = wait_retrace(); + if (ega_line > 255) + setb6845(OVRFL_REG, 0x1f); /* high order bit is in overflow reg */ + else + setb6845(OVRFL_REG, 0x0f); /* high order bit 0 */ + setb6845(LINE_CMP, ega_line & 0xff); /* now set line compare reg */ + /* Tell the EGA what display memory to put at top of screen */ + set_6845(VID_ORG, ega_origin >> 1); /* 6845 thinks in words */ + need_ega_int = 0; + restore(old_state); + } /*===========================================================================* * flush * *************** *** 1234,1239 **** --- 1379,1386 ---- /* Update the video parameters and cursor. */ tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords); + if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES)) + tp->tty_vid -= SCR_BYTES; set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ tp->tty_rwords = 0; } *************** *** 1254,1259 **** --- 1401,1409 ---- tp->tty_column = x; /* set x co-ordinate */ tp->tty_row = y; /* set y co-ordinate */ tp->tty_vid = (tp->tty_org + 2*y*LINE_WIDTH + 2*x); + if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES)) + tp->tty_vid -= SCR_BYTES; + set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ } *************** *** 1317,1322 **** --- 1467,1474 ---- } } + /* map from ANSI colors to the attributes used by the PC */ + PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7}; /*===========================================================================* * do_escape * *************** *** 1327,1332 **** --- 1479,1486 ---- { int n, ct, vx; + /* Some of these things hack on screen RAM, so it had better be up to date */ + flush(tp); /* Handle a sequence beginning with just ESC */ if (tp->tty_esc_intro == '\0') { switch (c) { *************** *** 1344,1349 **** --- 1498,1531 ---- /* Handle a sequence beginning with ESC [ and parameters */ if (tp->tty_esc_intro == '[') { switch (c) { + case 'A': + if (tp->tty_esc_parmv[0] == 0) + n = 1; + else + n = tp->tty_esc_parmv[0]; + move_to(tp, tp->tty_column, tp->tty_row - n); + break; + case 'B': + if (tp->tty_esc_parmv[0] == 0) + n = 1; + else + n = tp->tty_esc_parmv[0]; + move_to(tp, tp->tty_column, tp->tty_row + n); + break; + case 'C': + if (tp->tty_esc_parmv[0] == 0) + n = 1; + else + n = tp->tty_esc_parmv[0]; + move_to(tp, tp->tty_column + n, tp->tty_row); + break; + case 'D': + if (tp->tty_esc_parmv[0] == 0) + n = 1; + else + n = tp->tty_esc_parmv[0]; + move_to(tp, tp->tty_column - n, tp->tty_row); + break; case 'H': /* Position cursor */ move_to(tp, MAX(1, MIN(LINE_WIDTH, tp->tty_esc_parmv[1])) - 1, *************** *** 1354,1387 **** n = 2 * ((SCR_LINES - (tp->tty_row + 1)) * LINE_WIDTH + LINE_WIDTH - (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; ! } } break; case 'm': /* Set graphic rendition */ switch (tp->tty_esc_parmv[0]) { ! case 1: /* BOLD (light green on black) */ ! tp->tty_attribute = 0x0A << 8; ! break; ! ! case 4: /* UNDERLINE (blue on red) */ ! tp->tty_attribute = 0x41 << 8; ! break; ! ! case 5: /* BLINKING (light grey on black) */ ! tp->tty_attribute = 0x87 << 8; break; case 7: /* REVERSE (black on light grey) */ ! tp->tty_attribute = 0x70 << 8; ! break; ! ! default: tp->tty_attribute = 0007 << 8; ! break; } break; default: --- 1536,1734 ---- n = 2 * ((SCR_LINES - (tp->tty_row + 1)) * LINE_WIDTH + LINE_WIDTH - (tp->tty_column)); vx = tp->tty_vid; ! if (ega) { ! ct = MIN(n, SCR_BYTES - vx); ! vid_copy(NIL_PTR, vid_base, vx, ct/2); ! n -= ct; ! if (n > 0) ! vid_copy(NIL_PTR, vid_base, 0, n/2); ! } ! else ! long_vid_copy (NIL_PTR, vid_base, vx, n/2); ! } ! break; ! case 'K': /* Clear from cursor to end of line */ ! if (tp->tty_esc_parmv[0] == 0) { ! n = 2 * (LINE_WIDTH - (tp->tty_column)); ! vid_copy(NIL_PTR, vid_base, tp->tty_vid, n/2); ! } ! break; ! case 'L': /* Insert parm lines */ ! {int src, dst, count, limit, m; ! n = tp->tty_esc_parmv[0]; ! if (n < 1) ! n = 1; ! if (n > (SCR_LINES - tp->tty_row)) ! n = SCR_LINES - tp->tty_row; ! /* these are all relative to start of screen, ! * ignoring slight difficulties such as ! * wraparound. They are actually appropiate ! * arguments to scr_down for the soft_scroll case ! */ ! src = (SCR_LINES - n) * LINE_WIDTH * 2 - 2; ! dst = SCR_LINES * LINE_WIDTH * 2 - 2; ! count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH; ! if (softscroll) ! limit = 0x7fff; /* no wraparound possible */ ! else if (ega) ! limit = SCR_BYTES; ! else ! limit = vid_mask + 1; ! /* ! * The copy will have three phases: src and dest ! * wrapped around, dest wrapped around and src not, ! * and neither wrapped around ! */ ! src += tp->tty_org; ! dst += tp->tty_org; ! if (src >= limit && dst >= limit) { ! m = MIN (count, (src - limit) / 2 + 1); ! l_scr_down(vid_base, src - limit, dst - limit, m); ! count -= m; ! src -= m * 2; ! dst -= m * 2; ! } ! if (dst >= limit && count > 0) { ! m = MIN (count, (dst - limit) / 2 + 1); ! l_scr_down(vid_base, src, dst - limit, m); ! count -= m; ! src -= m * 2; ! dst -= m * 2; ! } ! if (count > 0) ! l_scr_down(vid_base, src, dst, count); ! /* OK, now let's clear the lines we inserted */ ! dst = tp->tty_row * LINE_WIDTH * 2; ! count = n * LINE_WIDTH; ! dst += tp->tty_org; ! if (dst < limit) { ! m = MIN (count, (limit - dst) / 2); ! long_vid_copy(NIL_PTR, vid_base, dst, m); ! count -= m; ! dst += m * 2; ! } ! if (count > 0) ! long_vid_copy(NIL_PTR, vid_base, dst - limit, count); ! } ! break; ! case 'M': /* Delete parm lines */ ! {int src, dst, count, limit, m; ! n = tp->tty_esc_parmv[0]; ! if (n < 1) ! n = 1; ! if (n > (SCR_LINES - tp->tty_row)) ! n = SCR_LINES - tp->tty_row; ! /* these are all relative to start of screen, ! * ignoring slight difficulties such as ! * wraparound. They are actually appropiate ! * arguments to scr_down for the soft_scroll case ! */ ! src = (tp->tty_row + n) * LINE_WIDTH * 2; ! dst = (tp->tty_row) * LINE_WIDTH * 2; ! count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH; ! if (softscroll) ! limit = 0x7fff; /* no wraparound possible */ ! else if (ega) ! limit = SCR_BYTES; ! else ! limit = vid_mask + 1; ! /* ! * The copy will have three phases: src and dest ! * not wrapped, src wrapped dest not, both wrapped ! */ ! src += tp->tty_org; ! dst += tp->tty_org; ! if (src < limit && dst < limit) { ! m = MIN (count, (limit - src) / 2); ! l_scr_up(vid_base, src, dst, m); ! count -= m; ! src += m * 2; ! dst += m * 2; ! } ! if (dst < limit && count > 0) { ! m = MIN (count, (limit - dst) / 2); ! l_scr_up(vid_base, src - limit, dst, m); ! count -= m; ! src += m * 2; ! dst += m * 2; ! } ! if (count > 0) ! l_scr_up(vid_base, src-limit, dst - limit, count); ! /* OK, now let's clear the lines at the bottom */ ! dst = (SCR_LINES - n) * LINE_WIDTH * 2; ! count = n * LINE_WIDTH; ! dst += tp->tty_org; ! if (dst < limit) { ! m = MIN (count, (limit - dst) / 2); ! long_vid_copy(NIL_PTR, vid_base, dst, m); ! count -= m; ! dst += m * 2; ! } ! if (count > 0) ! long_vid_copy(NIL_PTR, vid_base, dst - limit, count); } break; case 'm': /* Set graphic rendition */ switch (tp->tty_esc_parmv[0]) { ! case 1: /* BOLD */ ! if (color) ! tp->tty_attribute = /* red fg */ ! (tp->tty_attribute & 0xf0ff) | 0x0400; ! else ! tp->tty_attribute |= /* intensity */ ! 0x0800; ! break; ! ! case 4: /* UNDERLINE */ ! if (color) ! tp->tty_attribute = /* blue fg */ ! (tp->tty_attribute & 0xf0ff) | 0x0100; ! else ! tp->tty_attribute = /* ul */ ! (tp->tty_attribute & 0x8900); ! break; ! ! case 5: /* BLINKING */ ! if (color) /* can't blink color */ ! tp->tty_attribute = /* magenta fg */ ! (tp->tty_attribute & 0xf0ff) | 0x0500; ! else ! tp->tty_attribute |= /* blink */ ! 0x8000; break; case 7: /* REVERSE (black on light grey) */ ! if (color) ! tp->tty_attribute = ! ((tp->tty_attribute & 0xf000) >> 4) | ! ((tp->tty_attribute & 0x0f00) << 4); ! else if ((tp->tty_attribute & 0x7000) == 0) ! tp->tty_attribute = ! (tp->tty_attribute & 0x8800) | 0x7000; ! else ! tp->tty_attribute = ! (tp->tty_attribute & 0x8800) | 0x0700; ! break; ! ! default: if (tp->tty_esc_parmv[0] >= 30 && ! tp->tty_esc_parmv[0] <= 37) { ! tp->tty_attribute = ! (tp->tty_attribute & 0xf0ff) | ! (ansi_colors[(tp->tty_esc_parmv[0] - 30)] << 8); ! blank_color = ! (blank_color & 0xf0ff) | ! (ansi_colors[(tp->tty_esc_parmv[0] - 30)] << 8); ! } else if (tp->tty_esc_parmv[0] >= 40 && ! tp->tty_esc_parmv[0] <= 47) { ! tp->tty_attribute = ! (tp->tty_attribute & 0x0fff) | ! (ansi_colors[(tp->tty_esc_parmv[0] - 40)] << 12); ! blank_color = ! (blank_color & 0x0fff) | ! (ansi_colors[(tp->tty_esc_parmv[0] - 40)] << 12); ! } else ! tp->tty_attribute = blank_color; ! break; } break; default: *************** *** 1391,1396 **** --- 1738,1823 ---- tp->tty_esc_state = 0; } + /*===========================================================================* + * long_vid_copy * + *===========================================================================*/ + PRIVATE long_vid_copy(src, base, offset, count) + char *src; + unsigned int base, offset, count; + { + int ct; + /* + * break up a call to vid_copy for machines that can only write + * during vertical retrace. Vid_copy itself does the wait + */ + + while (count > 0) { + ct = MIN (count, vid_retrace >> 1); + vid_copy(src, base, offset, ct); + if (src != NIL_PTR) + src += ct * 2; + offset += ct * 2; + count -= ct; + } + } + + /*===========================================================================* + * long_src_up * + *===========================================================================*/ + PRIVATE l_scr_up(base, src, dst, count) + unsigned int base, src, dst, count; + { + int ct, old_state, wait; + /* + * break up a call to scr_up for machines that can only write + * during vertical retrace. scr_up doesn't do the wait, so we do. + * Note however that we keep interrupts on during the scr_up. This + * could lead to snow if an interrupt happens while we are doing + * the display. Sorry, but I don't see any good alternative. + * Turning off interrupts makes us loses RS232 input chars. + */ + wait = color && ! ega; + while (count > 0) { + if (wait) { + old_state = wait_retrace(); + restore(old_state); + } + ct = MIN (count, vid_retrace >> 1); + scr_up(base, src, dst, ct); + src += ct * 2; + dst += ct * 2; + count -= ct; + } + } + + /*===========================================================================* + * long_scr_down * + *===========================================================================*/ + PRIVATE l_scr_down(base, src, dst, count) + unsigned int base, src, dst, count; + { + int ct, old_state, wait; + /* + * break up a call to scr_down for machines that can only write + * during vertical retrace. scr_down doesn't do the wait, so we do. + * Note however that we keep interrupts on during the scr_down. This + * could lead to snow if an interrupt happens while we are doing + * the display. Sorry, but I don't see any good alternative. + * Turning off interrupts makes us loses RS232 input chars. + */ + wait = color && ! ega; + while (count > 0) { + if (wait) { + old_state = wait_retrace(); + restore(old_state); + } + ct = MIN (count, vid_retrace >> 1); + scr_down(base, src, dst, ct); + src -= ct * 2; + dst -= ct * 2; + count -= ct; + } + } /*===========================================================================* * set_6845 * *************** *** 1415,1424 **** --- 1842,1863 ---- port_out(vid_port + DATA, val&BYTE); /* output low byte */ } + /* Similar, but used for registers where we only want to set one byte */ + + PRIVATE setb6845(reg, val) + int reg; /* which register pair to set */ + int val; /* 16-bit value to set it to */ + { + port_out(vid_port + INDEX, reg); /* set the index register */ + port_out(vid_port + DATA, val); /* output high byte */ + } /*===========================================================================* * beep * *===========================================================================*/ + PRIVATE int beeping = 0; + PRIVATE int stopbeep(); + PRIVATE beep(f) int f; /* this value determines beep frequency */ { *************** *** 1428,1447 **** * on the bits in port B of the 8255 chip that drive the speaker. */ ! int x, k, s; ! s = 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 */ restore(s); /* re-enable interrupts to previous state */ } - /*===========================================================================* * set_leds * *===========================================================================*/ --- 1867,1903 ---- * on the bits in port B of the 8255 chip that drive the speaker. */ ! int k, s, x; ! message mess; ! ! if (beeping) ! return; s = 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 */ ! beeping = 1; ! restore(s); /* re-enable interrupts to previous state */ ! ! mess.m_type = SET_ALARM; ! mess.CLOCK_PROC_NR = TTY; ! mess.DELTA_TICKS = B_TIME; ! mess.FUNC_TO_CALL = stopbeep; ! sendrec(CLOCK, &mess); ! } ! ! stopbeep() { ! int s, x; ! ! s = lock(); /* disable interrupts */ ! port_in(PORT_B,&x); /* acquire status of port B */ ! port_out(PORT_B, x & 0xfffc); /* turn bits 0 and 1 on to beep */ ! beeping = 0; restore(s); /* re-enable interrupts to previous state */ } /*===========================================================================* * set_leds * *===========================================================================*/ *************** *** 1501,1506 **** --- 1957,1967 ---- vid_port = M_6845; vid_retrace = M_RETRACE; } + + if (ega) { + vid_mask = C_VID_MASK; + vid_retrace = SCR_BYTES; + } 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 */ *************** *** 1511,1516 **** --- 1972,1978 ---- * keyboard in use. */ if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE; + if (scan_code == SPACE_SCAN) ext_kbd = TRUE; } *************** *** 1547,1552 **** --- 2009,2021 ---- tty_struct[0].tty_org = 0; move_to(&tty_struct[0], 0, SCR_LINES-1); /* cursor to lower left */ set_6845(VID_ORG, 0); + if (ega) { + /* If EGA, we use the funny line compare reg for scrolling. Reinit it. + * see comments in scroll code. */ + setb6845(OVRFL_REG, 0x1f); + setb6845(LINE_CMP, 0xff); + } + if (softscroll) printf("\033[H\033[JSoftware scrolling enabled.\n"); else *************** *** 2018,2024 **** for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; tp++){ tp->tty_inhead = tp->tty_inqueue; tp->tty_intail = tp->tty_inqueue; ! tp->tty_mode = CRMOD | XTABS | ECHO; tp->tty_devstart = start_rs232; tp->tty_erase = ERASE_CHAR; tp->tty_kill = KILL_CHAR; --- 2487,2494 ---- for (tp = &tty_struct[NR_CONS]; tp < &tty_struct[NR_CONS+NR_RS_LINES]; tp++){ tp->tty_inhead = tp->tty_inqueue; tp->tty_intail = tp->tty_inqueue; ! /* tp->tty_mode = CRMOD | XTABS | ECHO; */ ! tp->tty_mode = RAW | BITS8; tp->tty_devstart = start_rs232; tp->tty_erase = ERASE_CHAR; tp->tty_kill = KILL_CHAR; *************** *** 2030,2037 **** tp->tty_makebreak = ONE_INT; /* RS232 only interrupts once/char */ } ! rs_struct[0].rs_base = PRIMARY; ! rs_struct[1].rs_base = SECONDARY; for (rs = &rs_struct[0]; rs < &rs_struct[NR_RS_LINES]; rs++) { line = rs - rs_struct + NR_CONS; --- 2500,2511 ---- tp->tty_makebreak = ONE_INT; /* RS232 only interrupts once/char */ } ! #if NR_RS_LINES > 0 ! rs_struct[0].rs_base = PRIMARY; ! #endif ! #if NR_RS_LINES > 1 ! rs_struct[1].rs_base = SECONDARY; ! #endif for (rs = &rs_struct[0]; rs < &rs_struct[NR_RS_LINES]; rs++) { line = rs - rs_struct + NR_CONS; *** fsck.c.ORIG Thu Jan 1 00:16:11 1970 --- fsck.c Thu Jan 1 00:16:22 1970 *************** *** 1851,1856 **** --- 1851,1857 ---- printf(" l check and list file system (first insert any file system diskette)\n"); printf(" m make an (empty) file system (first insert blank, formatted diskette)\n"); printf(" h check hard disk file system\n"); + printf(" <SPACE> to start MINIX with extended keyboard\n"); printf("\n# "); c = getc(); command = c & 0xFF; *************** *** 1895,1900 **** --- 1896,1902 ---- } break; + case ' ': case '=': return((c >> 8) & 0xFF); default: printf("Illegal command\n");