summaryrefslogtreecommitdiff
path: root/Kernel/Devices
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2023-04-08 17:17:19 +0300
committerJelle Raaijmakers <jelle@gmta.nl>2023-04-09 18:11:37 +0200
commitbfffe88de5ea18ed946ab403a777702d4d35a5c4 (patch)
treed67c8be0a8160aac7a3d5826d69b855cedf4dfa3 /Kernel/Devices
parent3a261f5ee8186b47a50188e7a2da807513916271 (diff)
downloadserenity-bfffe88de5ea18ed946ab403a777702d4d35a5c4.zip
Kernel/HID: Untie the PS2 protocol, i8042 hardware and generic devices
For a very long time, the kernel had only support for basic PS/2 devices such as the PS2 AT keyboard and regular PS2 mouse (with a scroll wheel). To adapt to this, we had very simple abstractions in place, essentially, the PS2 devices were registered as IRQ handlers (IRQ 1 and 12), and when an interrupt was triggered, we simply had to tell the I8042Controller to fetch a byte for us, then send it back to the appropriate device for further processing and queueing of either a key event, or a mouse packet so userspace can do something meaningful about it. When we added the VMWare mouse integration feature it was easily adapted to this paradigm, requiring small changes across the handling code for these devices. This patch is a major cleanup for any future advancements in the HID subsystem. It ensures we do things in a much more sane manner: - We stop using LockRefPtrs. Currently, after the initialization of the i8042 controller, we never have to change RefPtrs in that class, as we simply don't support PS2 hotplugging currently. Also, we remove the unnecessary getters for keyboard and mouse devices which also returned a LockRefPtr. - There's a clear separation between PS2 devices and the actual device nodes that normally exist in /dev. PS2 devices are not polled, because when the user uses these devices, they will trigger an IRQ which when is handled, could produce either a MousePacket or KeyEvent, depending on the device state. The separation is crucial for buses that are polled, for example - USB is a polled bus and will not generate an IRQ for HID devices. - There's a clear separation in roles of each structure. The PS2 devices which are attached to a I8042Controller object are managing the device state, while the generic MouseDevice and KeyboardDevice manage all related tasks of a CharacterDevice, as well as interpreting scan code events and mouse relative/absolute coordinates.
Diffstat (limited to 'Kernel/Devices')
-rw-r--r--Kernel/Devices/HID/Device.h8
-rw-r--r--Kernel/Devices/HID/KeyboardDevice.cpp100
-rw-r--r--Kernel/Devices/HID/KeyboardDevice.h11
-rw-r--r--Kernel/Devices/HID/MouseDevice.cpp18
-rw-r--r--Kernel/Devices/HID/MouseDevice.h8
-rw-r--r--Kernel/Devices/HID/ScanCodeEvent.h19
6 files changed, 123 insertions, 41 deletions
diff --git a/Kernel/Devices/HID/Device.h b/Kernel/Devices/HID/Device.h
index a9e12f15f8..891f215bcd 100644
--- a/Kernel/Devices/HID/Device.h
+++ b/Kernel/Devices/HID/Device.h
@@ -12,14 +12,6 @@
namespace Kernel {
class HIDDevice : public CharacterDevice {
-public:
- enum class Type {
- Unknown = 0,
- Keyboard,
- Mouse,
- };
-
- virtual Type instrument_type() const = 0;
protected:
HIDDevice(MajorNumber major, MinorNumber minor)
diff --git a/Kernel/Devices/HID/KeyboardDevice.cpp b/Kernel/Devices/HID/KeyboardDevice.cpp
index e71dc7143a..7daf6335b3 100644
--- a/Kernel/Devices/HID/KeyboardDevice.cpp
+++ b/Kernel/Devices/HID/KeyboardDevice.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021, Edwin Hoksberg <mail@edwinhoksberg.nl>
*
* SPDX-License-Identifier: BSD-2-Clause
@@ -9,9 +9,14 @@
#include <AK/Assertions.h>
#include <AK/Types.h>
#include <Kernel/API/Ioctl.h>
+#include <Kernel/API/KeyCode.h>
+#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/HID/KeyboardDevice.h>
+#include <Kernel/Scheduler.h>
#include <Kernel/Sections.h>
+#include <Kernel/TTY/ConsoleManagement.h>
#include <Kernel/TTY/VirtualConsole.h>
+#include <Kernel/WorkQueue.h>
namespace Kernel {
@@ -209,16 +214,58 @@ static constexpr KeyCode shifted_key_map[0x100] = {
Key_Menu,
};
-void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed)
+void KeyboardDevice::handle_scan_code_input_event(ScanCodeEvent event)
{
- KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[scan_code] : unshifted_key_map[scan_code];
+ m_entropy_source.add_random_event(event.scan_code_value);
+ switch (event.scan_code_value) {
+ case 0x38:
+ if (event.e0_prefix)
+ update_modifier(Mod_AltGr, event.pressed);
+ else
+ update_modifier(Mod_Alt, event.pressed);
+ break;
+ case 0x1d:
+ update_modifier(Mod_Ctrl, event.pressed);
+ break;
+ case 0x5b:
+ m_left_super_pressed = event.pressed;
+ update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed);
+ break;
+ case 0x5c:
+ m_right_super_pressed = event.pressed;
+ update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed);
+ break;
+ case 0x2a:
+ m_left_shift_pressed = event.pressed;
+ update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
+ break;
+ case 0x36:
+ m_right_shift_pressed = event.pressed;
+ update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
+ break;
+ }
+
+ KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[event.scan_code_value] : unshifted_key_map[event.scan_code_value];
+
+ if ((m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && key == Key_F12) {
+ // Alt+Shift+F12 pressed, dump some kernel state to the debug console.
+ ConsoleManagement::the().switch_to_debug();
+ Scheduler::dump_scheduler_state(m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift));
+ }
- if (key == Key_NumLock && pressed)
+ if ((m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key <= Key_1 + ConsoleManagement::s_max_virtual_consoles + 1) {
+ // FIXME: Do something sanely here if we can't allocate a work queue?
+ MUST(g_io_work->try_queue([key]() {
+ ConsoleManagement::the().switch_to(key - Key_1);
+ }));
+ }
+
+ if (key == Key_NumLock && event.pressed)
m_num_lock_on = !m_num_lock_on;
- if (m_num_lock_on && !m_has_e0_prefix) {
- if (scan_code >= 0x47 && scan_code <= 0x53) {
- u8 index = scan_code - 0x47;
+ if (m_num_lock_on && !event.e0_prefix) {
+ if (event.scan_code_value >= 0x47 && event.scan_code_value <= 0x53) {
+ u8 index = event.scan_code_value - 0x47;
constexpr KeyCode numpad_key_map[13] = { Key_7, Key_8, Key_9, Key_Invalid, Key_4, Key_5, Key_6, Key_Invalid, Key_1, Key_2, Key_3, Key_0, Key_Comma };
KeyCode newKey = numpad_key_map[index];
@@ -228,48 +275,51 @@ void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed)
}
}
- Event event;
- event.key = key;
- event.scancode = m_has_e0_prefix ? 0xe000 + scan_code : scan_code;
- event.flags = m_modifiers;
- event.e0_prefix = m_has_e0_prefix;
- event.caps_lock_on = m_caps_lock_on;
- event.code_point = HIDManagement::the().get_char_from_character_map(event);
+ Event queued_event;
+ queued_event.key = key;
+ queued_event.scancode = event.e0_prefix ? 0xe000 + event.scan_code_value : event.scan_code_value;
+ queued_event.flags = m_modifiers;
+ queued_event.e0_prefix = event.e0_prefix;
+ queued_event.caps_lock_on = m_caps_lock_on;
+ queued_event.code_point = HIDManagement::the().get_char_from_character_map(queued_event);
- // If using a non-QWERTY layout, event.key needs to be updated to be the same as event.code_point
- KeyCode mapped_key = code_point_to_key_code(event.code_point);
+ // If using a non-QWERTY layout, queued_event.key needs to be updated to be the same as event.code_point
+ KeyCode mapped_key = code_point_to_key_code(queued_event.code_point);
if (mapped_key != KeyCode::Key_Invalid) {
- event.key = mapped_key;
+ queued_event.key = mapped_key;
key = mapped_key;
}
- if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && pressed)
+ if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && event.pressed)
m_caps_lock_on = !m_caps_lock_on;
if (g_caps_lock_remapped_to_ctrl && key == Key_CapsLock) {
- m_caps_lock_to_ctrl_pressed = pressed;
+ m_caps_lock_to_ctrl_pressed = event.pressed;
update_modifier(Mod_Ctrl, m_caps_lock_to_ctrl_pressed);
}
- if (pressed)
- event.flags |= Is_Press;
+ if (event.pressed)
+ queued_event.flags |= Is_Press;
{
SpinlockLocker locker(HIDManagement::the().m_client_lock);
if (HIDManagement::the().m_client)
- HIDManagement::the().m_client->on_key_pressed(event);
+ HIDManagement::the().m_client->on_key_pressed(queued_event);
}
{
SpinlockLocker lock(m_queue_lock);
- m_queue.enqueue(event);
+ m_queue.enqueue(queued_event);
}
- m_has_e0_prefix = false;
-
evaluate_block_conditions();
}
+ErrorOr<NonnullRefPtr<KeyboardDevice>> KeyboardDevice::try_to_initialize()
+{
+ return *TRY(DeviceManagement::try_create_device<KeyboardDevice>());
+}
+
// FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices
// like USB keyboards, we need to remove this
UNMAP_AFTER_INIT KeyboardDevice::KeyboardDevice()
diff --git a/Kernel/Devices/HID/KeyboardDevice.h b/Kernel/Devices/HID/KeyboardDevice.h
index e37f9bedb1..fe52305444 100644
--- a/Kernel/Devices/HID/KeyboardDevice.h
+++ b/Kernel/Devices/HID/KeyboardDevice.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021, Edwin Hoksberg <mail@edwinhoksberg.nl>
*
* SPDX-License-Identifier: BSD-2-Clause
@@ -12,15 +12,20 @@
#include <Kernel/API/KeyCode.h>
#include <Kernel/Devices/CharacterDevice.h>
#include <Kernel/Devices/HID/Device.h>
+#include <Kernel/Devices/HID/ScanCodeEvent.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Random.h>
namespace Kernel {
class KeyboardDevice : public HIDDevice {
+ friend class DeviceManagement;
+
public:
using Event = KeyEvent;
+ static ErrorOr<NonnullRefPtr<KeyboardDevice>> try_to_initialize();
+
virtual ~KeyboardDevice() override;
// ^CharacterDevice
@@ -29,8 +34,7 @@ public:
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override { return EINVAL; }
virtual bool can_write(OpenFileDescription const&, u64) const override { return true; }
- // ^HIDDevice
- virtual Type instrument_type() const override { return Type::Keyboard; }
+ void handle_scan_code_input_event(ScanCodeEvent);
// ^File
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override;
@@ -54,7 +58,6 @@ protected:
bool m_caps_lock_to_ctrl_pressed { false };
bool m_caps_lock_on { false };
bool m_num_lock_on { false };
- bool m_has_e0_prefix { false };
bool m_left_shift_pressed { false };
bool m_right_shift_pressed { false };
bool m_left_super_pressed { false };
diff --git a/Kernel/Devices/HID/MouseDevice.cpp b/Kernel/Devices/HID/MouseDevice.cpp
index caa2b9c377..fc15b35f44 100644
--- a/Kernel/Devices/HID/MouseDevice.cpp
+++ b/Kernel/Devices/HID/MouseDevice.cpp
@@ -1,19 +1,35 @@
/*
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/HID/Management.h>
#include <Kernel/Devices/HID/MouseDevice.h>
namespace Kernel {
+ErrorOr<NonnullRefPtr<MouseDevice>> MouseDevice::try_to_initialize()
+{
+ return *TRY(DeviceManagement::try_create_device<MouseDevice>());
+}
+
MouseDevice::MouseDevice()
: HIDDevice(10, HIDManagement::the().generate_minor_device_number_for_mouse())
{
}
+void MouseDevice::handle_mouse_packet_input_event(MousePacket packet)
+{
+ m_entropy_source.add_random_event(packet);
+ {
+ SpinlockLocker lock(m_queue_lock);
+ m_queue.enqueue(packet);
+ }
+ evaluate_block_conditions();
+}
+
MouseDevice::~MouseDevice() = default;
bool MouseDevice::can_read(OpenFileDescription const&, u64) const
diff --git a/Kernel/Devices/HID/MouseDevice.h b/Kernel/Devices/HID/MouseDevice.h
index 65a7718fda..a571692f5d 100644
--- a/Kernel/Devices/HID/MouseDevice.h
+++ b/Kernel/Devices/HID/MouseDevice.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -18,7 +18,10 @@
namespace Kernel {
class MouseDevice : public HIDDevice {
+ friend class DeviceManagement;
+
public:
+ static ErrorOr<NonnullRefPtr<MouseDevice>> try_to_initialize();
virtual ~MouseDevice() override;
// ^CharacterDevice
@@ -27,8 +30,7 @@ public:
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override { return EINVAL; }
virtual bool can_write(OpenFileDescription const&, u64) const override { return true; }
- // ^HIDDevice
- virtual Type instrument_type() const override { return Type::Mouse; }
+ void handle_mouse_packet_input_event(MousePacket);
protected:
MouseDevice();
diff --git a/Kernel/Devices/HID/ScanCodeEvent.h b/Kernel/Devices/HID/ScanCodeEvent.h
new file mode 100644
index 0000000000..d89e8fc5fb
--- /dev/null
+++ b/Kernel/Devices/HID/ScanCodeEvent.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+
+namespace Kernel {
+
+struct ScanCodeEvent {
+ u32 scan_code_value { 0 };
+ bool pressed { false };
+ bool e0_prefix { false };
+};
+
+}