diff options
-rw-r--r-- | chip/lm4/lpc.c | 7 | ||||
-rw-r--r-- | common/keyboard.c | 31 | ||||
-rw-r--r-- | include/i8042_protocol.h | 6 | ||||
-rw-r--r-- | include/lpc.h | 3 |
4 files changed, 45 insertions, 2 deletions
diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c index 2ca762481d..8b8f0a2740 100644 --- a/chip/lm4/lpc.c +++ b/chip/lm4/lpc.c @@ -214,6 +214,13 @@ int lpc_keyboard_has_char(void) return (LM4_LPC_ST(LPC_CH_KEYBOARD) & LM4_LPC_ST_TOH) ? 1 : 0; } +/* Return true if the FRMH is set */ +int lpc_keyboard_input_pending(void) +{ + return (LM4_LPC_ST(LPC_CH_KEYBOARD) & LM4_LPC_ST_FRMH) ? 1 : 0; +} + +/* Put a char to host buffer and send IRQ if specified. */ void lpc_keyboard_put_char(uint8_t chr, int send_irq) { LPC_POOL_KEYBOARD[1] = chr; diff --git a/common/keyboard.c b/common/keyboard.c index f71842d7dd..2a68986a23 100644 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -62,6 +62,7 @@ static uint8_t controller_ram[0x20] = { I8042_XLATE | I8042_AUX_DIS | I8042_KBD_DIS, /* 0x01 - 0x1f are controller RAM */ }; +static uint8_t A20_status; static int power_button_pressed = 0; static void keyboard_special(uint16_t k); @@ -355,6 +356,7 @@ static enum { STATE_EX_SETLEDS_1, /* expect 2-byte parameter coming */ STATE_EX_SETLEDS_2, STATE_WRITE_CMD_BYTE, + STATE_WRITE_OUTPUT_PORT, STATE_ECHO_MOUSE, STATE_SETREP, STATE_SEND_TO_MOUSE, @@ -409,6 +411,13 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) data_port_state = STATE_NORMAL; break; + case STATE_WRITE_OUTPUT_PORT: + CPRINTF5("[%T KB eaten by STATE_WRITE_OUTPUT_PORT: 0x%02x]\n", + data); + A20_status = (data & (1 << 1)) ? 1 : 0; + data_port_state = STATE_NORMAL; + break; + case STATE_ECHO_MOUSE: CPRINTF5("[%T KB eaten by STATE_ECHO_MOUSE: 0x%02x]\n", data); output[out_len++] = data; @@ -559,6 +568,18 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) update_ctl_ram(0, read_ctl_ram(0) & ~I8042_KBD_DIS); break; + case I8042_READ_OUTPUT_PORT: + output[out_len++] = + (lpc_keyboard_input_pending() ? (1 << 5) : 0) | + (lpc_keyboard_has_char() ? (1 << 4) : 0) | + (A20_status ? (1 << 1) : 0) | + 1; /* Main processor in normal mode */ + break; + + case I8042_WRITE_OUTPUT_PORT: + data_port_state = STATE_WRITE_OUTPUT_PORT; + break; + case I8042_RESET_SELF_TEST: output[out_len++] = 0x55; /* Self test success */ break; @@ -599,9 +620,17 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) command <= I8042_WRITE_CTL_RAM_END) { data_port_state = STATE_WRITE_CMD_BYTE; controller_ram_address = command - 0x60; + } else if (command == I8042_DISABLE_A20) { + A20_status = 0; + } else if (command == I8042_ENABLE_A20) { + A20_status = 1; } else if (command >= I8042_PULSE_START && command <= I8042_PULSE_END) { - /* Pulse Output Bit. Not implemented. Ignore it. */ + /* Pulse Output Bits, + * b0=0 to reset CPU, see I8042_SYSTEM_RESET above + * b1=0 to disable A20 line + */ + A20_status = command & (1 << 1) ? 1 : 0; } else { CPRINTF("[%T KB unsupported cmd: 0x%02x]\n", command); reset_rate_and_delay(); diff --git a/include/i8042_protocol.h b/include/i8042_protocol.h index 961d3e337c..eecdafc476 100644 --- a/include/i8042_protocol.h +++ b/include/i8042_protocol.h @@ -55,11 +55,15 @@ #define I8042_TEST_KB_PORT 0xab #define I8042_DIS_KB 0xad #define I8042_ENA_KB 0xae +#define I8042_READ_OUTPUT_PORT 0xd0 +#define I8042_WRITE_OUTPUT_PORT 0xd1 #define I8042_ECHO_MOUSE 0xd3 /* expect a byte on port 0x60 */ #define I8042_SEND_TO_MOUSE 0xd4 /* expect a byte on port 0x60 */ +#define I8042_DISABLE_A20 0xdd +#define I8042_ENABLE_A20 0xdf #define I8042_PULSE_START 0xf0 -#define I8042_PULSE_END 0xfd #define I8042_SYSTEM_RESET 0xfe +#define I8042_PULSE_END 0xff /* port 0x60 return value */ #define I8042_RET_BAT 0xaa diff --git a/include/lpc.h b/include/lpc.h index 3dd39a105e..9ecef5027b 100644 --- a/include/lpc.h +++ b/include/lpc.h @@ -23,6 +23,9 @@ uint8_t *lpc_get_memmap_range(void); */ int lpc_keyboard_has_char(void); +/* Return true if the FRMH is still set */ +int lpc_keyboard_input_pending(void); + /** * Send a byte to host via keyboard port 0x60. * |