Path: tut!enea!mcvax!uunet!husc6!bloom-beacon!tut.cis.ohio-state.edu!rutgers!aramis.rutgers.edu!athos.rutgers.edu!hedrick
From: hedrick@athos.rutgers.edu (Charles Hedrick)
Newsgroups: comp.os.minix
Subject: ega fixes
Message-ID: <Aug.16.12.43.27.1988.16602@athos.rutgers.edu>
Date: 16 Aug 88 16:43:28 GMT
Organization: Rutgers Univ., New Brunswick, N.J.
Lines: 574


OK, I've had enough requests.  This set of diffs is a mixed bag.  It's
all for support of the EGA card, in one way or another.  One scrolling
thing is in tty.c, and is commented in a fairly obvious way.  In order
to make it work automatically, I have to know whether you are using an
EGA.  The test is done in main.c, but requires a subroutine in
klib88.s.  (It uses a BIOS call.  Apparently those have to be done
early in main.  When I tried it from tty.c, I got an error message.
It appears that once minix is up, it's not valid to talk to the BIOS
anymore.)  In addition, there are the following changes:
  - don't wait for retrace to put data on the screen for an EGA.
	It's not needed.  This is in klib88.
  - add an option to the startup menu (a space) specifying that
	you want special handling for the "extended" keyboard.
	Turns caps lock into control, reverses ESC and `,
	turns backspace into rubout.  This is in fsck and tty
  - provide ESC codes to set colors.  ESC [ 3x m and ESC [ 4 m
	set background and foreground colors (don't remember
	which is which).  x is the usual IBM PC color code.
  - on color monitor, make more use of color.  various of the
	codes that were there before now produce color changes.
	Also, normal text is now black on which instead of white
	on black.  This is really a matter of personal taste.
	If you don't like it, don't use it.  Changes are in
	tty.c and also klib88.  The klib changes are needed
	because vid_copy has an option that says "clear this
	region to spaces".  I have to choose the right kind of
	spaces.

The patch to make hardware scrolling work for EGA has a slight
sideeffect.  Now and then there is a brief glitch on the screen.
I suspect that the two register changes should be made during
vertical retrace.  This would mean adding somthing to klib88
that just waits for vertical retrace.  I haven't had a chance to
do it because I haven't figured out how to handle interrupts.
In theory you'd like to disable interrupts, so that you don't
wait for vertical retrace and get descheduled before you get
a chance to do anything.  But we certainly don't want to
disable interrupts for that long.  Chances are it would be OK
just to do it with interrupts enabled.  I think things are
particularly bad because of the black on white.  My suspicion
is that for one refresh cycle part of the screen is being
mapped to an area of the screen that is black.  I suspect that
this could be fixed by initializing the next page of the
screen memory to white.  I haven't had a chance to look at the
code yet, but suspect that the line that does
  if (ega)
    vid_mask = ....
could be changed to use C_VID_MASK rather than M_VID_MASK and
that might be enough.  My ega code doesn't use vid_mask at
all, but I think it determines how much of the screen gets
initialized.

*** klib88.s.ORIG	Thu Jan  1 00:10:10 1970
--- klib88.s	Sat Aug 13 23:44:13 1988
***************
*** 25,36 ****
  .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
  
  
  |*===========================================================================*
--- 25,37 ----
  .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
  
  | 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
  
  
  |*===========================================================================*
***************
*** 332,337 ****
--- 333,355 ----
  	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:
***************
*** 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
***************
*** 465,470 ****
--- 485,494 ----
  	ret			| return to caller
  
  vid.7:	mov ax,#BLANK		| ax = blanking character
+ 	test _color,*1		| if color, use reverse vid
+ 	jz vid.8		| if monochrome then go to vid.8
+ 	mov ax,#0x7000
+ vid.8:
  	rep			| copy loop
  	stow			| blank screen
  	jmp vid.5		| done
*** main.c.ORIG	Thu Jan  1 00:36:07 1970
--- main.c	Sat Aug 13 22:00:27 1988
***************
*** 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;
  
*** tty.c.ORIG	Thu Jan  1 00:36:21 1970
--- tty.c	Sat Aug 13 21:20:41 1988
***************
*** 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,179 ----
  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 */
  
  /* Scan codes to ASCII for unshifted keys */
  PRIVATE char unsh[] = {
***************
*** 194,199 ****
--- 195,220 ----
   '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[] = {
***************
*** 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) */
--- 525,538 ----
  
    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) */
***************
*** 961,966 ****
--- 989,995 ----
  #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	4000	/* # of bytes in RAM: LINE_WIDTH*SCR_LINES*2 */
  #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 ****
--- 1009,1019 ----
  #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 ****
--- 1022,1028 ----
  #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 */
***************
*** 1150,1155 ****
--- 1182,1188 ----
  			scroll_screen(tp, GO_FORWARD);
  		else
  			tp->tty_row++;
+ 
  		move_to(tp, tp->tty_column, tp->tty_row);
  		return;
  
***************
*** 1205,1221 ****
  		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 */
    }
  }
--- 1238,1306 ----
  		scr_down(vid_base);
  		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);
+ 	/* Tell the EGA what display memory to put at top of screen */  
+ 	set_6845(VID_ORG, tp->tty_org >> 1);	/* 6845 thinks in words */
+ 	/* Figure out where to wrap around to top of display mem */
+ 	lines = tp->tty_org / (LINE_WIDTH * 2);  /* convert to lines */
+ 	lines = 14 * (SCR_LINES - lines) - 1;  /* now to scan 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. */
+ 	if (lines > 255)
+ 	   setb6845(OVRFL_REG, 0x1f);  /* high order bit is in overflow reg */
+         else
+     	   setb6845(OVRFL_REG, 0x0f);  /* high order bit 0 */
+         setb6845(LINE_CMP, lines & 0xff);  /* now set line compare reg */
+   } 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 */
    }
  }
***************
*** 1234,1239 ****
--- 1319,1326 ----
  
    /* 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 ****
--- 1341,1349 ----
    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 */
  }
  
***************
*** 1364,1387 ****
  		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:
--- 1454,1502 ----
  		break;
  	case 'm':		/* Set graphic rendition */
   		switch (tp->tty_esc_parmv[0]) {
!  			case 1: /*  BOLD  (red on white)  */
! 				if (color)
! 	 				tp->tty_attribute = 0x74 << 8;
! 				else
! 	 				tp->tty_attribute = 0x0f << 8;
!  				break;
!  
!  			case 4: /*  UNDERLINE  (blue on white)  */
! 				if (color)
! 					tp->tty_attribute = 0x71 << 8;
! 				else
! 					tp->tty_attribute = 0x01 << 8;
!  				break;
!  
!  			case 5: /*  BLINKING */
! 				if (color)
! 					tp->tty_attribute = 0xf0 << 8;
! 				else
! 					tp->tty_attribute = 0x87 << 8;
   				break;
   
   			case 7: /*  REVERSE  (black on light grey)  */
! 				if (color)
! 	 				tp->tty_attribute = 0x07 << 8;
! 				else
! 	 				tp->tty_attribute = 0x70 << 8;
!   				break;
! 
!  			default: if (tp->tty_esc_parmv[0] >= 40 &&
! 				     tp->tty_esc_parmv[0] <= 47)
! 					tp->tty_attribute = 
! 					(tp->tty_attribute & 0xf0ff) |
! 					((tp->tty_esc_parmv[0] - 40) << 8);
! 				else if (tp->tty_esc_parmv[0] >= 30 &&
! 				     tp->tty_esc_parmv[0] <= 37)
! 					tp->tty_attribute = 
! 					(tp->tty_attribute & 0x0fff) |
! 					((tp->tty_esc_parmv[0] - 30) << 12);
! 				else if (color)
! 	 				tp->tty_attribute = 0x70 << 8;
! 				else
! 	 				tp->tty_attribute = 0x07 << 8;
!   				break;
   		}
  		break;
  	default:
***************
*** 1415,1421 ****
    port_out(vid_port + DATA, val&BYTE);	/* output low byte */
  }
  
! 
  /*===========================================================================*
   *				beep					     *
   *===========================================================================*/
--- 1530,1544 ----
    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					     *
   *===========================================================================*/
***************
*** 1480,1486 ****
  	tp->tty_mode = CRMOD | XTABS | ECHO;
  	tp->tty_devstart = console;
  	tp->tty_makebreak = TWO_INTS;
! 	tp->tty_attribute = BLANK;
  	tp->tty_erase = ERASE_CHAR;
  	tp->tty_kill  = KILL_CHAR;
  	tp->tty_intr  = INTR_CHAR;
--- 1603,1612 ----
  	tp->tty_mode = CRMOD | XTABS | ECHO;
  	tp->tty_devstart = console;
  	tp->tty_makebreak = TWO_INTS;
! 	if (color)
! 	  tp->tty_attribute = 0x7000;
! 	else
! 	  tp->tty_attribute = BLANK;
  	tp->tty_erase = ERASE_CHAR;
  	tp->tty_kill  = KILL_CHAR;
  	tp->tty_intr  = INTR_CHAR;
***************
*** 1501,1506 ****
--- 1627,1635 ----
  	vid_port = M_6845;
  	vid_retrace = M_RETRACE;
    }
+ 
+   if (ega)
+     vid_mask = M_VID_MASK;
    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 ****
--- 1640,1646 ----
     * keyboard in use.
     */
    if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE;
+   if (scan_code == SPACE_SCAN) ext_kbd = TRUE;
  }
  
  
***************
*** 1547,1552 ****
--- 1677,1689 ----
  	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
*** fsck.c.ORIG	Thu Jan  1 00:43:32 1970
--- fsck.c	Sat Aug 13 20:36:39 1988
***************
*** 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");
