From 063ea0088ed4798fc3be7dc47ce4e89dbf3e26f3 Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 15 Apr 2022 11:20:11 +0300 Subject: [PATCH] Kernel: Enable PS2 keyboard scan code translation if not already enabled On the QEMU microvm machine type, it became apparent that the BIOS was not setting the i8042 controller to function as expected. To ensure that the controller is always outputting correct scan codes, set it to scan code 2 and enable first port translation to ensure all scan codes are translated to scan code set 1. This is the expected behavior when using SeaBIOS, but on qboot (the BIOS for the QEMU microvm machine type), the firmware doesn't take care of this so we need to do this ourselves. --- Kernel/Devices/HID/I8042Controller.cpp | 10 ++++++++++ Kernel/Devices/HID/I8042Controller.h | 1 + 2 files changed, 11 insertions(+) diff --git a/Kernel/Devices/HID/I8042Controller.cpp b/Kernel/Devices/HID/I8042Controller.cpp index f05f5aa6cc..aeeb9edfa2 100644 --- a/Kernel/Devices/HID/I8042Controller.cpp +++ b/Kernel/Devices/HID/I8042Controller.cpp @@ -109,7 +109,17 @@ UNMAP_AFTER_INIT ErrorOr I8042Controller::detect_devices() TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); configuration &= ~I8042ConfigurationFlag::FirstPS2PortInterrupt; configuration &= ~I8042ConfigurationFlag::SecondPS2PortInterrupt; + + // Note: The default BIOS on the QEMU microvm machine type (qboot) doesn't + // behave like SeaBIOS, which means it doesn't set first port scan code translation. + // Howerver we rely on compatbility feature of the i8042 to send scan codes of set 1. + // To ensure that the controller is always outputting correct scan codes, set it + // to scan code 2 (because SeaBIOS on regular QEMU machine does this for us) and enable + // first port translation to ensure all scan codes are translated to scan code set 1. + configuration |= I8042ConfigurationFlag::FirstPS2PortTranslation; TRY(do_wait_then_write(I8042Port::Buffer, configuration)); + TRY(do_wait_then_write(I8042Port::Buffer, I8042Command::SetScanCodeSet)); + TRY(do_wait_then_write(I8042Port::Buffer, 0x2)); m_is_dual_channel = (configuration & I8042ConfigurationFlag::SecondPS2PortClock) != 0; dbgln("I8042: {} channel controller", m_is_dual_channel ? "Dual" : "Single"); diff --git a/Kernel/Devices/HID/I8042Controller.h b/Kernel/Devices/HID/I8042Controller.h index 5bbedce798..658dfc9712 100644 --- a/Kernel/Devices/HID/I8042Controller.h +++ b/Kernel/Devices/HID/I8042Controller.h @@ -30,6 +30,7 @@ enum I8042Command : u8 { DisableFirstPS2Port = 0xAD, EnableFirstPS2Port = 0xAE, WriteSecondPS2PortInputBuffer = 0xD4, + SetScanCodeSet = 0xF0, GetDeviceID = 0xF2, SetSampleRate = 0xF3, EnablePacketStreaming = 0xF4,