Kernel: Increase PS2 timeout to 300 ms, load PS2 in separate thread
PS/2 seems to hit command timeout sometimes on slow emulation so increase the timeouts. Also move PS/2 device initialization to a different thread because device indentification waits for timeouts.
This commit is contained in:
parent
92e4078287
commit
892e16dfb1
|
@ -27,7 +27,9 @@ namespace Kernel::Input
|
||||||
private:
|
private:
|
||||||
PS2Controller() = default;
|
PS2Controller() = default;
|
||||||
BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set);
|
BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set);
|
||||||
BAN::ErrorOr<void> initialize_device(uint8_t, uint8_t scancode_set);
|
BAN::ErrorOr<void> identify_device(uint8_t, uint8_t scancode_set);
|
||||||
|
|
||||||
|
void device_initialize_task(void*);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace Kernel::Input
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PS2Device(PS2Controller&, InputDevice::Type type);
|
PS2Device(PS2Controller&, InputDevice::Type type);
|
||||||
|
virtual ~PS2Device();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PS2Controller& m_controller;
|
PS2Controller& m_controller;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
namespace Kernel::Input
|
namespace Kernel::Input
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr uint64_t s_ps2_timeout_ms = 100;
|
static constexpr uint64_t s_ps2_timeout_ms = 300;
|
||||||
|
|
||||||
static PS2Controller* s_instance = nullptr;
|
static PS2Controller* s_instance = nullptr;
|
||||||
|
|
||||||
|
@ -238,6 +238,15 @@ namespace Kernel::Input
|
||||||
return *s_instance;
|
return *s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PS2DeviceInitInfo
|
||||||
|
{
|
||||||
|
PS2Controller* controller;
|
||||||
|
bool valid_ports[2];
|
||||||
|
uint8_t scancode_set;
|
||||||
|
uint8_t config;
|
||||||
|
BAN::Atomic<bool> thread_started;
|
||||||
|
};
|
||||||
|
|
||||||
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
|
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
|
||||||
{
|
{
|
||||||
constexpr size_t iapc_flag_off = offsetof(ACPI::FADT, iapc_boot_arch);
|
constexpr size_t iapc_flag_off = offsetof(ACPI::FADT, iapc_boot_arch);
|
||||||
|
@ -315,6 +324,54 @@ namespace Kernel::Input
|
||||||
if (!valid_ports[0] && !valid_ports[1])
|
if (!valid_ports[0] && !valid_ports[1])
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
// Reserve IRQs
|
||||||
|
if (valid_ports[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error())
|
||||||
|
{
|
||||||
|
dwarnln("Could not reserve irq for PS/2 port 1");
|
||||||
|
valid_ports[0] = false;
|
||||||
|
}
|
||||||
|
if (valid_ports[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error())
|
||||||
|
{
|
||||||
|
dwarnln("Could not reserve irq for PS/2 port 2");
|
||||||
|
valid_ports[1] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PS2DeviceInitInfo info {
|
||||||
|
.controller = this,
|
||||||
|
.valid_ports = { valid_ports[0], valid_ports[1] },
|
||||||
|
.scancode_set = scancode_set,
|
||||||
|
.config = config,
|
||||||
|
.thread_started { false },
|
||||||
|
};
|
||||||
|
|
||||||
|
auto* init_thread = TRY(Thread::create_kernel(
|
||||||
|
[](void* info) {
|
||||||
|
static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info);
|
||||||
|
}, &info, nullptr
|
||||||
|
));
|
||||||
|
TRY(Processor::scheduler().add_thread(init_thread));
|
||||||
|
|
||||||
|
while (!info.thread_started)
|
||||||
|
Processor::pause();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Controller::device_initialize_task(void* _info)
|
||||||
|
{
|
||||||
|
bool valid_ports[2];
|
||||||
|
uint8_t scancode_set;
|
||||||
|
uint8_t config;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& info = *static_cast<PS2DeviceInitInfo*>(_info);
|
||||||
|
valid_ports[0] = info.valid_ports[0];
|
||||||
|
valid_ports[1] = info.valid_ports[1];
|
||||||
|
scancode_set = info.scancode_set;
|
||||||
|
config = info.config;
|
||||||
|
info.thread_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize devices
|
// Initialize devices
|
||||||
for (uint8_t device = 0; device < 2; device++)
|
for (uint8_t device = 0; device < 2; device++)
|
||||||
{
|
{
|
||||||
|
@ -325,7 +382,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, scancode_set); res.is_error())
|
if (auto res = identify_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);
|
||||||
|
@ -333,20 +390,8 @@ namespace Kernel::Input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve IRQs
|
|
||||||
if (m_devices[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error())
|
|
||||||
{
|
|
||||||
dwarnln("Could not reserve irq for PS/2 port 1");
|
|
||||||
m_devices[0].clear();
|
|
||||||
}
|
|
||||||
if (m_devices[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error())
|
|
||||||
{
|
|
||||||
dwarnln("Could not reserve irq for PS/2 port 2");
|
|
||||||
m_devices[1].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_devices[0] && !m_devices[1])
|
if (!m_devices[0] && !m_devices[1])
|
||||||
return {};
|
return;
|
||||||
|
|
||||||
// Enable irqs on valid devices
|
// Enable irqs on valid devices
|
||||||
if (m_devices[0])
|
if (m_devices[0])
|
||||||
|
@ -362,21 +407,21 @@ namespace Kernel::Input
|
||||||
config |= PS2::Config::INTERRUPT_SECOND_PORT;
|
config |= PS2::Config::INTERRUPT_SECOND_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(send_command(PS2::Command::WRITE_CONFIG, config));
|
if (auto ret = send_command(PS2::Command::WRITE_CONFIG, config); ret.is_error())
|
||||||
|
{
|
||||||
|
dwarnln("PS2 failed to enable interrupts: {}", ret.error());
|
||||||
|
m_devices[0].clear();
|
||||||
|
m_devices[1].clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Send device initialization sequence after interrupts are enabled
|
// Send device initialization sequence after interrupts are enabled
|
||||||
for (uint8_t i = 0; i < 2; i++)
|
for (uint8_t i = 0; i < 2; i++)
|
||||||
{
|
if (m_devices[i])
|
||||||
if (!m_devices[i])
|
|
||||||
continue;
|
|
||||||
m_devices[i]->send_initialize();
|
m_devices[i]->send_initialize();
|
||||||
DevFileSystem::get().add_device(m_devices[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
BAN::ErrorOr<void> PS2Controller::identify_device(uint8_t device, uint8_t scancode_set)
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
||||||
|
|
|
@ -9,7 +9,14 @@ namespace Kernel::Input
|
||||||
PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type)
|
PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type)
|
||||||
: InputDevice(type)
|
: InputDevice(type)
|
||||||
, m_controller(controller)
|
, m_controller(controller)
|
||||||
{ }
|
{
|
||||||
|
DevFileSystem::get().add_device(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
PS2Device::~PS2Device()
|
||||||
|
{
|
||||||
|
DevFileSystem::get().remove_device(this);
|
||||||
|
}
|
||||||
|
|
||||||
bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size)
|
bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue