summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2022-02-10 10:19:28 +0200
committerIdan Horowitz <idan.horowitz@gmail.com>2022-02-10 15:42:56 +0200
commitdc41a0b8300408da2595c3c5f2595dd7cf2b7c98 (patch)
treeb039a5f0d090e40f506653d65d9e35c1eb1530f5 /Kernel
parentf1f0770d686a9fecfa51be3699469c287e1fd9c2 (diff)
downloadserenity-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.cpp34
-rw-r--r--Kernel/Devices/HID/I8042Controller.h5
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 };