From 4eb902d85384ba9b3541cd9f37c64b569ebfb86b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 19:44:15 +0200 Subject: [PATCH] More keyboard controller fixes. --- src/cpu/x86.c | 14 ++++++-- src/device/keyboard_at.c | 64 ++++++++++++++++++++++++++++++------ src/include/86box/keyboard.h | 1 + src/mem/mem.c | 5 +-- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/cpu/x86.c b/src/cpu/x86.c index eb1dc463f..47250045f 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -29,6 +29,7 @@ #include <86box/device.h> #include <86box/dma.h> #include <86box/io.h> +#include <86box/keyboard.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/nmi.h> @@ -265,9 +266,12 @@ reset_common(int hard) if (is286) { loadcs(0xF000); cpu_state.pc = 0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - if (is6117) - rammask |= 0x03000000; + if (hard) { + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + if (is6117) + rammask |= 0x03000000; + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } } idt.base = 0; cpu_state.flags = 2; @@ -315,6 +319,10 @@ reset_common(int hard) cache_index = 0; memset(_tr, 0x00, sizeof(_tr)); memset(_cache, 0x00, sizeof(_cache)); + + /* If we have an AT or PS/2 keyboard controller, make sure the A20 state + is correct. */ + kbc_at_a20_reset(); } if (!is286) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index b0308529d..bfa6fa0be 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -878,6 +878,8 @@ kbc_scan_kbd_at(atkbd_t *dev) } } +static void write_output(atkbd_t *dev, uint8_t val); + static void kbc_poll_at(atkbd_t *dev) { @@ -905,8 +907,12 @@ kbc_poll_at(atkbd_t *dev) break; case KBC_STATE_MAIN_KBD: case KBC_STATE_MAIN_BOTH: - (void) kbc_scan_kbd_at(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_at(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_KBC_OUT: /* Keyboard controller command want to output multiple bytes. */ @@ -1013,13 +1019,21 @@ kbc_poll_ps2(atkbd_t *dev) break; case KBC_STATE_MAIN_KBD: // pclog("KBC_STATE_MAIN_KBD\n"); - (void) kbc_scan_kbd_ps2(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_MAIN_MOUSE: // pclog("KBC_STATE_MAIN_MOUSE\n"); - (void) kbc_scan_aux_ps2(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_aux_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_MAIN_BOTH: // pclog("KBC_STATE_MAIN_BOTH\n"); @@ -2230,7 +2244,9 @@ write64_toshiba(void *priv, uint8_t val) static void kbd_key_reset(atkbd_t *dev, int do_fa) { + dev->out_new = -1; kbc_queue_reset(1); + kbd_last_scan_code = 0x00; /* Set scan code set to 2. */ @@ -2253,6 +2269,7 @@ kbd_key_reset(atkbd_t *dev, int do_fa) static void kbd_aux_reset(atkbd_t *dev, int do_fa) { + dev->out_new_mouse = -1; kbc_queue_reset(2); mouse_scan = 1; @@ -2475,7 +2492,15 @@ kbc_process_cmd(void *priv) kbd_log("ATkbc: self-test\n"); if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - dev->status = 0x60; + if (dev->kbc_state != KBC_STATE_RESET) { + kbd_log("ATkbc: self-test reinitialization\n"); + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; + write_output(dev, 0x4b); + } + + dev->status = (dev->status & 0x0f) | 0x60; dev->mem[0x20] = 0x30; dev->mem[0x21] = 0x01; @@ -2497,7 +2522,7 @@ kbc_process_cmd(void *priv) write_output(dev, 0xcf); } - dev->status = 0x60; + dev->status = (dev->status & 0x0f) | 0x60; dev->mem[0x20] = 0x10; dev->mem[0x21] = 0x01; @@ -2511,10 +2536,14 @@ kbc_process_cmd(void *priv) dev->mem[0x2c] = 0x15; } + dev->out_new = dev->out_new_mouse = -1; kbc_queue_reset(0); - dev->kbc_state = KBC_STATE_MAIN_IBF; - add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + // dev->kbc_state = KBC_STATE_MAIN_IBF; + dev->kbc_state = KBC_STATE_KBC_OUT; + + // add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + kbc_queue_add(dev, 0x55, 0); break; case 0xab: /* interface test */ @@ -2814,6 +2843,7 @@ kbd_reset(void *priv) dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; dev->ami_stat |= 0x02; + dev->output_port = 0xcd; if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { write_output(dev, 0x4b); } else { @@ -2841,6 +2871,20 @@ keyboard_at_reset(void) kbd_reset(SavedKbd); } +void +kbc_at_a20_reset(void) +{ + if (SavedKbd) { + SavedKbd->output_port = 0xcd; + if ((SavedKbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + write_output(SavedKbd, 0x4b); + } else { + /* The real thing writes CF and then AND's it with BF. */ + write_output(SavedKbd, 0x8f); + } + } +} + static void kbd_close(void *priv) { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 767ffdca7..0fd25dbd0 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -210,6 +210,7 @@ extern void keyboard_at_set_mode(int ps2); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); extern void keyboard_at_reset(void); +extern void kbc_at_a20_reset(void); #ifdef __cplusplus } diff --git a/src/mem/mem.c b/src/mem/mem.c index 1af83c844..9de4a670f 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2530,11 +2530,12 @@ void mem_a20_init(void) { if (is286) { - rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; if (is6117) rammask |= 0x03000000; flushmmucache(); - mem_a20_state = mem_a20_key | mem_a20_alt; + // mem_a20_state = mem_a20_key | mem_a20_alt; } else { rammask = 0xfffff; flushmmucache();