From 86a1ff520408e2af95d7e847ca40aed4247ec5f9 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Fri, 12 Nov 2021 00:17:30 +0100 Subject: [PATCH] Kernel: Drain I8042 PS/2 keyboard output after enabling As soon as we enable the first PS/2 port on the I8042 controller, the output buffer may become full. We need to drain it before attempting any new commands with the controller (such as enabling the second PS/2 port). Fixes #10872. --- Kernel/Devices/HID/I8042Controller.cpp | 11 ++++++----- Kernel/Devices/HID/I8042Controller.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Kernel/Devices/HID/I8042Controller.cpp b/Kernel/Devices/HID/I8042Controller.cpp index c19c58b38a..1e28a7e4a0 100644 --- a/Kernel/Devices/HID/I8042Controller.cpp +++ b/Kernel/Devices/HID/I8042Controller.cpp @@ -36,13 +36,12 @@ UNMAP_AFTER_INIT void I8042Controller::detect_devices() u8 configuration; { SpinlockLocker lock(m_lock); - // Disable devices + + drain_output_buffer(); + do_wait_then_write(I8042Port::Command, I8042Command::DisableFirstPS2Port); do_wait_then_write(I8042Port::Command, I8042Command::DisableSecondPS2Port); // ignored if it doesn't exist - // Drain buffers - do_drain(); - do_wait_then_write(I8042Port::Command, I8042Command::ReadConfiguration); configuration = do_wait_then_read(I8042Port::Buffer); do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration); @@ -75,6 +74,8 @@ UNMAP_AFTER_INIT void I8042Controller::detect_devices() dbgln("I8042: Keyboard port not available"); } + drain_output_buffer(); + if (m_is_dual_channel) { do_wait_then_write(I8042Port::Command, I8042Command::TestSecondPS2Port); m_second_port_available = (do_wait_then_read(I8042Port::Buffer) == 0); @@ -152,7 +153,7 @@ bool I8042Controller::irq_process_input_buffer(HIDDevice::Type instrument_type) return false; } -void I8042Controller::do_drain() +void I8042Controller::drain_output_buffer() { for (;;) { u8 status = IO::in8(I8042Port::Status); diff --git a/Kernel/Devices/HID/I8042Controller.h b/Kernel/Devices/HID/I8042Controller.h index 190d5c5044..86765a71d7 100644 --- a/Kernel/Devices/HID/I8042Controller.h +++ b/Kernel/Devices/HID/I8042Controller.h @@ -135,7 +135,6 @@ public: private: I8042Controller(); - void do_drain(); bool do_reset_device(HIDDevice::Type); u8 do_send_command(HIDDevice::Type type, u8 data); u8 do_send_command(HIDDevice::Type device, u8 command, u8 data); @@ -143,6 +142,7 @@ private: u8 do_read_from_device(HIDDevice::Type device); void do_wait_then_write(u8 port, u8 data); u8 do_wait_then_read(u8 port); + void drain_output_buffer(); Spinlock m_lock; bool m_first_port_available { false };