Skip to content

Commit

Permalink
Replace Ultima VIII keyboard hack with a proper solution
Browse files Browse the repository at this point in the history
  • Loading branch information
FeralChild64 committed Jun 16, 2024
1 parent 3845460 commit f4443b8
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 106 deletions.
11 changes: 11 additions & 0 deletions src/cpu/callback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
67 changes: 0 additions & 67 deletions src/hardware/input/intel8042.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
// ***************************************************************************
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<Command>(byte + 0x20));
Expand Down Expand Up @@ -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;
}

Expand Down
40 changes: 1 addition & 39 deletions src/ints/bios_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
}
}

0 comments on commit f4443b8

Please sign in to comment.