Kernel: Add ps2=<scancode set> command line argument
This allows forcing specific scancode set on broken PS/2 emulations
This commit is contained in:
parent
40c6989374
commit
42e2c15e0c
|
@ -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);
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,42 @@
|
||||||
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();
|
||||||
|
if (m_scancode_set == 0xFF)
|
||||||
|
{
|
||||||
append_command_queue(Command::CONFIG_SCANCODE_SET, wanted_scancode_set, 0);
|
append_command_queue(Command::CONFIG_SCANCODE_SET, wanted_scancode_set, 0);
|
||||||
append_command_queue(Command::CONFIG_SCANCODE_SET, 0, 1);
|
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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue