Kernel: Add ps2=<scancode set> command line argument

This allows forcing specific scancode set on broken PS/2 emulations
This commit is contained in:
Bananymous 2024-08-18 20:45:49 +03:00
parent 40c6989374
commit 42e2c15e0c
5 changed files with 57 additions and 24 deletions

View File

@ -15,7 +15,7 @@ namespace Kernel::Input
class PS2Controller
{
public:
static BAN::ErrorOr<void> initialize();
static BAN::ErrorOr<void> initialize(uint8_t scancode_set);
static PS2Controller& get();
bool append_command_queue(PS2Device*, uint8_t command, uint8_t response_size);
@ -26,8 +26,8 @@ namespace Kernel::Input
private:
PS2Controller() = default;
BAN::ErrorOr<void> initialize_impl();
BAN::ErrorOr<void> initialize_device(uint8_t);
BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set);
BAN::ErrorOr<void> initialize_device(uint8_t, uint8_t scancode_set);
BAN::ErrorOr<uint8_t> read_byte();
BAN::ErrorOr<void> send_byte(uint16_t port, uint8_t byte);

View File

@ -17,7 +17,7 @@ namespace Kernel::Input
};
public:
static BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> create(PS2Controller&);
static BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> create(PS2Controller&, uint8_t scancode_set);
virtual void send_initialize() override;
virtual void command_timedout(uint8_t* command_data, uint8_t command_size) final override;
@ -27,13 +27,14 @@ namespace Kernel::Input
virtual void update() final override { m_controller.update_command_queue(); }
private:
PS2Keyboard(PS2Controller& controller);
PS2Keyboard(PS2Controller& controller, bool basic);
void update_leds();
private:
BAN::Array<uint8_t, 3> m_byte_buffer;
uint8_t m_byte_index { 0 };
bool m_basic { false };
uint8_t m_scancode_set { 0xFF };
uint16_t m_modifiers { 0 };

View File

@ -221,14 +221,14 @@ namespace Kernel::Input
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> PS2Controller::initialize()
BAN::ErrorOr<void> PS2Controller::initialize(uint8_t scancode_set)
{
ASSERT(s_instance == nullptr);
s_instance = new PS2Controller;
if (s_instance == nullptr)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard guard([] { delete s_instance; });
TRY(s_instance->initialize_impl());
TRY(s_instance->initialize_impl(scancode_set));
guard.disable();
return {};
}
@ -239,7 +239,7 @@ namespace Kernel::Input
return *s_instance;
}
BAN::ErrorOr<void> PS2Controller::initialize_impl()
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
{
// Determine if the PS/2 Controller Exists
auto* fadt = static_cast<const ACPI::FADT*>(ACPI::ACPI::get().get_header("FACP"_sv, 0));
@ -317,7 +317,7 @@ namespace Kernel::Input
dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error());
continue;
}
if (auto res = initialize_device(device); res.is_error())
if (auto res = initialize_device(device, scancode_set); res.is_error())
{
dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error());
(void)send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT);
@ -368,7 +368,7 @@ namespace Kernel::Input
return {};
}
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device)
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device, uint8_t scancode_set)
{
// Reset device
TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET));
@ -411,7 +411,7 @@ namespace Kernel::Input
if (index == 2 && (bytes[0] == 0xAB && (bytes[1] == 0x83 || bytes[1] == 0x41)))
{
dprintln_if(DEBUG_PS2, "PS/2 found keyboard");
m_devices[device] = TRY(PS2Keyboard::create(*this));
m_devices[device] = TRY(PS2Keyboard::create(*this, scancode_set));
return {};
}

View File

@ -9,22 +9,42 @@
namespace Kernel::Input
{
BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> PS2Keyboard::create(PS2Controller& controller)
BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> PS2Keyboard::create(PS2Controller& controller, uint8_t scancode_set)
{
return TRY(BAN::RefPtr<PS2Keyboard>::create(controller));
auto keyboard = TRY(BAN::RefPtr<PS2Keyboard>::create(controller, scancode_set != 0));
if (scancode_set)
{
if (scancode_set > 3)
{
dwarnln("Invalid scancode set {}, using scan code set 2 instead", scancode_set);
scancode_set = 2;
}
keyboard->m_scancode_set = scancode_set;
keyboard->m_keymap.initialize(scancode_set);
dprintln("Skipping scancode detection, using scan code set {}", scancode_set);
}
return keyboard;
}
PS2Keyboard::PS2Keyboard(PS2Controller& controller)
PS2Keyboard::PS2Keyboard(PS2Controller& controller, bool basic)
: PS2Device(controller, InputDevice::Type::Keyboard)
, m_basic(basic)
{ }
void PS2Keyboard::send_initialize()
{
constexpr uint8_t wanted_scancode_set = 3;
append_command_queue(Command::SET_LEDS, 0x00, 0);
update_leds();
if (m_scancode_set == 0xFF)
{
append_command_queue(Command::CONFIG_SCANCODE_SET, wanted_scancode_set, 0);
append_command_queue(Command::CONFIG_SCANCODE_SET, 0, 1);
}
else
{
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
}
}
void PS2Keyboard::command_timedout(uint8_t* command_data, uint8_t command_size)
{
@ -33,8 +53,8 @@ namespace Kernel::Input
if (command_data[0] == Command::CONFIG_SCANCODE_SET && m_scancode_set >= 0xFE)
{
dwarnln("Could not detect scancode set, assuming 1");
m_scancode_set = 1;
dwarnln("Could not detect scancode set, assuming 2");
m_scancode_set = 2;
m_keymap.initialize(m_scancode_set);
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
}
@ -169,6 +189,9 @@ namespace Kernel::Input
{
using KeyModifier = LibInput::KeyEvent::Modifier;
if (m_basic)
return;
uint8_t new_leds = 0;
if (m_modifiers & +KeyModifier::ScrollLock)
new_leds |= PS2::KBLeds::SCROLL_LOCK;

View File

@ -32,12 +32,15 @@
#include <LibInput/KeyboardLayout.h>
#include <ctype.h>
struct ParsedCommandLine
{
bool force_pic = false;
bool disable_serial = false;
bool disable_smp = false;
bool disable_usb = false;
uint8_t ps2_override = 0;
BAN::StringView console = "tty0"_sv;
BAN::StringView root;
};
@ -78,6 +81,12 @@ static void parse_command_line()
cmdline.disable_smp = true;
else if (argument == "nousb")
cmdline.disable_usb = true;
else if (argument.starts_with("ps2="))
{
if (argument.size() != 5 || !isdigit(argument[4]))
dprintln("Invalid ps2= command line argument format '{}'", argument);
cmdline.ps2_override = argument[4] - '0';
}
else if (argument.size() > 5 && argument.substring(0, 5) == "root=")
cmdline.root = argument.substring(5);
else if (argument.size() > 8 && argument.substring(0, 8) == "console=")
@ -221,7 +230,7 @@ static void init2(void*)
// Initialize empty keymap
MUST(LibInput::KeyboardLayout::initialize());
if (auto res = PS2Controller::initialize(); res.is_error())
if (auto res = PS2Controller::initialize(cmdline.ps2_override); res.is_error())
dprintln("{}", res.error());
MUST(NetworkManager::initialize());