Minix1.5/kernel/keyboard.c
/* Keyboard driver for PC's and AT's. */
#include "kernel.h"
#include <sgtty.h>
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "tty.h"
/* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
#define KEYBD 0x60 /* I/O port for keyboard data */
/* AT keyboard. Most of these values are only used for rebooting. */
#define KB_COMMAND 0x64 /* I/O port for commands on AT */
#define KB_GATE_A20 0x02 /* bit in output port to enable A20 line */
#define KB_PULSE_OUTPUT 0xF0 /* base for commands to pulse output port */
#define KB_RESET 0x01 /* bit in output port to reset CPU */
#define KB_STATUS 0x64 /* I/O port for status on AT */
/* PS/2 model 30 keyboard. */
#define PS_KB_STATUS 0x72 /* I/O port for status on ps/2 (???) */
#define PS_KEYBD 0x68 /* I/O port for data on ps/2 */
/* AT and PS/2 model 30 keyboards. */
#define KB_ACK 0xFA /* keyboard ack response */
#define KB_BUSY 0x02 /* status bit set when KEYBD port ready */
#define LED_CODE 0xED /* command to keyboard to set LEDs */
#define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
#define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
/* All keyboards. */
#define KBIT 0x80 /* bit used to ack characters to keyboard */
/* Scan codes whose action is not completely captured by maps. */
#define DEL_SCAN 83 /* DEL for use in CTRL-ALT-DEL reboot */
#define DUTCH_EXT_SCAN 32 /* 'd' */
#define ESCAPE_CODE 0xE0 /* beginning of escape sequence */
#define F1 59 /* function key F1, others follow */
#define F2 60
#define F3 61
#define F4 62
#define F5 63
#define F8 66
#define F9 67
#define F10 68
#define MINUS_DU 0x35 /* '-' on Dutch extended keybd */
#define NUM_SLASH_DU 0x57 /* numeric keypad slash on Dutch extended kb */
#define OLIVETTI_SCAN 12 /* '=' key on olivetti */
#define SCODE1 71 /* Home on numeric pad */
#define SCODE2 81 /* PgDn on numeric pad */
#define STANDARD_SCAN 13 /* '=' key on IBM */
#define TOP_ROW 14 /* codes below this are shifted if CTRL */
#define US_EXT_SCAN 22 /* 'u' */
#define NR_SCAN_CODES 0x69 /* Number of scan codes */
/* Keyboard types. */
#define IBM_PC 1 /* Standard IBM keyboard */
#define OLIVETTI 2 /* Olivetti keyboard */
#define DUTCH_EXT 3 /* Dutch extended IBM keyboard */
#define US_EXT 4 /* U.S. extended keyboard */
/* Miscellaneous. */
#define CTRL_S 31 /* scan code for letter S (for CRTL-S) */
#define CONSOLE 0 /* line number for console */
#define MEMCHECK_ADR 0x472 /* address to stop memory check after reboot */
#define MEMCHECK_MAG 0x1234 /* magic number to stop memory check */
#define kb_addr(n) (&kb_lines[CONSOLE]) /* incorrectly ignore n */
#define KB_IBUFSIZE 32 /* size of keyboard input buffer */
PRIVATE int alt; /* alt key state */
PRIVATE int capslock; /* caps lock key state */
PRIVATE int esc; /* escape scan code detected? */
PRIVATE int control; /* control key state */
PRIVATE int caps_off; /* 1 = normal position, 0 = depressed */
PRIVATE int keyb_type; /* type of keyboard attached */
PRIVATE int minus_code; /* numeric minus on dutch extended keyboard */
PRIVATE int numlock; /* number lock key state */
PRIVATE int num_off; /* 1 = normal position, 0 = depressed */
PRIVATE int num_slash; /* numeric slash on dutch extended keyboard */
PRIVATE int shift1; /* left shift key state */
PRIVATE int shift2; /* right shift key state */
/* Scan codes to ASCII for alt keys (IBM Extended keyboard) */
PRIVATE char alt_c[NR_SCAN_CODES];
/* Scan codes to ASCII for unshifted keys for IBM-PC (default) */
PRIVATE char unsh[NR_SCAN_CODES] = {
0,033,'1','2','3','4','5','6', '7','8','9','0','-','=','\b','\t',
'q','w','e','r','t','y','u','i', 'o','p','[',']',015,0202,'a','s',
'd','f','g','h','j','k','l',';', 047,0140,0200,0134,'z','x','c','v',
'b','n','m',',','.','/',0201,'*', 0203,' ',0204,0241,0242,0243,0244,0245,
0246,0247,0250,0251,0252,0205,0210,0267, 0270,0271,0211,0264,0265,0266,0214
,0261,0262,0263,'0',0177,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
/* Scan codes to ASCII for shifted keys */
PRIVATE char sh[NR_SCAN_CODES] = {
0,033,'!','@','#','$','%','^', '&','*','(',')','_','+','\b','\t',
'Q','W','E','R','T','Y','U','I', 'O','P','{','}',015,0202,'A','S',
'D','F','G','H','J','K','L',':', 042,'~',0200,'|','Z','X','C','V',
'B','N','M','<','>','?',0201,'*', 0203,' ',0204,0221,0222,0223,0224,0225,
0226,0227,0230,0231,0232,0204,0213,'7', '8','9',0211,'4','5','6',0214,'1',
'2','3','0','.',0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
/* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
PRIVATE char unm24[NR_SCAN_CODES] = {
0,033,'1','2','3','4','5','6', '7','8','9','0','-','^','\b','\t',
'q','w','e','r','t','y','u','i', 'o','p','@','[','\r',0202,'a','s',
'd','f','g','h','j','k','l',';', ':',']',0200,'\\','z','x','c','v',
'b','n','m',',','.','/',0201,'*', 0203,' ',0204,0241,0242,0243,0244,0245,
0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
0262,0263,'0','.',' ',014,0212,'\r', 0264,0262,0266,0270,032,0213,' ','/',
0253,0254,0255,0256,0257,0215,0216,0217
};
/* Scan codes to ASCII for Olivetti M24 for shifted keys. */
PRIVATE char m24[NR_SCAN_CODES] = {
0,033,'!','"','#','$','%','&', 047,'(',')','_','=','~','\b','\t',
'Q','W','E','R' ,'T','Y','U','I', 'O','P',0140,'{','\r',0202,'A','S',
'D','F','G','H','J','K','L','+', '*','}',0200,'|','Z','X','C','V',
'B','N','M','<','>','?',0201,'*', 0203,' ',0204,0221,0222,0223,0224,0225,
0226,0227,0230,0231,0232,0270,023,'7', '8','9',0211,'4','5','6',0214,'1',
'2','3',0207,0177,0271,014,0272,'\r', '\b','\n','\f',036,032,0273,0274,'/',
0233,0234,0235,0236,0237,0275,0276,0277
};
PRIVATE char dutch_unsh[NR_SCAN_CODES] = {
0,033,'1','2','3','4','5','6', '7','8','9','0','/',0370,'\b','\t',
'q','w','e','r','t','y','u','i', 'o','p',0,'*','\r',0202,'a','s',
'd','f','g','h','j','k','l','+', '\'',0100,0200,'<','z','x','c','v',
'b','n','m',',','.','-',0201,'*', 0203,' ',0204,0,0,0,0,0,
0,0,0,0,0,0205,0,183, 184,185,137,180,'5',182,140,177,
178,179,0,0177,0,0,']','/',0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
PRIVATE char dutch_sh[NR_SCAN_CODES] = {
0,033,'!','\"','#','$','%','&', '_','(',')','\'','?',0176,'\b','\t',
'Q','W','E','R','T','Y','U','I', 'O','P','^','|','\r',0202,'A','S',
'D','F','G','H','J','K','L',0361, 0,025,0200,'>','Z','X','C','V',
'B','N','M',';',':','=',0201,'*', 0203,' ',0204,0,0,0,0,0,
0,0,0,0,0,0205,0,'7', '8','9',137,'4','5','6',140,'1',
'2','3','0',',',0,0,'[','/',0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
/* Code table for alt key */
PRIVATE char dutch_alt[NR_SCAN_CODES] = {
0,0,0,253,0,172,171,0, 156,'{','}',0,'\\',0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0202,0,0,
0,0,0,0,0,0,0,0, 0,170,0200,0,174,175,0,0,
0,0,0,0,0,0,0201,0, 0203,0,0204,0,0,0,0,0,
0,0,0,0,0,0205,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0177,0,0,'|',0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
/* Unshifted U.S. extended kbd */
PRIVATE char unsh_usx[NR_SCAN_CODES] = {
0,'`','1','2','3','4','5','6', '7','8','9','0','-','=','\b','\t',
'q','w','e','r','t','y','u','i', 'o','p','[',']',015,0202,'a','s',
'd','f','g','h','j','k','l',';', 047,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,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
/* Shifted U.S. extended kbd */
PRIVATE char sh_usx[NR_SCAN_CODES] = {
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','.',0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
PRIVATE char scode_map[] =
{'H', 'A', 'V', 'S', 'D', 'G', 'C', 'T', 'Y', 'B', 'U'};
/* Keyboard structure, 1 per console. */
struct kb_s {
int minor; /* minor number of this line (base 0) */
char *ibuf; /* start of input buffer */
char *ibufend; /* end of input buffer */
char *iptr; /* next free spot in input buffer */
char ibuf1[KB_IBUFSIZE + 1]; /* 1st input buffer, guard at end */
char ibuf2[KB_IBUFSIZE + 1]; /* 2nd input buffer (for swapping) */
};
PRIVATE struct kb_s kb_lines[NR_CONS];
FORWARD int kb_ack();
FORWARD int kb_wait();
FORWARD void load_dutch_table();
FORWARD void load_olivetti();
FORWARD void load_us_ext();
FORWARD int scan_keyboard();
FORWARD void set_leds();
/*===========================================================================*
* keyboard *
*===========================================================================*/
PUBLIC void keyboard()
{
/* A keyboard interrupt has occurred. Process it. */
int code, k;
register struct kb_s *kb;
/* Fetch the character from the keyboard hardware and acknowledge it. */
code = scan_keyboard();
/* The IBM keyboard interrupts twice per key, once when depressed, once when
* released. Filter out the latter, ignoring all but the shift-type keys.
* The shift-type keys 29, 42, 54, 56, 58, and 69 must be processed normally.
*/
if (keyb_type == DUTCH_EXT)
if (esc) {
/* Numeric slash gives scan codes 0xE0 0x35. */
if (code == minus_code) code = num_slash;
esc = FALSE;
} else
esc = (code == ESCAPE_CODE);
k = code - 0200; /* codes > 0200 mean key release */
if (k > 0) {
/* A key has been released. */
if (k != 29 && k != 42 && k != 54 && k != 56 && k != 58 && k != 69)
return; /* don't call tty_task() */
} else {
/* Check to see if character is CTRL-S, to stop output. Setting xoff
* to anything other than CTRL-S will not be detected here, but will
* be detected later, in the driver. A general routine to detect any
* xoff character here would be complicated since we only have the
* scan code here, not the ASCII character.
*/
if (!(tty_struct[CONSOLE].tty_mode & RAW) &&
control && code == CTRL_S &&
tty_struct[CONSOLE].tty_xoff == XOFF_CHAR) {
tty_struct[CONSOLE].tty_inhibited = STOPPED;
return;
}
}
/* Call debugger? (as early as practical, not in TTY which may be hung) */
if (code == F10 && db_exists) {
db_enabled = TRUE;
db();
}
/* Store the character in memory so the task can get at it later. */
kb = kb_addr(-NR_CONS);
*kb->iptr = code;
if (kb->iptr < kb->ibufend) {
lock(); /* protect shared variable */
tty_events += EVENT_THRESHOLD; /* C doesn't guarantee atomic */
unlock();
++kb->iptr;
}
/* Else it doesn't fit - discard it. */
}
/*==========================================================================*
* kb_read *
*==========================================================================*/
PUBLIC int kb_read(minor, bufindirect, odoneindirect)
int minor;
char **bufindirect;
unsigned char *odoneindirect;
{
/* Swap the keyboard input buffers, giving the old one to TTY. */
register char *ibuf;
register struct kb_s *kb;
int nread;
kb = kb_addr(minor);
*odoneindirect = FALSE;
if (kb->iptr == (ibuf = kb->ibuf)) return 0;
*bufindirect = ibuf;
lock();
nread = kb->iptr - ibuf;
tty_events -= nread * EVENT_THRESHOLD;
if (ibuf == kb->ibuf1)
ibuf = kb->ibuf2;
else
ibuf = kb->ibuf1;
kb->ibufend = ibuf + KB_IBUFSIZE;
kb->iptr = ibuf;
unlock();
kb->ibuf = ibuf;
return nread;
}
/*===========================================================================*
* letter_code *
*===========================================================================*/
PUBLIC int letter_code(scode)
int scode; /* scan code from key press */
{
/* Convert scan codes from numeric keypad to letters for use in escape seqs. */
if (scode >= SCODE1 && scode <= SCODE2 && (shift1 || shift2 || !numlock))
return scode_map[scode - SCODE1];
return 0;
}
/*===========================================================================*
* make_break *
*===========================================================================*/
PUBLIC int make_break(ch)
char ch; /* scan code of key just struck or released */
{
/* This routine can handle keyboards that interrupt only on key depression,
* as well as keyboards that interrupt on key depression and key release.
* For efficiency, the interrupt routine filters out most key releases.
*/
int c, make, code;
/* Check for CTRL-ALT-DEL, and if found, reboot the computer. This would
* be better done in keyboard() in case TTY is hung, except control and
* alt are set in the high level code.
*/
if (control && alt && ch == DEL_SCAN) reboot(); /* CTRL-ALT-DEL */
c = ch & 0177; /* high-order bit set on key release */
make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */
if (alt && keyb_type == DUTCH_EXT)
code = alt_c[c];
else
code = (shift1 || shift2 ? sh[c] : unsh[c]);
if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */
if (c >= SCODE1 && c <= SCODE2 + 2) /* numeric pad including DEL, INS */
code = (shift1 || shift2 || !numlock ? unsh[c] : sh[c]);
code &= BYTE;
if (code < 0200 || code >= 0206) {
/* Ordinary key, i.e. not shift, control, alt, etc. */
if (capslock)
if (code >= 'A' && code <= 'Z')
code += 'a' - 'A';
else if (code >= 'a' && code <= 'z')
code -= 'a' - 'A';
if (alt && keyb_type != DUTCH_EXT) code |= 0200; /* alt ORs in 0200 */
if (control) code &= 037;
if (make == 0) code = -1; /* key release */
return(code);
}
/* Table entries 0200 - 0206 denote special actions. */
switch(code - 0200) {
case 0: shift1 = make; break; /* shift key on left */
case 1: shift2 = make; break; /* shift key on right */
case 2:
#if KEYBOARD_84
/* Until IBM invented the 101-key keyboard, the CTRL key was always to the
* left of the 'A'. This fix puts it back there on the 101-key keyboard.
*/
if (make && caps_off) {
capslock = 1 - capslock;
set_leds();
}
caps_off = 1 - make; break; /* caps lock */
#else
control = make; break; /* control */
#endif
case 3: alt = make; break; /* alt key */
case 4:
#if KEYBOARD_84
control = make; break; /* control */
#else
if (make && caps_off) {
capslock = 1 - capslock;
set_leds();
}
caps_off = 1 - make; break; /* caps lock */
#endif
case 5: if (make && num_off) {
numlock = 1 - numlock;
set_leds();
}
num_off = 1 - make;
break; /* num lock */
}
return(-1);
}
/*===========================================================================*
* set_leds *
*===========================================================================*/
PRIVATE void set_leds()
{
/* Set the LEDs on the caps lock and num lock keys */
int leds, data_port, status_port;
if (!pc_at && !ps) return; /* PC/XT doesn't have LEDs */
leds = (numlock << 1) | (capslock << 2); /* encode LED bits */
if (ps) {
data_port = PS_KEYBD;
status_port = PS_KB_STATUS;
} else {
data_port = KEYBD;
status_port = KB_STATUS;
}
kb_wait(status_port); /* wait for buffer empty */
out_byte(data_port, LED_CODE); /* prepare keyboard to accept LED values */
kb_ack(data_port); /* wait for ack response */
kb_wait(status_port); /* wait for buffer empty */
out_byte(data_port, leds); /* give keyboard LED values */
kb_ack(data_port); /* wait for ack response */
}
/*==========================================================================*
* kb_wait *
*==========================================================================*/
PRIVATE int kb_wait(status_port)
int status_port;
{
/* Wait until the controller is ready; return zero if this times out. */
int retries;
retries = MAX_KB_BUSY_RETRIES + 1;
while (--retries != 0 && in_byte(status_port) & KB_BUSY)
; /* wait until not busy */
return(retries); /* nonzero if ready */
}
/*==========================================================================*
* kb_ack *
*==========================================================================*/
PRIVATE int kb_ack(data_port)
int data_port;
{
/* Wait until kbd acknowledges last command; return zero if this times out. */
int retries;
retries = MAX_KB_ACK_RETRIES + 1;
while (--retries != 0 && in_byte(data_port) != KB_ACK)
; /* wait for ack */
return(retries); /* nonzero if ack received */
}
/*===========================================================================*
* kb_init *
*===========================================================================*/
PUBLIC void kb_init(minor)
int minor;
{
/* Initialize the keyboard driver. */
register struct kb_s *kb;
kb = kb_addr(minor);
/* Record minor number. */
kb->minor = minor;
/* Set up input queue. */
kb->iptr = kb->ibuf = kb->ibuf1;
kb->ibufend = kb->ibuf1 + KB_IBUFSIZE;
kb->iptr = kb->ibuf1;
/* Set initial values. */
caps_off = 1;
num_off = 1;
set_leds(); /* turn off numlock led */
/* Determine which keyboard type is attached. The bootstrap program asks
* the user to type an '='. The scan codes for '=' differ depending on the
* keyboard in use.
*/
switch(scan_code) {
case STANDARD_SCAN: keyb_type = IBM_PC; break;
case OLIVETTI_SCAN: keyb_type = OLIVETTI; load_olivetti(); break;
case DUTCH_EXT_SCAN: keyb_type = DUTCH_EXT;
load_dutch_table(); break;
case US_EXT_SCAN: keyb_type = US_EXT;
load_us_ext(); break;
}
scan_keyboard(); /* stop lockup from leftover keystroke */
enable_irq(KEYBOARD_IRQ); /* safe now everything initialised! */
}
/*===========================================================================*
* load_dutch_table *
*===========================================================================*/
PRIVATE void load_dutch_table()
{
/* Load the scan code to ASCII table for extended dutch keyboard. */
register int i;
for (i = 0; i < NR_SCAN_CODES; i++) {
sh[i] = dutch_sh[i];
unsh[i] = dutch_unsh[i];
alt_c[i] = dutch_alt[i];
}
minus_code = MINUS_DU;
num_slash = NUM_SLASH_DU;
}
/*===========================================================================*
* load_olivetti *
*===========================================================================*/
PRIVATE void load_olivetti()
{
/* Load the scan code to ASCII table for olivetti type keyboard. */
register int i;
for (i = 0; i < NR_SCAN_CODES; i++) {
sh[i] = m24[i];
unsh[i] = unm24[i];
}
}
/*===========================================================================*
* load_us_ext *
*===========================================================================*/
PRIVATE void load_us_ext()
{
/* Load the scan code to ASCII table for US extended keyboard. */
register int i;
for (i = 0; i < NR_SCAN_CODES; i++) {
sh[i] = sh_usx[i];
unsh[i] = unsh_usx[i];
}
}
/*===========================================================================*
* func_key *
*===========================================================================*/
PUBLIC int func_key(ch)
char ch; /* scan code for a function key */
{
/* This procedure traps function keys for debugging and control purposes. */
if (ch < F1 || ch > F10) return(FALSE); /* not our job */
if (ch == F1) p_dmp(); /* print process table */
if (ch == F2) map_dmp(); /* print memory map */
if (ch == F3) toggle_scroll(); /* hardware vs. software scrolling */
#if AM_KERNEL
#if !NONET
if (ch == F4) net_init(); /* Re-initialise the ethernet card */
#endif
if (ch == F5) amdump(); /* Dump Amoeba statistics. */
#endif /* AM_KERNEL */
if (ch == F8 && control) sigchar(&tty_struct[CONSOLE], SIGINT);
if (ch == F9 && control) sigchar(&tty_struct[CONSOLE], SIGKILL);
return(TRUE);
}
/*==========================================================================*
* scan_keyboard *
*==========================================================================*/
PRIVATE int scan_keyboard()
{
/* Fetch the character from the keyboard hardware and acknowledge it. */
int code;
int val;
if (ps) {
code = in_byte(PS_KEYBD); /* get the scan code for key struck */
val = in_byte(0x69); /* acknowledge it in mysterious ways */
out_byte(0x69, val ^ 0x10); /* 0x69 should be equiv to PORT_B */
out_byte(0x69, val); /* XOR looks fishy */
val = in_byte(0x66); /* what is 0x66? */
out_byte(0x66, val & ~0x10); /* 0x72 for PS_KB_STATUS is fishier */
out_byte(0x66, val | 0x10);
out_byte(0x66, val & ~0x10);
} else {
code = in_byte(KEYBD); /* get the scan code for the key struck */
val = in_byte(PORT_B); /* strobe the keyboard to ack the char */
out_byte(PORT_B, val | KBIT); /* strobe the bit high */
out_byte(PORT_B, val); /* now strobe it low */
}
return code;
}
/*==========================================================================*
* reboot *
*==========================================================================*/
PUBLIC void reboot()
{
/* Reboot the machine. */
static u16_t magic = MEMCHECK_MAG;
lock();
eth_stp(); /* stop ethernet (may be unnecessary) */
/* Stop BIOS memory test. */
phys_copy(numap(TTY, (vir_bytes) &magic, sizeof magic),
(phys_bytes) MEMCHECK_ADR, (phys_bytes) sizeof magic);
if (protected_mode) {
/* Rebooting is nontrivial because the BIOS reboot code is in real
* mode and there is no sane way to return to real mode on 286's.
*/
if (pc_at) {
/* Use the AT keyboard controller to reset the processor.
* The A20 line is kept enabled in case this code is ever
* run from extended memory, and because some machines
* appear to drive the fake A20 high instead of low just
* after reset, leading to an illegal opode trap. This bug
* is more of a problem if the fake A20 is in use, as it
* would be if the keyboard reset were used for real mode.
*/
kb_wait();
out_byte(KB_COMMAND,
KB_PULSE_OUTPUT | (0x0F & ~(KB_GATE_A20 | KB_RESET)));
} else {
printf("No way to reboot from protected mode on this machine ");
}
while (TRUE)
; /* no way to recover if the above fails */
}
/* In real mode, jumping to the reset address is good enough. */
reset();
}
/*==========================================================================*
* wreboot *
*==========================================================================*/
PUBLIC void wreboot()
{
/* Wait for a keystroke, then reboot the machine. Don't rely on interrupt
* to provide the keystroke, since this is usually called after a crash,
* and possibly before interrupts are initialized.
*/
register int scancode;
lock();
milli_delay(1000); /* pause for a second to ignore key release */
scan_keyboard(); /* ack any old input */
printf("Type any key to reboot\r\n");
scancode = scan_keyboard(); /* quiescent value (0 on PC, last code on AT)*/
while(scan_keyboard() == scancode)
; /* loop until new keypress or any release */
reboot();
}