diff options
author | Liav A <liavalb@gmail.com> | 2022-02-10 10:19:28 +0200 |
---|---|---|
committer | Idan Horowitz <idan.horowitz@gmail.com> | 2022-02-10 15:42:56 +0200 |
commit | dc41a0b8300408da2595c3c5f2595dd7cf2b7c98 (patch) | |
tree | b039a5f0d090e40f506653d65d9e35c1eb1530f5 /Kernel | |
parent | f1f0770d686a9fecfa51be3699469c287e1fd9c2 (diff) | |
download | serenity-dc41a0b8300408da2595c3c5f2595dd7cf2b7c98.zip |
Kernel: Check i8042 existence before trying to use it
If we don't do so, we just hang forever because we assume there's i8042
controller in the system, which is not a valid assumption for modern PC
hardware.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Devices/HID/I8042Controller.cpp | 34 | ||||
-rw-r--r-- | Kernel/Devices/HID/I8042Controller.h | 5 |
2 files changed, 39 insertions, 0 deletions
diff --git a/Kernel/Devices/HID/I8042Controller.cpp b/Kernel/Devices/HID/I8042Controller.cpp index 1e28a7e4a0..9bec82f5f1 100644 --- a/Kernel/Devices/HID/I8042Controller.cpp +++ b/Kernel/Devices/HID/I8042Controller.cpp @@ -31,8 +31,30 @@ UNMAP_AFTER_INIT I8042Controller::I8042Controller() { } +UNMAP_AFTER_INIT bool I8042Controller::check_existence() +{ + { + SpinlockLocker lock(m_lock); + // Note: Perform controller self-test before touching the controller + // Try to probe the controller for 5 times and give up if nothing + // responded. + for (int attempt = 0; attempt < 5; attempt++) { + do_write(I8042Port::Command, I8042Command::TestPS2Controller); + if (do_read(I8042Port::Buffer) == I8042Response::ControllerTestPassed) + return true; + // Note: Wait 50 microseconds in case the controller couldn't respond + IO::delay(50); + } + dbgln("I8042: Trying to probe for existence of controller failed"); + return false; + } +} + UNMAP_AFTER_INIT void I8042Controller::detect_devices() { + if (!check_existence()) + return; + u8 configuration; { SpinlockLocker lock(m_lock); @@ -255,6 +277,18 @@ void I8042Controller::prepare_for_output() } } +UNMAP_AFTER_INIT void I8042Controller::do_write(u8 port, u8 data) +{ + VERIFY(m_lock.is_locked()); + IO::out8(port, data); +} + +UNMAP_AFTER_INIT u8 I8042Controller::do_read(u8 port) +{ + VERIFY(m_lock.is_locked()); + return IO::in8(port); +} + void I8042Controller::do_wait_then_write(u8 port, u8 data) { VERIFY(m_lock.is_locked()); diff --git a/Kernel/Devices/HID/I8042Controller.h b/Kernel/Devices/HID/I8042Controller.h index 86765a71d7..da3d4c3851 100644 --- a/Kernel/Devices/HID/I8042Controller.h +++ b/Kernel/Devices/HID/I8042Controller.h @@ -144,6 +144,11 @@ private: u8 do_wait_then_read(u8 port); void drain_output_buffer(); + // Note: These functions exist only for the initialization process of the controller + void do_write(u8 port, u8 data); + u8 do_read(u8 port); + bool check_existence(); + Spinlock m_lock; bool m_first_port_available { false }; bool m_second_port_available { false }; |