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

View File

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

View File

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

View File

@ -9,21 +9,41 @@
namespace Kernel::Input 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) : PS2Device(controller, InputDevice::Type::Keyboard)
, m_basic(basic)
{ } { }
void PS2Keyboard::send_initialize() void PS2Keyboard::send_initialize()
{ {
constexpr uint8_t wanted_scancode_set = 3; constexpr uint8_t wanted_scancode_set = 3;
append_command_queue(Command::SET_LEDS, 0x00, 0); update_leds();
append_command_queue(Command::CONFIG_SCANCODE_SET, wanted_scancode_set, 0); if (m_scancode_set == 0xFF)
append_command_queue(Command::CONFIG_SCANCODE_SET, 0, 1); {
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) 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) if (command_data[0] == Command::CONFIG_SCANCODE_SET && m_scancode_set >= 0xFE)
{ {
dwarnln("Could not detect scancode set, assuming 1"); dwarnln("Could not detect scancode set, assuming 2");
m_scancode_set = 1; m_scancode_set = 2;
m_keymap.initialize(m_scancode_set); m_keymap.initialize(m_scancode_set);
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0); append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
} }
@ -169,6 +189,9 @@ namespace Kernel::Input
{ {
using KeyModifier = LibInput::KeyEvent::Modifier; using KeyModifier = LibInput::KeyEvent::Modifier;
if (m_basic)
return;
uint8_t new_leds = 0; uint8_t new_leds = 0;
if (m_modifiers & +KeyModifier::ScrollLock) if (m_modifiers & +KeyModifier::ScrollLock)
new_leds |= PS2::KBLeds::SCROLL_LOCK; new_leds |= PS2::KBLeds::SCROLL_LOCK;

View File

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