diff --git a/kernel/include/kernel/Input/PS2/Controller.h b/kernel/include/kernel/Input/PS2/Controller.h index 59a75420..ead794fe 100644 --- a/kernel/include/kernel/Input/PS2/Controller.h +++ b/kernel/include/kernel/Input/PS2/Controller.h @@ -27,7 +27,9 @@ namespace Kernel::Input private: PS2Controller() = default; BAN::ErrorOr initialize_impl(uint8_t scancode_set); - BAN::ErrorOr initialize_device(uint8_t, uint8_t scancode_set); + BAN::ErrorOr identify_device(uint8_t, uint8_t scancode_set); + + void device_initialize_task(void*); BAN::ErrorOr read_byte(); BAN::ErrorOr send_byte(uint16_t port, uint8_t byte); diff --git a/kernel/include/kernel/Input/PS2/Device.h b/kernel/include/kernel/Input/PS2/Device.h index a5869d58..ba80c71f 100644 --- a/kernel/include/kernel/Input/PS2/Device.h +++ b/kernel/include/kernel/Input/PS2/Device.h @@ -22,6 +22,7 @@ namespace Kernel::Input protected: PS2Device(PS2Controller&, InputDevice::Type type); + virtual ~PS2Device(); protected: PS2Controller& m_controller; diff --git a/kernel/kernel/Input/PS2/Controller.cpp b/kernel/kernel/Input/PS2/Controller.cpp index 107c1bd5..01f553f8 100644 --- a/kernel/kernel/Input/PS2/Controller.cpp +++ b/kernel/kernel/Input/PS2/Controller.cpp @@ -12,7 +12,7 @@ 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; @@ -238,6 +238,15 @@ namespace Kernel::Input return *s_instance; } + struct PS2DeviceInitInfo + { + PS2Controller* controller; + bool valid_ports[2]; + uint8_t scancode_set; + uint8_t config; + BAN::Atomic thread_started; + }; + BAN::ErrorOr PS2Controller::initialize_impl(uint8_t scancode_set) { 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]) 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(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(_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 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()); 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()); (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]) - return {}; + return; // Enable irqs on valid devices if (m_devices[0]) @@ -362,21 +407,21 @@ namespace Kernel::Input 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 for (uint8_t i = 0; i < 2; i++) - { - if (!m_devices[i]) - continue; - m_devices[i]->send_initialize(); - DevFileSystem::get().add_device(m_devices[i]); - } - - return {}; + if (m_devices[i]) + m_devices[i]->send_initialize(); } - BAN::ErrorOr PS2Controller::initialize_device(uint8_t device, uint8_t scancode_set) + BAN::ErrorOr PS2Controller::identify_device(uint8_t device, uint8_t scancode_set) { // Reset device TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET)); diff --git a/kernel/kernel/Input/PS2/Device.cpp b/kernel/kernel/Input/PS2/Device.cpp index 011d98a2..2b2ed4be 100644 --- a/kernel/kernel/Input/PS2/Device.cpp +++ b/kernel/kernel/Input/PS2/Device.cpp @@ -9,7 +9,14 @@ namespace Kernel::Input PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type) : InputDevice(type) , 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) {