[comp.os.minix] kernel fixes for RS232 performance, EGA support, ANSI escape codes

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");