From f4443b83934c518030d8d4135d40099b92ce79da Mon Sep 17 00:00:00 2001 From: FeralChild64 Date: Mon, 10 Jun 2024 21:08:21 +0200 Subject: [PATCH] Replace Ultima VIII keyboard hack with a proper solution --- src/cpu/callback.cpp | 11 ++++++ src/hardware/input/intel8042.cpp | 67 -------------------------------- src/ints/bios_keyboard.cpp | 40 +------------------ 3 files changed, 12 insertions(+), 106 deletions(-) diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index 30e1ec9e9c..5fb68b282b 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -288,7 +288,17 @@ static uint8_t callback_setup_extra(const callback_number_t callback_number, break; case CB_IRQ1: // keyboard INT9 add_instruction_1(0x50); // push ax + // Disable keyboard port + add_instruction_2(0xb0, 0xad); // mov al, 0xad + add_instruction_2(0xe6, 0x64); // out 0x64, al + // Read the keyboard input add_instruction_2(0xe4, 0x60); // in al, 0x60 + // Re-enable keyboard port + add_instruction_1(0x50); // push ax + add_instruction_2(0xb0, 0xae); // mov al, 0xae + add_instruction_2(0xe6, 0x64); // out 0x64, al + add_instruction_1(0x58); // pop ax + // Handle keyboard interception via INT 15h add_instruction_2(0xb4, 0x4f); // mov ah, 0x4f add_instruction_1(0xf9); // stc add_instruction_2(0xcd, 0x15); // int 0x15 @@ -297,6 +307,7 @@ static uint8_t callback_setup_extra(const callback_number_t callback_number, add_native_call_4(callback_number); // jump here to (skip): } + // Process the key, handle PIC add_instruction_1(0xfa); // cli add_instruction_2(0xb0, 0x20); // mov al, 0x20 add_instruction_2(0xe6, 0x20); // out 0x20, al diff --git a/src/hardware/input/intel8042.cpp b/src/hardware/input/intel8042.cpp index d8c490b3b9..0b640bcc81 100644 --- a/src/hardware/input/intel8042.cpp +++ b/src/hardware/input/intel8042.cpp @@ -370,63 +370,6 @@ static uint8_t get_translated(const uint8_t byte) return translation_table[byte]; } -// *************************************************************************** -// Port disable workaround -// *************************************************************************** - -// TODO: This part is a workaround for 'Ultima VIII: Pagan' problem with -// non-working keyboard. The proper fix would require larger rework: -// - it seems that even if keyboard is disabled, the 8042 should fire the -// interrupt -// - testing with 86Box revealed that command 0xad (disable keyboard port) and -// 0xae (enable port) are being sent by BIOS with each and every key press; -// our internal BIOS does not work this way -// -// Ignoring command 0xad totally might be risky, as Windows 3.11 for Workgroups -// disables/reenables the keyboard port during startup and shutdown, issuing -// controller commands in between; if something disturbs it, we might run into -// a problem with keyboard/mouse not responding at all. -// -// This code re-enables the keyboard after certain time - unless there is -// some command currently being issued to the controller. - -static bool kbd_disabled_timer_running = false; -static bool kbd_disabled_timer_expired = true; - -// Make the delay a little longer than between two bytes of a scancode, -// even lower values are enough -constexpr double KbdDisabledDurationMs = PortDelayMs * 1.5f; - -// Forward declaration -static void restart_kbd_disabled_timer(); - -static void maybe_reenable_kbd_port() -{ - if (is_disabled_kbd && kbd_disabled_timer_expired) { - is_disabled_kbd = false; - } -} - -static void kbd_disabled_timer_handler(uint32_t /*val*/) -{ - kbd_disabled_timer_running = false; - kbd_disabled_timer_expired = true; - - if (current_command != Command::None) { - restart_kbd_disabled_timer(); - } -} - -static void restart_kbd_disabled_timer() -{ - if (kbd_disabled_timer_running) { - PIC_RemoveEvents(kbd_disabled_timer_handler); - } - PIC_AddEvent(kbd_disabled_timer_handler, KbdDisabledDurationMs); - kbd_disabled_timer_running = true; - kbd_disabled_timer_expired = false; -} - // *************************************************************************** // Controller buffer support // *************************************************************************** @@ -776,7 +719,6 @@ static void execute_command(const Command command) is_disabled_kbd = true; uses_kbd_translation = true; passed_self_test = true; - restart_kbd_disabled_timer(); flush_buffer(); buffer_add(0x55); break; @@ -785,7 +727,6 @@ static void execute_command(const Command command) // (as with aux port test) // Disables the keyboard port is_disabled_kbd = true; - restart_kbd_disabled_timer(); flush_buffer(); buffer_add(0x00); // as with TestPortAux break; @@ -811,7 +752,6 @@ static void execute_command(const Command command) // Disable keyboard port; any keyboard command // reenables the port is_disabled_kbd = true; - restart_kbd_disabled_timer(); break; case Command::EnablePortKbd: // 0xae // Enable the keyboard port @@ -1034,9 +974,6 @@ static void write_data_port(io_port_t, io_val_t value, io_width_t) // port 0x60 // A controller command is waiting for a parameter const auto command = current_command; current_command = Command::None; - if (is_disabled_kbd) { - restart_kbd_disabled_timer(); - } const bool should_notify_aux = !I8042_IsReadyForAuxFrame(); const bool should_notify_kbd = !I8042_IsReadyForKbdFrame(); @@ -1080,9 +1017,6 @@ static void write_command_port(io_port_t, io_val_t value, io_width_t) // port 0x status_byte.was_last_write_cmd = true; current_command = Command::None; - if (is_disabled_kbd) { - restart_kbd_disabled_timer(); - } if ((byte <= 0x1f) || (byte >= 0x40 && byte <= 0x5f)) { // AMI BIOS systems command aliases execute_command(static_cast(byte + 0x20)); @@ -1173,7 +1107,6 @@ bool I8042_IsReadyForAuxFrame() bool I8042_IsReadyForKbdFrame() { - maybe_reenable_kbd_port(); return !waiting_bytes_from_kbd && !is_disabled_kbd && !is_diagnostic_dump; } diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 6faa0fc0b5..3788a32f34 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -533,7 +533,7 @@ static bool IsEnhancedKey(uint16_t &key) { return false; } -static Bitu INT16_Handler(void) { +static Bitu INT16_Handler(void) { // XXX uint16_t temp=0; switch (reg_ah) { case 0x00: /* GET KEYSTROKE */ @@ -659,49 +659,11 @@ void BIOS_SetupKeyboard(void) { call_irq1=CALLBACK_Allocate(); CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRQ1,RealToPhysical(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard"); RealSetVec(0x09,BIOS_DEFAULT_IRQ1_LOCATION); - // pseudocode for CB_IRQ1: - // push ax - // in al, 0x60 - // mov ah, 0x4f - // stc - // int 15 - // jc skip - // callback IRQ1_Handler - // label skip: - // cli - // mov al, 0x20 - // out 0x20, al - // pop ax - // iret - // cli - // mov al, 0x20 - // out 0x20, al - // push bp - // int 0x05 - // pop bp - // pop ax - // iret if (machine==MCH_PCJR) { call_irq6=CALLBACK_Allocate(); CALLBACK_Setup(call_irq6,nullptr,CB_IRQ6_PCJR,"PCJr kb irq"); RealSetVec(0x0e,CALLBACK_RealPointer(call_irq6)); - // pseudocode for CB_IRQ6_PCJR: - // push ax - // in al, 0x60 - // cmp al, 0xe0 - // je skip - // push ds - // push 0x40 - // pop ds - // int 0x09 - // pop ds - // label skip: - // cli - // mov al, 0x20 - // out 0x20, al - // pop ax - // iret } }